parse.y revision 1.228
1132727Skan/*	$OpenBSD: parse.y,v 1.228 2002/11/29 17:14:18 henning Exp $	*/
2132727Skan
318334Speter/*
4132727Skan * Copyright (c) 2001 Markus Friedl.  All rights reserved.
5132727Skan * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
6132727Skan *
790081Sobrien * Redistribution and use in source and binary forms, with or without
818334Speter * modification, are permitted provided that the following conditions
990081Sobrien * are met:
1018334Speter * 1. Redistributions of source code must retain the above copyright
1118334Speter *    notice, this list of conditions and the following disclaimer.
1218334Speter * 2. Redistributions in binary form must reproduce the above copyright
1318334Speter *    notice, this list of conditions and the following disclaimer in the
1490081Sobrien *    documentation and/or other materials provided with the distribution.
1518334Speter *
1618334Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1718334Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1818334Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1918334Speter * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2090081Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2118334Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2218334Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2318334Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2418334Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2518334Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2618334Speter */
2718334Speter%{
2818334Speter#include <sys/types.h>
2990081Sobrien#include <sys/socket.h>
30132727Skan#include <sys/ioctl.h>
31132727Skan#include <net/if.h>
32132727Skan#include <netinet/in.h>
3390081Sobrien#include <netinet/in_systm.h>
34132727Skan#include <netinet/ip.h>
35132727Skan#include <netinet/ip_icmp.h>
36132727Skan#include <netinet/icmp6.h>
37132727Skan#include <net/pfvar.h>
38132727Skan#include <arpa/inet.h>
39132727Skan
40132727Skan#include <stdio.h>
41132727Skan#include <stdlib.h>
42132727Skan#include <ifaddrs.h>
43132727Skan#include <netdb.h>
44132727Skan#include <stdarg.h>
4518334Speter#include <errno.h>
46132727Skan#include <string.h>
4718334Speter#include <ctype.h>
48132727Skan#include <err.h>
49132727Skan#include <pwd.h>
50132727Skan#include <grp.h>
51132727Skan#include <md5.h>
52132727Skan
53132727Skan#include "pfctl_parser.h"
54132727Skan#include "pfctl_altq.h"
55132727Skan
56132727Skanstatic struct pfctl *pf = NULL;
57132727Skanstatic FILE *fin = NULL;
58132727Skanstatic int debug = 0;
59132727Skanstatic int lineno = 1;
60132727Skanstatic int errors = 0;
61132727Skanstatic int rulestate = 0;
62132727Skanstatic u_int16_t returnicmpdefault =  (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
63132727Skanstatic u_int16_t returnicmp6default = (ICMP6_DST_UNREACH << 8) |
64132727Skan    ICMP6_DST_UNREACH_NOPORT;
65132727Skanstatic int blockpolicy = PFRULE_DROP;
66132727Skanstatic int require_order = 1;
67132727Skan
68132727Skanenum {
69132727Skan	PFCTL_STATE_NONE = 0,
70132727Skan	PFCTL_STATE_OPTION = 1,
71132727Skan	PFCTL_STATE_SCRUB = 2,
7250448Sobrien	PFCTL_STATE_QUEUE = 3,
7350448Sobrien	PFCTL_STATE_NAT = 4,
74132727Skan	PFCTL_STATE_FILTER = 5
75132727Skan};
76132727Skan
77132727Skanenum pfctl_iflookup_mode {
78132727Skan	PFCTL_IFLOOKUP_HOST = 0,
79132727Skan	PFCTL_IFLOOKUP_NET = 1,
80132727Skan	PFCTL_IFLOOKUP_BCAST = 2
81132727Skan};
82132727Skan
83132727Skanstruct node_if {
84132727Skan	char			 ifname[IFNAMSIZ];
85132727Skan	u_int8_t		 not;
86132727Skan	u_int			 ifa_flags;
87132727Skan	struct node_if		*next;
88132727Skan	struct node_if		*tail;
89132727Skan};
90132727Skan
9150448Sobrienstruct node_proto {
9250448Sobrien	u_int8_t		 proto;
93132727Skan	struct node_proto	*next;
94132727Skan	struct node_proto	*tail;
95132727Skan};
96132727Skan
9790081Sobrienstruct node_host {
98132727Skan	struct pf_addr_wrap	 addr;
99132727Skan	struct pf_addr		 bcast;
100132727Skan	sa_family_t		 af;
101132727Skan	u_int8_t		 not;
102132727Skan	u_int8_t		 noroute;
103132727Skan	u_int32_t		 ifindex;	/* link-local IPv6 addrs */
104132727Skan	char			*ifname;
105132727Skan	u_int			 ifa_flags;
106132727Skan	struct node_host	*next;
107132727Skan	struct node_host	*tail;
108132727Skan};
109132727Skan
110132727Skanstruct node_port {
111132727Skan	u_int16_t		 port[2];
112132727Skan	u_int8_t		 op;
113132727Skan	struct node_port	*next;
114132727Skan	struct node_port	*tail;
115132727Skan};
11618334Speter
11718334Speterstruct node_uid {
11818334Speter	uid_t			 uid[2];
11918334Speter	u_int8_t		 op;
12050448Sobrien	struct node_uid		*next;
12118334Speter	struct node_uid		*tail;
12218334Speter};
12352298Sobrien
124132727Skanstruct node_gid {
12518334Speter	gid_t			 gid[2];
12650448Sobrien	u_int8_t		 op;
12750448Sobrien	struct node_gid		*next;
12850448Sobrien	struct node_gid		*tail;
12990081Sobrien};
13090081Sobrien
13190081Sobrienstruct node_icmp {
13290081Sobrien	u_int8_t		 code;
13390081Sobrien	u_int8_t		 type;
13490081Sobrien	u_int8_t		 proto;
13590081Sobrien	struct node_icmp	*next;
13690081Sobrien	struct node_icmp	*tail;
13718334Speter};
13850448Sobrien
13918334Speterenum	{ PF_STATE_OPT_MAX=0, PF_STATE_OPT_TIMEOUT=1 };
14050448Sobrienstruct node_state_opt {
14118334Speter	int			 type;
14290081Sobrien	union {
14390081Sobrien		u_int32_t	 max_states;
14490081Sobrien		struct {
145117404Skan			int		number;
146117404Skan			u_int32_t	seconds;
147132727Skan		}		 timeout;
148117404Skan	}			 data;
149132727Skan	struct node_state_opt	*next;
150117404Skan	struct node_state_opt	*tail;
15190081Sobrien};
15290081Sobrien
15390081Sobrienstruct peer {
15490081Sobrien	struct node_host	*host;
15590081Sobrien	struct node_port	*port;
15690081Sobrien};
15790081Sobrien
15890081Sobrienstruct node_queue {
15990081Sobrien	char			 queue[PF_QNAME_SIZE];
16090081Sobrien	char			 parent[PF_QNAME_SIZE];
16190081Sobrien	char			 ifname[IFNAMSIZ];
16290081Sobrien	struct node_queue	*next;
16390081Sobrien	struct node_queue	*tail;
164132727Skan}	*queues = NULL;
165132727Skan
16690081Sobrienstruct node_queue_opt {
167117404Skan	int			 qtype;
168117404Skan	union {	/* options for other schedulers will follow */
169117404Skan		struct cbq_opts		 cbq_opts;
170117404Skan	}			 data;
171132727Skan};
172132727Skan
173132727Skanstruct node_queue_bw {
174117404Skan	u_int32_t	bw_absolute;
175117404Skan	u_int16_t	bw_percent;
176117404Skan};
177117404Skan
17890081Sobrienint	yyerror(char *, ...);
17990081Sobrienint	rule_consistent(struct pf_rule *);
180132727Skanint	nat_consistent(struct pf_nat *);
18190081Sobrienint	rdr_consistent(struct pf_rdr *);
182132727Skanint	yyparse(void);
183132727Skanvoid	set_ipmask(struct node_host *, u_int8_t);
184132727Skanvoid	expand_rdr(struct pf_rdr *, struct node_if *, struct node_proto *,
185132727Skan	    struct node_host *, struct node_host *, struct node_host *);
186132727Skanvoid	expand_nat(struct pf_nat *, struct node_if *, struct node_proto *,
187132727Skan	    struct node_host *, struct node_port *,
188132727Skan	    struct node_host *, struct node_port *, struct node_host *);
189132727Skanvoid	expand_label_if(const char *, char *, const char *);
190132727Skanvoid	expand_label_addr(const char *, char *, u_int8_t, struct node_host *);
191132727Skanvoid	expand_label_port(const char *, char *, struct node_port *);
192132727Skanvoid	expand_label_proto(const char *, char *, u_int8_t);
193132727Skanvoid	expand_label_nr(const char *, char *);
19490081Sobrienvoid	expand_label(char *, const char *, u_int8_t, struct node_host *,
19590081Sobrien	    struct node_port *, struct node_host *, struct node_port *,
19690081Sobrien	    u_int8_t);
19790081Sobrienvoid	expand_rule(struct pf_rule *, struct node_if *, struct node_host *,
19890081Sobrien	    struct node_proto *, struct node_host *, struct node_port *,
199132727Skan	    struct node_host *, struct node_port *, struct node_uid *,
200132727Skan	    struct node_gid *, struct node_icmp *);
20118334Speterint	expand_altq(struct pf_altq *, struct node_if *, struct node_queue *);
20218334Speterint	expand_queue(struct pf_altq *, struct node_queue *,
20318334Speter	    struct node_queue_bw);
20418334Speterint	check_rulestate(int);
20518334Speterint	kw_cmp(const void *, const void *);
20618334Speterint	lookup(char *);
20718334Speterint	lgetc(FILE *);
20852298Sobrienint	lungetc(int, FILE *);
20950448Sobrienint	findeol(void);
21090081Sobrienint	yylex(void);
21118334Speterstruct	node_host *host(char *, int);
21290081Sobrienint	atoul(char *, u_long *);
21390081Sobrienint	getservice(char *);
21418334Speter
21518334Speterstruct sym {
21690081Sobrien	struct sym *next;
217132727Skan	int used;
218132727Skan	char *nam;
219132727Skan	char *val;
220132727Skan};
221132727Skanstruct sym *symhead = NULL;
222117404Skan
223117404Skanint	symset(const char *, const char *);
224117404Skanchar *	symget(const char *);
225117404Skan
226117404Skanvoid	ifa_load(void);
227117404Skanstruct	node_host *ifa_exists(char *);
228117404Skanstruct	node_host *ifa_lookup(char *, enum pfctl_iflookup_mode);
229117404Skanvoid	decide_address_family(struct node_host *, sa_family_t *);
23018334Spetervoid	remove_invalid_hosts(struct node_host **, sa_family_t *);
23150448Sobrienu_int16_t	parseicmpspec(char *, sa_family_t);
23250448Sobrien
23350448Sobrientypedef struct {
23450448Sobrien	union {
23550448Sobrien		u_int32_t		number;
23618334Speter		int			i;
23750448Sobrien		char			*string;
23850448Sobrien		struct {
23990081Sobrien			u_int8_t	b1;
24090081Sobrien			u_int8_t	b2;
241132727Skan			u_int16_t	w;
24218334Speter			u_int16_t	w2;
24390081Sobrien		}			b;
24490081Sobrien		struct range {
245132727Skan			int		a;
246132727Skan			int		b;
247132727Skan			int		t;
248132727Skan		}			range;
249132727Skan		struct node_if		*interface;
250132727Skan		struct node_proto	*proto;
25150448Sobrien		struct node_icmp	*icmp;
252132727Skan		struct node_host	*host;
253132727Skan		struct node_port	*port;
254132727Skan		struct node_uid		*uid;
255132727Skan		struct node_gid		*gid;
256132727Skan		struct node_state_opt	*state_opt;
257132727Skan		struct peer		peer;
25890081Sobrien		struct {
25990081Sobrien			struct peer	src, dst;
26090081Sobrien		}			fromto;
26118334Speter		struct pf_poolhashkey	*hashkey;
26290081Sobrien		struct {
26390081Sobrien			struct node_host	*host;
26490081Sobrien			u_int8_t	rt;
26590081Sobrien			u_int8_t	pool_opts;
26690081Sobrien			sa_family_t	af;
26718334Speter			struct pf_poolhashkey	*key;
26890081Sobrien		}			route;
26990081Sobrien		struct redirection {
27018334Speter			struct node_host	*host;
27118334Speter			struct range		 rport;
27290081Sobrien		}			*redirection;
27350448Sobrien		struct {
27418334Speter			int		type;
27518334Speter			struct pf_poolhashkey	*key;
27618334Speter		}			pooltype;
277117404Skan		struct {
278117404Skan			int			 action;
279117404Skan			struct node_state_opt	*options;
280117404Skan		}			keep_state;
281117404Skan		struct {
282117404Skan			u_int8_t	log;
283117404Skan			u_int8_t	quick;
284117404Skan		}			logquick;
28518334Speter		struct node_queue	*queue;
286117404Skan		struct node_queue_opt	queue_options;
28718334Speter		struct node_queue_bw	queue_bwspec;
28818334Speter	} v;
289132727Skan	int lineno;
29018334Speter} YYSTYPE;
29118334Speter
29218334Speter%}
29390081Sobrien
294132727Skan%token	PASS BLOCK SCRUB RETURN IN OUT LOG LOGALL QUICK ON FROM TO FLAGS
29518334Speter%token	RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
296132727Skan%token	ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
297132727Skan%token	MINTTL ERROR ALLOWOPTS FASTROUTE ROUTETO DUPTO REPLYTO NO LABEL
298132727Skan%token	NOROUTE FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP
29918334Speter%token	FRAGNORM FRAGDROP FRAGCROP
30050448Sobrien%token	SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY
30150448Sobrien%token	REQUIREORDER YES
30250448Sobrien%token	ANTISPOOF FOR
30350448Sobrien%token	BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT
304132727Skan%token	ALTQ SCHEDULER CBQ BANDWIDTH TBRSIZE
30550448Sobrien%token	QUEUE PRIORITY QLIMIT
30650448Sobrien%token	DEFAULT CONTROL BORROW RED ECN RIO
307132727Skan%token	<v.string> STRING
30850448Sobrien%token	<v.i>	PORTUNARY PORTBINARY
30950448Sobrien%type	<v.interface>	interface if_list if_item_not if_item
31090081Sobrien%type	<v.number>	number port icmptype icmp6type minttl uid gid maxmss
31190081Sobrien%type	<v.number>	tos
31290081Sobrien%type	<v.i>	no dir log af nodf allowopts fragment fragcache
31350448Sobrien%type	<v.i>	staticport
31450448Sobrien%type	<v.b>	action flag flags blockspec
31550448Sobrien%type	<v.range>	dport rport
31650448Sobrien%type	<v.hashkey>     hashkey
317132727Skan%type	<v.pooltype>	pooltype
318132727Skan%type	<v.proto>	proto proto_list proto_item
31950448Sobrien%type	<v.icmp>	icmpspec icmp_list icmp6_list icmp_item icmp6_item
320132727Skan%type	<v.fromto>	fromto
32150448Sobrien%type	<v.peer>	ipportspec
32250448Sobrien%type	<v.host>	ipspec xhost host address host_list
32390081Sobrien%type	<v.host>	redir_host_list redirspec
32490081Sobrien%type	<v.host>	route_host route_host_list routespec
32590081Sobrien%type	<v.port>	portspec port_list port_item
32690081Sobrien%type	<v.uid>		uids uid_list uid_item
32790081Sobrien%type	<v.gid>		gids gid_list gid_item
32890081Sobrien%type	<v.route>	route
329132727Skan%type	<v.redirection>	redirection redirpool
33090081Sobrien%type	<v.string>	label string
33190081Sobrien%type	<v.keep_state>	keep
332132727Skan%type	<v.state_opt>	state_opt_spec state_opt_list state_opt_item
33390081Sobrien%type	<v.logquick>	logquick
33490081Sobrien%type	<v.interface>	antispoof_ifspc antispoof_iflst
33518334Speter%type	<v.number>	priority qlimit tbrsize
336132727Skan%type	<v.string>	qname
337132727Skan%type	<v.queue>	qassign qassign_list qassign_item
338132727Skan%type	<v.queue_options>	schedtype
339132727Skan%type	<v.number>	cbqflags_list cbqflags_item
34090081Sobrien%type	<v.queue_bwspec>	bandwidth
34190081Sobrien%%
34290081Sobrien
34390081Sobrienruleset		: /* empty */
34490081Sobrien		| ruleset '\n'
345117404Skan		| ruleset option '\n'
34618334Speter		| ruleset scrubrule '\n'
34790081Sobrien		| ruleset natrule '\n'
34890081Sobrien		| ruleset binatrule '\n'
34990081Sobrien		| ruleset rdrrule '\n'
350132727Skan		| ruleset pfrule '\n'
35118334Speter		| ruleset altqif '\n'
35290081Sobrien		| ruleset queuespec '\n'
35390081Sobrien		| ruleset varset '\n'
35490081Sobrien		| ruleset antispoof '\n'
35590081Sobrien		| ruleset error '\n'		{ errors++; }
35690081Sobrien		;
35790081Sobrien
35890081Sobrienoption		: SET OPTIMIZATION STRING		{
35918334Speter			if (pf->opts & PF_OPT_VERBOSE)
36018334Speter				printf("set optimization %s\n", $3);
36118334Speter			if (check_rulestate(PFCTL_STATE_OPTION))
362132727Skan				YYERROR;
363132727Skan			if (pfctl_set_optimization(pf, $3) != 0) {
364132727Skan				yyerror("unknown optimization %s", $3);
365132727Skan				YYERROR;
366132727Skan			}
367132727Skan		}
36850448Sobrien		| SET TIMEOUT timeout_spec
36950448Sobrien		| SET TIMEOUT '{' timeout_list '}'
37050448Sobrien		| SET LIMIT limit_spec
371132727Skan		| SET LIMIT '{' limit_list '}'
372132727Skan		| SET LOGINTERFACE STRING		{
373117404Skan			if (pf->opts & PF_OPT_VERBOSE)
37490081Sobrien				printf("set loginterface %s\n", $3);
375132727Skan			if (check_rulestate(PFCTL_STATE_OPTION))
37690081Sobrien				YYERROR;
377132727Skan			if (pfctl_set_logif(pf, $3) != 0) {
37890081Sobrien				yyerror("error setting loginterface %s", $3);
37990081Sobrien				YYERROR;
380132727Skan			}
38190081Sobrien		}
382132727Skan		| SET BLOCKPOLICY DROP	{
383132727Skan			if (pf->opts & PF_OPT_VERBOSE)
38490081Sobrien				printf("set block-policy drop\n");
385132727Skan			if (check_rulestate(PFCTL_STATE_OPTION))
386132727Skan				YYERROR;
38750448Sobrien			blockpolicy = PFRULE_DROP;
38852298Sobrien		}
38990081Sobrien		| SET BLOCKPOLICY RETURN {
39050448Sobrien			if (pf->opts & PF_OPT_VERBOSE)
39152298Sobrien				printf("set block-policy return\n");
39250448Sobrien			if (check_rulestate(PFCTL_STATE_OPTION))
393132727Skan				YYERROR;
394132727Skan			blockpolicy = PFRULE_RETURN;
39550448Sobrien		}
39650448Sobrien		| SET REQUIREORDER YES {
39750448Sobrien			if (pf->opts & PF_OPT_VERBOSE)
39850448Sobrien				printf("set require-order yes\n");
39990081Sobrien			require_order = 1;
40018334Speter		}
401132727Skan		| SET REQUIREORDER NO {
402132727Skan			if (pf->opts & PF_OPT_VERBOSE)
403132727Skan				printf("set require-order no\n");
404132727Skan			require_order = 0;
40518334Speter		}
40618334Speter		;
40750448Sobrien
40818334Speterstring		: string STRING				{
40918334Speter			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
41018334Speter				yyerror("asprintf failed");
41118334Speter				YYERROR;
41250448Sobrien			}
41318334Speter			free($1);
41450448Sobrien			free($2);
41518334Speter		}
41650448Sobrien		| STRING
41718334Speter		;
41850448Sobrien
419132727Skanvarset		: STRING PORTUNARY string		{
420132727Skan			if (pf->opts & PF_OPT_VERBOSE)
421132727Skan				printf("%s = %s\n", $1, $3);
422132727Skan			if (symset($1, $3) == -1) {
423132727Skan				yyerror("cannot store variable %s", $1);
424132727Skan				YYERROR;
425132727Skan			}
426132727Skan		}
427132727Skan		;
428132727Skan
429132727Skanscrubrule	: SCRUB dir interface af fromto nodf minttl maxmss fragcache
43052298Sobrien		{
43152298Sobrien			struct pf_rule r;
43252298Sobrien
43352298Sobrien			if (check_rulestate(PFCTL_STATE_SCRUB))
43452298Sobrien				YYERROR;
43552298Sobrien
43690081Sobrien			memset(&r, 0, sizeof(r));
43790081Sobrien
43890081Sobrien			r.action = PF_SCRUB;
439132727Skan			r.direction = $2;
44090081Sobrien
44190081Sobrien			if ($3) {
44218334Speter				if ($3->not) {
44390081Sobrien					yyerror("scrub rules do not support "
44490081Sobrien					    "'! <if>'");
44518334Speter					YYERROR;
44650448Sobrien				}
44750448Sobrien			}
44850448Sobrien			r.af = $4;
44952298Sobrien			if ($6)
45090081Sobrien				r.rule_flag |= PFRULE_NODF;
45152298Sobrien			if ($7)
45218334Speter				r.min_ttl = $7;
45390081Sobrien			if ($8)
45490081Sobrien				r.max_mss = $8;
45518334Speter			if ($9)
45650448Sobrien				r.rule_flag |= $9;
45750448Sobrien
45818334Speter			expand_rule(&r, $3, NULL, NULL,
45918334Speter			    $5.src.host, $5.src.port, $5.dst.host, $5.dst.port,
46052298Sobrien			    NULL, NULL, NULL);
46152298Sobrien		}
46290081Sobrien		;
46318334Speter
46418334Speterantispoof	: ANTISPOOF logquick antispoof_ifspc af {
46518334Speter			struct pf_rule r;
46652298Sobrien			struct node_host *h = NULL;
46752298Sobrien			struct node_if *i, *j;
46852298Sobrien
46952298Sobrien			if (check_rulestate(PFCTL_STATE_FILTER))
470132727Skan				YYERROR;
471132727Skan
47252298Sobrien			for (i = $3; i; i = i->next) {
47390081Sobrien				memset(&r, 0, sizeof(r));
47490081Sobrien
475132727Skan				r.action = PF_DROP;
47690081Sobrien				r.direction = PF_IN;
47790081Sobrien				r.log = $2.log;
47890081Sobrien				r.quick = $2.quick;
47918334Speter				r.af = $4;
48090081Sobrien
48190081Sobrien				j = calloc(1, sizeof(struct node_if));
48218334Speter				if (j == NULL)
48390081Sobrien					errx(1, "antispoof: calloc");
48490081Sobrien				strlcpy(j->ifname, i->ifname, IFNAMSIZ);
48518334Speter				j->not = 1;
48618334Speter				h = ifa_lookup(j->ifname, PFCTL_IFLOOKUP_NET);
48718334Speter
48818334Speter				expand_rule(&r, j, NULL, NULL, h, NULL, NULL,
48950448Sobrien				    NULL, NULL, NULL, NULL);
49096273Sobrien
49190081Sobrien				if ((i->ifa_flags & IFF_LOOPBACK) == 0) {
49218334Speter					memset(&r, 0, sizeof(r));
49318334Speter
49490081Sobrien					r.action = PF_DROP;
49518334Speter					r.direction = PF_IN;
49618334Speter					r.log = $2.log;
49718334Speter					r.quick = $2.quick;
49890081Sobrien					r.af = $4;
49918334Speter
50090081Sobrien					h = ifa_lookup(i->ifname,
50190081Sobrien					    PFCTL_IFLOOKUP_HOST);
502117404Skan
503132727Skan					expand_rule(&r, NULL, NULL, NULL, h,
50418334Speter					    NULL, NULL, NULL, NULL, NULL, NULL);
505122190Skan				}
50690081Sobrien			}
507132727Skan		}
50890081Sobrien		;
50918334Speter
51090081Sobrienantispoof_ifspc	: FOR if_item			{ $$ = $2; }
51190081Sobrien		| FOR '{' antispoof_iflst '}'	{ $$ = $3; }
51290081Sobrien		;
51318334Speter
51418334Speterantispoof_iflst	: if_item			{ $$ = $1; }
51518334Speter		| antispoof_iflst comma if_item	{
51650448Sobrien			$1->tail->next = $3;
51718334Speter			$1->tail = $3;
51818334Speter			$$ = $1;
51950448Sobrien		}
52018334Speter		;
52118334Speter
52218334Speter
52350448Sobrien/* altq stuff */
52418334Speter
52518334Speteraltqif		: ALTQ interface SCHEDULER schedtype bandwidth qlimit
52618334Speter		  tbrsize QUEUE qassign	{
52750448Sobrien			struct	pf_altq a;
52818334Speter
52918334Speter			if (check_rulestate(PFCTL_STATE_QUEUE))
53018334Speter				YYERROR;
531132727Skan
53218334Speter			memset(&a, 0, sizeof(a));
53318334Speter			if ($4.qtype == ALTQT_NONE) {
53450448Sobrien				yyerror("no scheduler specified!");
53518334Speter				YYERROR;
53618334Speter			}
53718334Speter			a.scheduler = $4.qtype;
53850448Sobrien			a.pq_u.cbq_opts.flags = $4.data.cbq_opts.flags;
53918334Speter			if ((a.ifbandwidth = $5.bw_absolute) == 0) {
54090081Sobrien				yyerror("interface bandwidth must be absolute");
54118334Speter				YYERROR;
54290081Sobrien			}
54318334Speter			a.qlimit = $6;
54490081Sobrien			a.tbrsize = $7;
54518334Speter			if ($9 == NULL) {
54690081Sobrien				yyerror("no child queues specified");
54718334Speter				YYERROR;
54818334Speter			}
54990081Sobrien			if (expand_altq(&a, $2, $9))
55018334Speter				YYERROR;
55118334Speter		}
552117404Skan		;
55318334Speter
55490081Sobrienqassign		: /* empty */		{ $$ = NULL; }
55590081Sobrien		| qassign_item		{ $$ = $1; }
55618334Speter		| '{' qassign_list '}'	{ $$ = $2; }
55790081Sobrien		;
55890081Sobrien
55990081Sobrienqassign_list	: qassign_item			{ $$ = $1; }
56018334Speter		| qassign_list comma qassign_item	{
56118334Speter			$1->tail->next = $3;
56218334Speter			$1->tail = $3;
56390081Sobrien			$$ = $1;
56418334Speter		}
56518334Speter		;
56618334Speter
56718334Speterqassign_item	: STRING			{
56850448Sobrien			$$ = calloc(1, sizeof(struct node_queue));
56950448Sobrien			if ($$ == NULL)
57050448Sobrien				err(1, "queue_item: calloc");
57118334Speter			strlcpy($$->queue, $1, PF_QNAME_SIZE);
57218334Speter			$$->next = NULL;
573117404Skan			$$->tail = $$;
57418334Speter		}
57518334Speter		;
57618334Speter
57718334Speterqueuespec	: QUEUE STRING bandwidth priority qlimit schedtype qassign {
57818334Speter			struct	pf_altq a;
57918334Speter
58018334Speter			if (check_rulestate(PFCTL_STATE_QUEUE))
58118334Speter				YYERROR;
58218334Speter
58318334Speter			memset(&a, 0, sizeof(a));
58418334Speter
585117404Skan			if (strlcpy(a.qname, $2, sizeof(a.qname)) >=
58618334Speter			    PF_QNAME_SIZE) {
58718334Speter				yyerror("queue name too long (max "
58890081Sobrien				    "%d chars)", PF_QNAME_SIZE-1);
58918334Speter				YYERROR;
590117404Skan			}
59190081Sobrien			if ($4 > 255) {
592132727Skan				yyerror("priority out of range: max 255");
593132727Skan				YYERROR;
59490081Sobrien			}
59590081Sobrien			a.priority = $4;
596132727Skan			a.qlimit = $5;
597132727Skan			a.scheduler = $6.qtype;
59818334Speter			switch (a.scheduler) {
59918334Speter			case ALTQT_CBQ:
600132727Skan				a.pq_u.cbq_opts.flags = $6.data.cbq_opts.flags;
601132727Skan			}
602132727Skan			if (expand_queue(&a, $7, $3))
603132727Skan				YYERROR;
604132727Skan
605132727Skan		}
606132727Skan		;
60718334Speter
60850448Sobrienschedtype	: /* empty */			{ $$.qtype = ALTQT_NONE; }
60950448Sobrien		| CBQ				{ $$.qtype = ALTQT_CBQ; }
61050448Sobrien		| CBQ '(' cbqflags_list ')'	{
61150448Sobrien			$$.qtype = ALTQT_CBQ;
61218334Speter			$$.data.cbq_opts.flags = $3;
61350448Sobrien		}
61450448Sobrien		;
61550448Sobrien
61650448Sobriencbqflags_list	: cbqflags_item				{ $$ |= $1; }
61750448Sobrien		| cbqflags_list comma cbqflags_item	{ $$ |= $3; }
61818334Speter		;
61990081Sobrien
62018334Speter
62118334Spetercbqflags_item	: DEFAULT	{ $$ = CBQCLF_DEFCLASS; }
62290081Sobrien		| CONTROL	{ $$ = CBQCLF_CTLCLASS; }
62318334Speter		| BORROW	{ $$ = CBQCLF_BORROW; }
62450448Sobrien		| RED		{ $$ = CBQCLF_RED; }
62590081Sobrien		| ECN		{ $$ = CBQCLF_RED|CBQCLF_ECN; }
62650448Sobrien		| RIO		{ $$ = CBQCLF_RIO; }
62750448Sobrien		;
62850448Sobrien
62950448Sobrienbandwidth	: /* empty */		{
63090081Sobrien			$$.bw_absolute = 0;
63190081Sobrien			$$.bw_percent = 100;
63290081Sobrien		}
63390081Sobrien		| BANDWIDTH STRING {
63490081Sobrien			double bps;
635132727Skan			char *cp;
636132727Skan
637132727Skan			$$.bw_percent = 0;
638132727Skan
639132727Skan			bps = strtod($2, &cp);
640132727Skan			if (cp != NULL) {
641132727Skan				if (!strcmp(cp, "b"))
64218334Speter					;
64318334Speter				else if (!strcmp(cp, "Kb"))
644132727Skan					bps *= 1000;
645132727Skan				else if (!strcmp(cp, "Mb"))
646132727Skan					bps *= 1000 * 1000;
647132727Skan				else if (!strcmp(cp, "Gb"))
648132727Skan					bps *= 1000 * 1000 * 1000;
649132727Skan				else if (!strcmp(cp, "%")) {
650132727Skan					if (bps < 0 || bps > 100) {
651132727Skan						yyerror("bandwidth spec "
652132727Skan						    "out of range");
65318334Speter						YYERROR;
654132727Skan					}
65596273Sobrien					$$.bw_percent = bps;
656117404Skan					bps = 0;
65796273Sobrien				} else {
658132727Skan					yyerror("unknown unit %s", cp);
65990081Sobrien					YYERROR;
660132727Skan				}
66190081Sobrien			}
662117404Skan			$$.bw_absolute = (u_int32_t)bps;
663132727Skan		}
664117404Skan		;
665132727Skan
666132727Skanpriority	: /* empty */		{ $$ = DEFAULT_PRIORITY; }
66790081Sobrien		| PRIORITY number	{
66890081Sobrien			if ($2 > 255) {
66990081Sobrien				yyerror("priority out of range: max 255");
67090081Sobrien				YYERROR;
67190081Sobrien			}
67290081Sobrien			$$ = $2;
67390081Sobrien		}
67490081Sobrien		;
675132727Skan
67690081Sobrienqlimit		: /* empty */		{ $$ = DEFAULT_QLIMIT; }
67790081Sobrien		| QLIMIT number		{
678117404Skan			if ($2 > 65535) {
67990081Sobrien				yyerror("qlimit out of range: max 65535");
68090081Sobrien				YYERROR;
68190081Sobrien			}
68290081Sobrien			$$ = $2;
683132727Skan		}
684132727Skan		;
685132727Skan
68690081Sobrien
68750448Sobrientbrsize		: /* empty */		{ $$ = 0; }
68818334Speter		| TBRSIZE number	{
68918334Speter			if ($2 > 65535) {
69090081Sobrien				yyerror("tbrsize too big: max 65535");
69190081Sobrien				YYERROR;
69290081Sobrien			}
69390081Sobrien			$$ = $2;
69418334Speter		}
695132727Skan		;
696132727Skan
697117404Skanpfrule		: action dir logquick interface route af proto fromto
698117404Skan		  uids gids flags icmpspec tos keep fragment allowopts label
69918334Speter		  qname
70018334Speter		{
70118334Speter			struct pf_rule r;
70218334Speter			struct node_state_opt *o;
70390081Sobrien			struct node_proto *proto;
70490081Sobrien
70590081Sobrien			if (check_rulestate(PFCTL_STATE_FILTER))
70690081Sobrien				YYERROR;
70718334Speter
70890081Sobrien			memset(&r, 0, sizeof(r));
709132727Skan
71018334Speter			r.action = $1.b1;
71118334Speter			switch ($1.b2) {
71218334Speter			case PFRULE_RETURNRST:
713132727Skan				r.rule_flag |= PFRULE_RETURNRST;
71418334Speter				r.return_ttl = $1.w;
71518334Speter				break;
71618334Speter			case PFRULE_RETURNICMP:
717132727Skan				r.rule_flag |= PFRULE_RETURNICMP;
71818334Speter				r.return_icmp = $1.w;
719117404Skan				r.return_icmp6 = $1.w2;
720117404Skan				break;
721117404Skan			case PFRULE_RETURN:
722117404Skan				r.rule_flag |= PFRULE_RETURN;
723117404Skan				r.return_icmp = $1.w;
724117404Skan				r.return_icmp6 = $1.w2;
72518334Speter				break;
72618334Speter			}
727132727Skan			r.direction = $2;
72818334Speter			r.log = $3.log;
729132727Skan			r.quick = $3.quick;
730132727Skan
731132727Skan			r.af = $6;
732132727Skan			r.flags = $11.b1;
73390081Sobrien			r.flagset = $11.b2;
734132727Skan
735132727Skan			if ($11.b1 || $11.b2) {
736132727Skan				for (proto = $7; proto != NULL &&
73718334Speter				    proto->proto != IPPROTO_TCP;
73818334Speter				    proto = proto->next)
73918334Speter					;	/* nothing */
74090081Sobrien				if (proto == NULL && $7 != NULL) {
74118334Speter					yyerror("flags only apply to tcp");
74290081Sobrien					YYERROR;
74390081Sobrien				}
744132727Skan			}
74590081Sobrien
746132727Skan			r.tos = $13;
74718334Speter			r.keep_state = $14.action;
74818334Speter			o = $14.options;
74990081Sobrien			while (o) {
75018334Speter				struct node_state_opt *p = o;
75150448Sobrien
752132727Skan				switch (o->type) {
753132727Skan				case PF_STATE_OPT_MAX:
75418334Speter					if (r.max_states) {
755132727Skan						yyerror("state option 'max' "
75650448Sobrien						    "multiple definitions");
75750448Sobrien						YYERROR;
75818334Speter					}
75918334Speter					r.max_states = o->data.max_states;
76018334Speter					break;
76118334Speter				case PF_STATE_OPT_TIMEOUT:
76218334Speter					if (r.timeout[o->data.timeout.number]) {
76318334Speter						yyerror("state timeout %s "
764132727Skan						    "multiple definitions",
765132727Skan						    pf_timeouts[o->data.
766132727Skan						    timeout.number].name);
767132727Skan						YYERROR;
768132727Skan					}
769132727Skan					r.timeout[o->data.timeout.number] =
770132727Skan					    o->data.timeout.seconds;
771132727Skan				}
772132727Skan				o = o->next;
773132727Skan				free(p);
774132727Skan			}
775132727Skan
776132727Skan			if ($15)
777132727Skan				r.rule_flag |= PFRULE_FRAGMENT;
778132727Skan			r.allow_opts = $16;
779132727Skan
780132727Skan			decide_address_family($8.src.host, &r.af);
781132727Skan			decide_address_family($8.dst.host, &r.af);
782132727Skan
783132727Skan			if ($5.rt) {
78452298Sobrien				r.rt = $5.rt;
78518334Speter				r.rt_pool.opts = $5.pool_opts;
78618334Speter			}
78790081Sobrien			if (r.rt && r.rt != PF_FASTROUTE) {
78818334Speter
78990081Sobrien				decide_address_family($5.host, &r.af);
79090081Sobrien				remove_invalid_hosts(&$5.host, &r.af);
79150448Sobrien				if ($5.host == NULL) {
79250448Sobrien					yyerror("$5.host == NULL");
79318334Speter					YYERROR;
79418334Speter				}
79590081Sobrien				if ($5.host->next != NULL) {
79618334Speter					if (r.rt_pool.opts == PF_POOL_NONE)
79718334Speter						r.rt_pool.opts = PF_POOL_ROUNDROBIN;
79850448Sobrien					if (r.rt_pool.opts != PF_POOL_ROUNDROBIN) {
79918334Speter						yyerror("r.rt_pool.opts must be "
80018334Speter						    "PF_POOL_ROUNDROBIN");
80118334Speter						YYERROR;
80250448Sobrien					}
80352298Sobrien				}
80490081Sobrien			}
80552298Sobrien
80618334Speter			if ($17) {
807132727Skan				if (strlcpy(r.label, $17, sizeof(r.label)) >=
80852298Sobrien				    PF_RULE_LABEL_SIZE) {
80952298Sobrien					yyerror("rule label too long (max "
81090081Sobrien					    "%d chars)", PF_RULE_LABEL_SIZE-1);
81190081Sobrien					YYERROR;
81252298Sobrien				}
81352298Sobrien				free($17);
81452298Sobrien			}
81552298Sobrien
81652298Sobrien			if ($18) {
81752298Sobrien				if (strlcpy(r.qname, $18, sizeof(r.qname)) >=
81852298Sobrien				    PF_QNAME_SIZE) {
81990081Sobrien					yyerror("rule qname too long (max "
82090081Sobrien					    "%d chars)", PF_QNAME_SIZE-1);
82150448Sobrien					YYERROR;
82218334Speter				}
82318334Speter				free($18);
82490081Sobrien			}
82590081Sobrien
82690081Sobrien			expand_rule(&r, $4, $5.host, $7,
82790081Sobrien			    $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
82890081Sobrien			    $9, $10, $12);
82990081Sobrien		}
83050448Sobrien		;
83190081Sobrien
832117404Skanaction		: PASS			{ $$.b1 = PF_PASS; $$.b2 = $$.w = 0; }
833132727Skan		| BLOCK blockspec	{ $$ = $2; $$.b1 = PF_DROP; }
834132727Skan		;
83518334Speter
83618334Speterblockspec	: /* empty */		{
837132727Skan			$$.b2 = blockpolicy;
83818334Speter			$$.w = returnicmpdefault;
83918334Speter			$$.w2 = returnicmp6default;
84018334Speter		}
841132727Skan		| DROP			{
842132727Skan			$$.b2 = PFRULE_DROP;
843117404Skan			$$.w = 0;
844132727Skan			$$.w2 = 0;
845132727Skan		}
846132727Skan		| RETURNRST		{
847132727Skan			$$.b2 = PFRULE_RETURNRST;
848117404Skan			$$.w = 0;
849117404Skan			$$.w2 = 0;
850132727Skan		}
851117404Skan		| RETURNRST '(' TTL number ')'	{
852132727Skan			$$.b2 = PFRULE_RETURNRST;
853132727Skan			$$.w = $4;
854132727Skan			$$.w2 = 0;
855117404Skan		}
856117404Skan		| RETURNICMP		{
857117404Skan			$$.b2 = PFRULE_RETURNICMP;
858117404Skan			$$.w = returnicmpdefault;
859132727Skan			$$.w2 = returnicmp6default;
860132727Skan		}
861132727Skan		| RETURNICMP6		{
862132727Skan			$$.b2 = PFRULE_RETURNICMP;
86390081Sobrien			$$.w = returnicmpdefault;
864132727Skan			$$.w2 = returnicmp6default;
865132727Skan		}
866132727Skan		| RETURNICMP '(' STRING ')'	{
867132727Skan			$$.b2 = PFRULE_RETURNICMP;
868132727Skan			if (!($$.w = parseicmpspec($3, AF_INET)))
869132727Skan				YYERROR;
870132727Skan			$$.w2 = returnicmp6default;
871132727Skan		}
87290081Sobrien		| RETURNICMP6 '(' STRING ')'	{
87390081Sobrien			$$.b2 = PFRULE_RETURNICMP;
87418334Speter			$$.w = returnicmpdefault;
87518334Speter			if (!($$.w2 = parseicmpspec($3, AF_INET6)))
87618334Speter				YYERROR;
87790081Sobrien		}
878132727Skan		| RETURNICMP '(' STRING comma STRING ')' {
879132727Skan			$$.b2 = PFRULE_RETURNICMP;
880117404Skan			if (!($$.w = parseicmpspec($3, AF_INET)))
88190081Sobrien				YYERROR;
88250448Sobrien			if (!($$.w2 = parseicmpspec($5, AF_INET6)));
88350448Sobrien		}
88450448Sobrien		| RETURN {
88550448Sobrien			$$.b2 = PFRULE_RETURN;
88690081Sobrien			$$.w = returnicmpdefault;
887132727Skan			$$.w2 = returnicmp6default;
888117404Skan		}
889117404Skan		;
890132727Skan
891117404Skanfragcache	: /* empty */		{ $$ = 0; }
892132727Skan		| fragment FRAGNORM	{ $$ = 0; /* default */ }
893132727Skan		| fragment FRAGCROP	{ $$ = PFRULE_FRAGCROP; }
894132727Skan		| fragment FRAGDROP	{ $$ = PFRULE_FRAGDROP; }
89518334Speter		;
89618334Speter
897132727Skan
898132727Skandir		: IN				{ $$ = PF_IN; }
89918334Speter		| OUT				{ $$ = PF_OUT; }
900132727Skan		;
901132727Skan
90250448Sobrienlogquick	: /* empty */			{ $$.log = 0; $$.quick = 0; }
90350448Sobrien		| log				{ $$.log = $1; $$.quick = 0; }
90450448Sobrien		| QUICK				{ $$.log = 0; $$.quick = 1; }
90590081Sobrien		| log QUICK			{ $$.log = $1; $$.quick = 1; }
906117404Skan		| QUICK log			{ $$.log = $2; $$.quick = 1; }
90750448Sobrien		;
90850448Sobrien
90950448Sobrienlog		: LOG				{ $$ = 1; }
91090081Sobrien		| LOGALL			{ $$ = 2; }
911117404Skan		;
91250448Sobrien
913117404Skaninterface	: /* empty */			{ $$ = NULL; }
914117404Skan		| ON if_item_not		{ $$ = $2; }
915117404Skan		| ON '{' if_list '}'		{ $$ = $3; }
916117404Skan		;
917117404Skan
91890081Sobrienif_list		: if_item_not			{ $$ = $1; }
91990081Sobrien		| if_list comma if_item_not	{
92090081Sobrien			$1->tail->next = $3;
92190081Sobrien			$1->tail = $3;
92250448Sobrien			$$ = $1;
92318334Speter		}
92418334Speter		;
92518334Speter
92618334Speterif_item_not	: '!' if_item			{ $$ = $2; $$->not = 1; }
92790081Sobrien		| if_item			{ $$ = $1; }
92818334Speter
92990081Sobrienif_item		: STRING			{
930132727Skan			struct node_host *n;
93118334Speter
93218334Speter			if ((n = ifa_exists($1)) == NULL) {
933132727Skan				yyerror("unknown interface %s", $1);
934132727Skan				YYERROR;
935132727Skan			}
936132727Skan			$$ = calloc(1, sizeof(struct node_if));
93718334Speter			if ($$ == NULL)
938132727Skan				err(1, "if_item: calloc");
93950448Sobrien			strlcpy($$->ifname, $1, IFNAMSIZ);
94018334Speter			$$->ifa_flags = n->ifa_flags;
941132727Skan			$$->not = 0;
942132727Skan			$$->next = NULL;
943132727Skan			$$->tail = $$;
944132727Skan		}
94518334Speter		;
946132727Skan
947132727Skanaf		: /* empty */			{ $$ = 0; }
948132727Skan		| INET				{ $$ = AF_INET; }
949132727Skan		| INET6				{ $$ = AF_INET6; }
950132727Skan
951132727Skanproto		: /* empty */			{ $$ = NULL; }
952132727Skan		| PROTO proto_item		{ $$ = $2; }
953132727Skan		| PROTO '{' proto_list '}'	{ $$ = $3; }
954132727Skan		;
955132727Skan
956132727Skanproto_list	: proto_item			{ $$ = $1; }
957132727Skan		| proto_list comma proto_item	{
958132727Skan			$1->tail->next = $3;
95950448Sobrien			$1->tail = $3;
96018334Speter			$$ = $1;
961132727Skan		}
962132727Skan		;
963132727Skan
96418334Speterproto_item	: STRING			{
965132727Skan			u_int8_t pr;
966132727Skan			u_long ulval;
967132727Skan
968132727Skan			if (atoul($1, &ulval) == 0) {
969132727Skan				if (ulval > 255) {
970132727Skan					yyerror("protocol outside range");
97190081Sobrien					YYERROR;
972132727Skan				}
97390081Sobrien				pr = (u_int8_t)ulval;
974132727Skan			} else {
97590081Sobrien				struct protoent *p;
97650448Sobrien
97790081Sobrien				p = getprotobyname($1);
978132727Skan				if (p == NULL) {
979132727Skan					yyerror("unknown protocol %s", $1);
98090081Sobrien					YYERROR;
98190081Sobrien				}
982132727Skan				pr = p->p_proto;
983132727Skan			}
984132727Skan			if (pr == 0) {
985132727Skan				yyerror("proto 0 cannot be used");
98690081Sobrien				YYERROR;
98790081Sobrien			}
98890081Sobrien			$$ = calloc(1, sizeof(struct node_proto));
989132727Skan			if ($$ == NULL)
99090081Sobrien				err(1, "proto_item: calloc");
99190081Sobrien			$$->proto = pr;
992132727Skan			$$->next = NULL;
993132727Skan			$$->tail = $$;
994132727Skan		}
995132727Skan		;
996132727Skan
99790081Sobrienfromto		: ALL				{
998132727Skan			$$.src.host = NULL;
999132727Skan			$$.src.port = NULL;
100090081Sobrien			$$.dst.host = NULL;
100190081Sobrien			$$.dst.port = NULL;
1002132727Skan		}
100390081Sobrien		| FROM ipportspec TO ipportspec	{
100490081Sobrien			$$.src = $2;
100590081Sobrien			$$.dst = $4;
100690081Sobrien		}
1007132727Skan		;
100890081Sobrien
100990081Sobrienipportspec	: ipspec			{ $$.host = $1; $$.port = NULL; }
101090081Sobrien		| ipspec PORT portspec		{
101190081Sobrien			$$.host = $1;
101290081Sobrien			$$.port = $3;
101390081Sobrien		}
101490081Sobrien		;
101590081Sobrien
1016117404Skanipspec		: ANY				{ $$ = NULL; }
1017117404Skan		| xhost				{ $$ = $1; }
1018117404Skan		| '{' host_list '}'		{ $$ = $2; }
101950448Sobrien		;
102050448Sobrien
102150448Sobrienhost_list	: xhost				{ $$ = $1; }
102250448Sobrien		| host_list comma xhost		{
102350448Sobrien			/* $3 may be a list, so use its tail pointer */
102450448Sobrien			if ($3 == NULL)
102550448Sobrien				$$ = $1;
102650448Sobrien			else if ($1 == NULL)
102750448Sobrien				$$ = $3;
102890081Sobrien			else {
102990081Sobrien				$1->tail->next = $3->tail;
103090081Sobrien				$1->tail = $3->tail;
103190081Sobrien				$$ = $1;
1032132727Skan			}
103390081Sobrien		}
103490081Sobrien		;
103590081Sobrien
103650448Sobrienxhost		: '!' host			{
103750448Sobrien			struct node_host *h;
1038132727Skan			for (h = $2; h; h = h->next)
1039132727Skan				h->not = 1;
1040132727Skan			$$ = $2;
104150448Sobrien		}
104250448Sobrien		| host				{ $$ = $1; }
104350448Sobrien		| NOROUTE			{
104450448Sobrien			$$ = calloc(1, sizeof(struct node_host));
104590081Sobrien			if ($$ == NULL)
104650448Sobrien				err(1, "xhost: calloc");
104790081Sobrien			$$->noroute = 1;
104850448Sobrien			$$->next = NULL;
104950448Sobrien			$$->tail = $$;
105052298Sobrien		}
105150448Sobrien		;
105250448Sobrien
1053132727Skanhost		: address
1054132727Skan		| STRING '/' number		{ $$ = host($1, $3); }
1055132727Skan		;
1056132727Skan
105752298Sobriennumber		: STRING			{
105818334Speter			u_long ulval;
105990081Sobrien
106090081Sobrien			if (atoul($1, &ulval) == -1) {
106118334Speter				yyerror("%s is not a number", $1);
106290081Sobrien				YYERROR;
1063132727Skan			} else
106418334Speter				$$ = ulval;
106590081Sobrien		}
106618334Speter		;
106718334Speter
1068132727Skanaddress		: '(' STRING ')'		{
106950448Sobrien			$$ = calloc(1, sizeof(struct node_host));
107018334Speter			if ($$ == NULL)
107118334Speter				err(1, "address: calloc");
1072117404Skan			$$->af = 0;
107318334Speter			set_ipmask($$, 128);
107418334Speter			$$->addr.addr_dyn = (struct pf_addr_dyn *)1;
107518334Speter			strncpy($$->addr.addr.pfa.ifname, $2,
107650448Sobrien			    sizeof($$->addr.addr.pfa.ifname));
107718334Speter			$$->next = NULL;
107818334Speter			$$->tail = $$;
107918334Speter		}
108052298Sobrien		| STRING			{ $$ = host($1, -1); }
108118334Speter		;
108218334Speter
108318334Speterportspec	: port_item			{ $$ = $1; }
108490081Sobrien		| '{' port_list '}'		{ $$ = $2; }
108518334Speter		;
108690081Sobrien
1087132727Skanport_list	: port_item			{ $$ = $1; }
108890081Sobrien		| port_list comma port_item	{
1089132727Skan			$1->tail->next = $3;
109090081Sobrien			$1->tail = $3;
109118334Speter			$$ = $1;
109218334Speter		}
109318334Speter		;
109418334Speter
109552298Sobrienport_item	: port				{
109652298Sobrien			$$ = calloc(1, sizeof(struct node_port));
109752298Sobrien			if ($$ == NULL)
109852298Sobrien				err(1, "port_item: calloc");
109918334Speter			$$->port[0] = $1;
110090081Sobrien			$$->port[1] = $1;
110152298Sobrien			$$->op = PF_OP_EQ;
110252298Sobrien			$$->next = NULL;
110370638Sobrien			$$->tail = $$;
110452298Sobrien		}
110552298Sobrien		| PORTUNARY port		{
110652298Sobrien			$$ = calloc(1, sizeof(struct node_port));
110752298Sobrien			if ($$ == NULL)
110818334Speter				err(1, "port_item: calloc");
1109132727Skan			$$->port[0] = $2;
111018334Speter			$$->port[1] = $2;
1111132727Skan			$$->op = $1;
111218334Speter			$$->next = NULL;
111318334Speter			$$->tail = $$;
111418334Speter		}
111518334Speter		| port PORTBINARY port		{
111650448Sobrien			$$ = calloc(1, sizeof(struct node_port));
111718334Speter			if ($$ == NULL)
111818334Speter				err(1, "port_item: calloc");
111990081Sobrien			$$->port[0] = $1;
112090081Sobrien			$$->port[1] = $3;
112190081Sobrien			$$->op = $2;
112218334Speter			$$->next = NULL;
112318334Speter			$$->tail = $$;
112418334Speter		}
112518334Speter		;
112618334Speter
112718334Speterport		: STRING			{
112818334Speter			struct servent *s = NULL;
112918334Speter			u_long ulval;
113018334Speter
113150448Sobrien			if (atoul($1, &ulval) == 0) {
113218334Speter				if (ulval > 65535) {
113318334Speter					yyerror("illegal port value %d", ulval);
113490081Sobrien					YYERROR;
113590081Sobrien				}
113618334Speter				$$ = htons(ulval);
1137117404Skan			} else {
113890081Sobrien				s = getservbyname($1, "tcp");
113990081Sobrien				if (s == NULL)
114090081Sobrien					s = getservbyname($1, "udp");
1141132727Skan				if (s == NULL) {
114290081Sobrien					yyerror("unknown port %s", $1);
114390081Sobrien					YYERROR;
114490081Sobrien				}
114590081Sobrien				$$ = s->s_port;
114690081Sobrien			}
114790081Sobrien		}
114890081Sobrien		;
114990081Sobrien
115090081Sobrienuids		: /* empty */			{ $$ = NULL; }
1151117404Skan		| USER uid_item			{ $$ = $2; }
1152117404Skan		| USER '{' uid_list '}'		{ $$ = $3; }
115390081Sobrien		;
115490081Sobrien
115590081Sobrienuid_list	: uid_item			{ $$ = $1; }
115690081Sobrien		| uid_list comma uid_item	{
115790081Sobrien			$1->tail->next = $3;
115890081Sobrien			$1->tail = $3;
115990081Sobrien			$$ = $1;
116096273Sobrien		}
116190081Sobrien		;
116290081Sobrien
1163104764Skanuid_item	: uid				{
116490081Sobrien			$$ = calloc(1, sizeof(struct node_uid));
116590081Sobrien			if ($$ == NULL)
116690081Sobrien				err(1, "uid_item: calloc");
116718334Speter			$$->uid[0] = $1;
116890081Sobrien			$$->uid[1] = $1;
116990081Sobrien			$$->op = PF_OP_EQ;
1170132727Skan			$$->next = NULL;
117190081Sobrien			$$->tail = $$;
1172117404Skan		}
1173117404Skan		| PORTUNARY uid			{
1174132727Skan			if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
1175132727Skan				yyerror("user unknown requires operator = or !=");
117618334Speter				YYERROR;
1177132727Skan			}
1178132727Skan			$$ = calloc(1, sizeof(struct node_uid));
117990081Sobrien			if ($$ == NULL)
1180132727Skan				err(1, "uid_item: calloc");
118190081Sobrien			$$->uid[0] = $2;
1182132727Skan			$$->uid[1] = $2;
118390081Sobrien			$$->op = $1;
118490081Sobrien			$$->next = NULL;
118590081Sobrien			$$->tail = $$;
118618334Speter		}
118718334Speter		| uid PORTBINARY uid		{
118818334Speter			if ($1 == UID_MAX || $3 == UID_MAX) {
118918334Speter				yyerror("user unknown requires operator = or !=");
119050448Sobrien				YYERROR;
119150448Sobrien			}
1192104764Skan			$$ = calloc(1, sizeof(struct node_uid));
1193104764Skan			if ($$ == NULL)
119496273Sobrien				err(1, "uid_item: calloc");
119596273Sobrien			$$->uid[0] = $1;
119696273Sobrien			$$->uid[1] = $3;
119796273Sobrien			$$->op = $2;
119896273Sobrien			$$->next = NULL;
119996273Sobrien			$$->tail = $$;
120096273Sobrien		}
1201104764Skan		;
1202104764Skan
120396273Sobrienuid		: STRING			{
120496273Sobrien			u_long ulval;
1205104764Skan
1206104764Skan			if (atoul($1, &ulval) == -1) {
120796273Sobrien				if (!strcmp($1, "unknown"))
120890081Sobrien					$$ = UID_MAX;
120990081Sobrien				else {
121018334Speter					struct passwd *pw;
121118334Speter
121290081Sobrien					if ((pw = getpwnam($1)) == NULL) {
1213132727Skan						yyerror("unknown user %s", $1);
121490081Sobrien						YYERROR;
1215132727Skan					}
121690081Sobrien					$$ = pw->pw_uid;
121790081Sobrien				}
121890081Sobrien			} else {
121918334Speter				if (ulval >= UID_MAX) {
122018334Speter					yyerror("illegal uid value %lu", ulval);
122118334Speter					YYERROR;
122218334Speter				}
122390081Sobrien				$$ = ulval;
1224132727Skan			}
122590081Sobrien		}
122690081Sobrien		;
122790081Sobrien
122818334Spetergids		: /* empty */			{ $$ = NULL; }
122990081Sobrien		| GROUP gid_item		{ $$ = $2; }
1230132727Skan		| GROUP '{' gid_list '}'	{ $$ = $3; }
123190081Sobrien		;
123290081Sobrien
123390081Sobriengid_list	: gid_item			{ $$ = $1; }
123418334Speter		| gid_list comma gid_item	{
123590081Sobrien			$1->tail->next = $3;
123690081Sobrien			$1->tail = $3;
1237132727Skan			$$ = $1;
123890081Sobrien		}
123990081Sobrien		;
124090081Sobrien
124118334Spetergid_item	: gid				{
124290081Sobrien			$$ = calloc(1, sizeof(struct node_gid));
1243132727Skan			if ($$ == NULL)
124490081Sobrien				err(1, "gid_item: calloc");
124590081Sobrien			$$->gid[0] = $1;
124690081Sobrien			$$->gid[1] = $1;
124750448Sobrien			$$->op = PF_OP_EQ;
124890081Sobrien			$$->next = NULL;
124990081Sobrien			$$->tail = $$;
1250132727Skan		}
125190081Sobrien		| PORTUNARY gid			{
125290081Sobrien			if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
125390081Sobrien				yyerror("group unknown requires operator = or !=");
125490081Sobrien				YYERROR;
125590081Sobrien			}
125690081Sobrien			$$ = calloc(1, sizeof(struct node_gid));
125750448Sobrien			if ($$ == NULL)
125850448Sobrien				err(1, "gid_item: calloc");
125950448Sobrien			$$->gid[0] = $2;
126050448Sobrien			$$->gid[1] = $2;
126150448Sobrien			$$->op = $1;
126250448Sobrien			$$->next = NULL;
126350448Sobrien			$$->tail = $$;
126450448Sobrien		}
126590081Sobrien		| gid PORTBINARY gid		{
126650448Sobrien			if ($1 == GID_MAX || $3 == GID_MAX) {
126718334Speter				yyerror("group unknown requires operator = or !=");
126818334Speter				YYERROR;
126918334Speter			}
127018334Speter			$$ = calloc(1, sizeof(struct node_gid));
127118334Speter			if ($$ == NULL)
127218334Speter				err(1, "gid_item: calloc");
127318334Speter			$$->gid[0] = $1;
1274132727Skan			$$->gid[1] = $3;
1275132727Skan			$$->op = $2;
1276132727Skan			$$->next = NULL;
1277132727Skan			$$->tail = $$;
1278132727Skan		}
127990081Sobrien		;
1280132727Skan
128190081Sobriengid		: STRING			{
1282132727Skan			u_long ulval;
1283132727Skan
1284132727Skan			if (atoul($1, &ulval) == -1) {
1285132727Skan				if (!strcmp($1, "unknown"))
1286132727Skan					$$ = GID_MAX;
1287132727Skan				else {
1288132727Skan					struct group *grp;
128950448Sobrien
1290132727Skan					if ((grp = getgrnam($1)) == NULL) {
1291132727Skan						yyerror("unknown group %s", $1);
1292132727Skan						YYERROR;
129318334Speter					}
1294132727Skan					$$ = grp->gr_gid;
1295132727Skan				}
1296132727Skan			} else {
1297132727Skan				if (ulval >= GID_MAX) {
1298132727Skan					yyerror("illegal gid value %lu", ulval);
1299132727Skan					YYERROR;
1300132727Skan				}
1301132727Skan				$$ = ulval;
1302132727Skan			}
130390081Sobrien		}
1304132727Skan		;
1305132727Skan
1306132727Skanflag		: STRING			{
1307132727Skan			int f;
1308132727Skan
1309132727Skan			if ((f = parse_flags($1)) < 0) {
1310132727Skan				yyerror("bad flags %s", $1);
131190081Sobrien				YYERROR;
1312132727Skan			}
1313132727Skan			$$.b1 = f;
1314132727Skan		}
1315132727Skan		;
1316132727Skan
1317132727Skanflags		: /* empty */			{ $$.b1 = 0; $$.b2 = 0; }
1318132727Skan		| FLAGS flag "/" flag		{ $$.b1 = $2.b1; $$.b2 = $4.b1; }
1319132727Skan		| FLAGS "/" flag		{ $$.b1 = 0; $$.b2 = $3.b1; }
1320132727Skan		;
1321132727Skan
1322132727Skanicmpspec	: /* empty */			{ $$ = NULL; }
1323132727Skan		| ICMPTYPE icmp_item		{ $$ = $2; }
1324132727Skan		| ICMPTYPE '{' icmp_list '}'	{ $$ = $3; }
1325132727Skan		| ICMP6TYPE icmp6_item		{ $$ = $2; }
1326132727Skan		| ICMP6TYPE '{' icmp6_list '}'	{ $$ = $3; }
1327132727Skan		;
1328132727Skan
132918334Spetericmp_list	: icmp_item			{ $$ = $1; }
1330117404Skan		| icmp_list comma icmp_item	{
133190081Sobrien			$1->tail->next = $3;
133252298Sobrien			$1->tail = $3;
133318334Speter			$$ = $1;
133490081Sobrien		}
133590081Sobrien		;
133690081Sobrien
133718334Spetericmp6_list	: icmp6_item			{ $$ = $1; }
1338132727Skan		| icmp6_list comma icmp6_item	{
133990081Sobrien			$1->tail->next = $3;
134018334Speter			$1->tail = $3;
1341132727Skan			$$ = $1;
134290081Sobrien		}
134318334Speter		;
1344132727Skan
1345117404Skanicmp_item	: icmptype		{
134618334Speter			$$ = calloc(1, sizeof(struct node_icmp));
134718334Speter			if ($$ == NULL)
134818334Speter				err(1, "icmp_item: calloc");
1349132727Skan			$$->type = $1;
1350132727Skan			$$->code = 0;
1351132727Skan			$$->proto = IPPROTO_ICMP;
1352132727Skan			$$->next = NULL;
1353132727Skan			$$->tail = $$;
1354132727Skan		}
1355132727Skan		| icmptype CODE STRING	{
135618334Speter			const struct icmpcodeent *p;
1357132727Skan			u_long ulval;
1358132727Skan
1359132727Skan			if (atoul($3, &ulval) == 0) {
1360132727Skan				if (ulval > 255) {
1361132727Skan					yyerror("illegal icmp-code %d", ulval);
1362117404Skan					YYERROR;
1363132727Skan				}
1364132727Skan			} else {
1365132727Skan				if ((p = geticmpcodebyname($1-1, $3,
1366132727Skan				    AF_INET)) == NULL) {
136790081Sobrien					yyerror("unknown icmp-code %s", $3);
136890081Sobrien					YYERROR;
1369132727Skan				}
137090081Sobrien				ulval = p->code;
1371117404Skan			}
137290081Sobrien			$$ = calloc(1, sizeof(struct node_icmp));
1373132727Skan			if ($$ == NULL)
1374132727Skan				err(1, "icmp_item: calloc");
137590081Sobrien			$$->type = $1;
1376132727Skan			$$->code = ulval + 1;
1377132727Skan			$$->proto = IPPROTO_ICMP;
1378132727Skan			$$->next = NULL;
137990081Sobrien			$$->tail = $$;
1380132727Skan		}
1381132727Skan		;
1382117404Skan
1383132727Skanicmp6_item	: icmp6type		{
1384132727Skan			$$ = calloc(1, sizeof(struct node_icmp));
1385132727Skan			if ($$ == NULL)
1386132727Skan				err(1, "icmp_item: calloc");
1387132727Skan			$$->type = $1;
1388132727Skan			$$->code = 0;
1389132727Skan			$$->proto = IPPROTO_ICMPV6;
139018334Speter			$$->next = NULL;
139118334Speter			$$->tail = $$;
139250448Sobrien		}
139390081Sobrien		| icmp6type CODE STRING	{
1394132727Skan			const struct icmpcodeent *p;
1395132727Skan			u_long ulval;
139618334Speter
1397132727Skan			if (atoul($3, &ulval) == 0) {
139890081Sobrien				if (ulval > 255) {
139990081Sobrien					yyerror("illegal icmp6-code %ld", ulval);
1400132727Skan					YYERROR;
1401117404Skan				}
140290081Sobrien			} else {
140390081Sobrien				if ((p = geticmpcodebyname($1-1, $3,
140490081Sobrien				    AF_INET6)) == NULL) {
1405132727Skan					yyerror("unknown icmp6-code %s", $3);
140690081Sobrien					YYERROR;
140790081Sobrien				}
140890081Sobrien				ulval = p->code;
140950448Sobrien			}
141050448Sobrien			$$ = calloc(1, sizeof(struct node_icmp));
141190081Sobrien			if ($$ == NULL)
141218334Speter				err(1, "icmp_item: calloc");
1413132727Skan			$$->type = $1;
141490081Sobrien			$$->code = ulval + 1;
141590081Sobrien			$$->proto = IPPROTO_ICMPV6;
141690081Sobrien			$$->next = NULL;
141790081Sobrien			$$->tail = $$;
141890081Sobrien		}
141952298Sobrien		;
1420132727Skan
142190081Sobrienicmptype	: STRING			{
142250448Sobrien			const struct icmptypeent *p;
142390081Sobrien			u_long ulval;
1424117404Skan
142590081Sobrien			if (atoul($1, &ulval) == 0) {
142690081Sobrien				if (ulval > 255) {
142750448Sobrien					yyerror("illegal icmp-type %d", ulval);
1428132727Skan					YYERROR;
1429132727Skan				}
1430132727Skan				$$ = ulval + 1;
143150448Sobrien			} else {
1432132727Skan				if ((p = geticmptypebyname($1, AF_INET)) == NULL) {
1433132727Skan					yyerror("unknown icmp-type %s", $1);
143450448Sobrien					YYERROR;
143590081Sobrien				}
143690081Sobrien				$$ = p->type + 1;
143790081Sobrien			}
143890081Sobrien		}
143990081Sobrien		;
144090081Sobrien
144190081Sobrienicmp6type	: STRING			{
144290081Sobrien			const struct icmptypeent *p;
144390081Sobrien			u_long ulval;
144490081Sobrien
144590081Sobrien			if (atoul($1, &ulval) == 0) {
144690081Sobrien				if (ulval > 255) {
144790081Sobrien					yyerror("illegal icmp6-type %d", ulval);
144890081Sobrien					YYERROR;
144990081Sobrien				}
145090081Sobrien				$$ = ulval + 1;
1451132727Skan			} else {
1452132727Skan				if ((p = geticmptypebyname($1, AF_INET6)) == NULL) {
1453132727Skan					yyerror("unknown ipv6-icmp-type %s", $1);
1454132727Skan					YYERROR;
1455132727Skan				}
1456132727Skan				$$ = p->type + 1;
1457132727Skan			}
145818334Speter		}
145918334Speter		;
146090081Sobrien
146152298Sobrientos		: /* empty */			{ $$ = 0; }
1462132727Skan		| TOS STRING			{
1463132727Skan			if (!strcmp($2, "lowdelay"))
1464117404Skan				$$ = IPTOS_LOWDELAY;
1465132727Skan			else if (!strcmp($2, "throughput"))
1466117404Skan				$$ = IPTOS_THROUGHPUT;
1467132727Skan			else if (!strcmp($2, "reliability"))
1468132727Skan				$$ = IPTOS_RELIABILITY;
146990081Sobrien			else if ($2[0] == '0' && $2[1] == 'x')
1470132727Skan				$$ = strtoul($2, NULL, 16);
1471132727Skan			else
147290081Sobrien				$$ = strtoul($2, NULL, 10);
1473132727Skan			if (!$$ || $$ > 255) {
1474132727Skan				yyerror("illegal tos value %s", $2);
147590081Sobrien				YYERROR;
1476132727Skan			}
1477132727Skan		}
147890081Sobrien		;
1479132727Skan
1480132727Skankeep		: /* empty */			{
148190081Sobrien			$$.action = 0;
1482132727Skan			$$.options = NULL;
148390081Sobrien		}
148490081Sobrien		| KEEP STATE state_opt_spec	{
1485132727Skan			$$.action = PF_STATE_NORMAL;
148650448Sobrien			$$.options = $3;
148750448Sobrien		}
148890081Sobrien		| MODULATE STATE state_opt_spec	{
148918334Speter			$$.action = PF_STATE_MODULATE;
1490132727Skan			$$.options = $3;
1491132727Skan		}
149218334Speter		;
1493132727Skan
1494132727Skanstate_opt_spec	: /* empty */			{ $$ = NULL; }
1495132727Skan		| '(' state_opt_list ')'	{ $$ = $2; }
1496132727Skan		;
1497132727Skan
1498117404Skanstate_opt_list	: state_opt_item		{ $$ = $1; }
1499132727Skan		| state_opt_list comma state_opt_item {
1500132727Skan			$1->tail->next = $3;
150190081Sobrien			$1->tail = $3;
1502132727Skan			$$ = $1;
1503132727Skan		}
1504132727Skan		;
1505132727Skan
1506132727Skanstate_opt_item	: MAXIMUM number		{
1507132727Skan			if ($2 <= 0) {
1508132727Skan				yyerror("illegal states max value %d", $2);
1509132727Skan				YYERROR;
1510132727Skan			}
1511132727Skan			$$ = calloc(1, sizeof(struct node_state_opt));
1512132727Skan			if ($$ == NULL)
151390081Sobrien				err(1, "state_opt_item: calloc");
1514132727Skan			$$->type = PF_STATE_OPT_MAX;
1515132727Skan			$$->data.max_states = $2;
1516132727Skan			$$->next = NULL;
1517132727Skan			$$->tail = $$;
1518117404Skan		}
1519132727Skan		| STRING number			{
1520132727Skan			int i;
1521132727Skan
1522132727Skan			for (i = 0; pf_timeouts[i].name &&
1523132727Skan			    strcmp(pf_timeouts[i].name, $1); ++i)
1524132727Skan				;	/* nothing */
1525132727Skan			if (!pf_timeouts[i].name) {
1526132727Skan				yyerror("illegal timeout name %s", $1);
1527132727Skan				YYERROR;
152890081Sobrien			}
152990081Sobrien			if (strchr(pf_timeouts[i].name, '.') == NULL) {
1530132727Skan				yyerror("illegal state timeout %s", $1);
1531132727Skan				YYERROR;
1532132727Skan			}
1533132727Skan			$$ = calloc(1, sizeof(struct node_state_opt));
153490081Sobrien			if ($$ == NULL)
1535132727Skan				err(1, "state_opt_item: calloc");
153690081Sobrien			$$->type = PF_STATE_OPT_TIMEOUT;
1537132727Skan			$$->data.timeout.number = pf_timeouts[i].timeout;
153818334Speter			$$->data.timeout.seconds = $2;
1539132727Skan			$$->next = NULL;
1540132727Skan			$$->tail = $$;
154118334Speter		}
1542132727Skan		;
1543132727Skan
1544132727Skanfragment	: /* empty */			{ $$ = 0; }
1545132727Skan		| FRAGMENT			{ $$ = 1; }
1546132727Skan
154790081Sobrienminttl		: /* empty */			{ $$ = 0; }
154818334Speter		| MINTTL number			{
1549132727Skan			if ($2 > 255) {
1550132727Skan				yyerror("illegal min-ttl value %d", $2);
1551132727Skan				YYERROR;
1552132727Skan			}
1553132727Skan			$$ = $2;
155418334Speter		}
1555132727Skan		;
155690081Sobrien
155718334Speternodf		: /* empty */			{ $$ = 0; }
1558132727Skan		| NODF				{ $$ = 1; }
1559132727Skan		;
156090081Sobrien
1561117404Skanmaxmss		: /* empty */			{ $$ = 0; }
1562132727Skan		| MAXMSS number			{ $$ = $2; }
1563132727Skan		;
1564117404Skan
1565132727Skanallowopts	: /* empty */			{ $$ = 0; }
1566132727Skan		| ALLOWOPTS			{ $$ = 1; }
1567132727Skan
1568117404Skanlabel		: /* empty */			{ $$ = NULL; }
1569132727Skan		| LABEL STRING			{
1570132727Skan			if (($$ = strdup($2)) == NULL) {
1571132727Skan				yyerror("rule label strdup() failed");
1572132727Skan				YYERROR;
1573117404Skan			}
1574132727Skan		}
1575132727Skan		;
1576132727Skanqname		: /* empty */			{ $$ = NULL; }
157790081Sobrien		| QUEUE STRING			{
1578132727Skan			if (($$ = strdup($2)) == NULL) {
1579132727Skan				yyerror("qname strdup() failed");
1580132727Skan				YYERROR;
1581132727Skan			}
1582132727Skan		}
1583132727Skan		;
158490081Sobrien
1585117404Skanno		: /* empty */			{ $$ = 0; }
1586132727Skan		| NO				{ $$ = 1; }
1587132727Skan		;
1588132727Skan
1589132727Skanrport		: STRING			{
1590132727Skan			char *p = strchr($1, ':');
1591117404Skan
1592132727Skan			if (p == NULL) {
1593132727Skan				if (($$.a = getservice($1)) == -1)
1594132727Skan					YYERROR;
1595132727Skan				$$.b = $$.t = 0;
1596132727Skan			} else if (!strcmp(p+1, "*")) {
1597132727Skan				*p = 0;
1598132727Skan				if (($$.a = getservice($1)) == -1)
1599132727Skan					YYERROR;
1600132727Skan				$$.b = 0;
1601132727Skan				$$.t = PF_RPORT_RANGE;
1602132727Skan			} else {
1603132727Skan				*p++ = 0;
1604132727Skan				if (($$.a = getservice($1)) == -1 ||
1605132727Skan				    ($$.b = getservice(p)) == -1)
1606132727Skan					YYERROR;
1607117404Skan				$$.t = PF_RPORT_RANGE;
1608132727Skan			}
1609132727Skan		}
161090081Sobrien		;
1611132727Skan
1612132727Skanredirspec	: host				{ $$ = $1; }
1613132727Skan		| '{' redir_host_list '}'	{ $$ = $2; }
1614132727Skan		;
1615132727Skan
1616132727Skanredir_host_list	: host				{ $$ = $1; }
1617132727Skan		| redir_host_list comma host	{
1618132727Skan			/* $3 may be a list, so use its tail pointer */
1619132727Skan			$1->tail->next = $3->tail;
1620132727Skan			$1->tail = $3->tail;
1621132727Skan			$$ = $1;
1622132727Skan		}
1623132727Skan		;
1624132727Skan
1625132727Skanredirpool	: /* empty */			{ $$ = NULL; }
162690081Sobrien		| ARROW redirspec		{
1627117404Skan			$$ = calloc(1, sizeof(struct redirection));
1628132727Skan			if ($$ == NULL)
1629132727Skan				err(1, "redirection: calloc");
1630132727Skan			$$->host = $2;
1631132727Skan			$$->rport.a = $$->rport.b = $$->rport.t = 0;
163218334Speter		}
1633132727Skan		| ARROW redirspec PORT rport	{
1634132727Skan			$$ = calloc(1, sizeof(struct redirection));
1635132727Skan			if ($$ == NULL)
1636132727Skan				err(1, "redirection: calloc");
1637132727Skan			$$->host = $2;
1638132727Skan			$$->rport = $4;
1639132727Skan		}
1640132727Skan		;
1641132727Skan
1642132727Skanhashkey		: /* empty */
1643132727Skan		{
1644132727Skan			$$ = malloc(sizeof(struct pf_poolhashkey));
1645132727Skan			if ($$ == NULL)
1646132727Skan				err(1, "pooltype: malloc");
164790081Sobrien			$$->key32[0] = arc4random();
1648132727Skan			$$->key32[1] = arc4random();
1649132727Skan			$$->key32[2] = arc4random();
165090081Sobrien			$$->key32[3] = arc4random();
1651132727Skan		}
1652132727Skan		| string
1653132727Skan		{
1654132727Skan			char buf[11] = "0x";
1655132727Skan			int i;
1656132727Skan
1657132727Skan			if (!strncmp((char *)$1, "0x", 2)) {
1658132727Skan				if (strlen((char *)$1) != 34) {
1659132727Skan					yyerror("hex key must be 128 bits "
1660132727Skan						"(32 hex digits) long");
1661132727Skan					YYERROR;
1662132727Skan				}
166390081Sobrien				$$ = calloc(1, sizeof(struct pf_poolhashkey));
1664132727Skan				if ($$ == NULL)
1665132727Skan					err(1, "hashkey: calloc");
1666132727Skan
1667132727Skan				/* convert to binary */
1668132727Skan				for (i = 0; i < 4; i++) {
1669132727Skan					strncpy((char *)(buf + 2),
1670132727Skan					    (char *)($1 + 2 + (i * 8)), 8);
1671132727Skan					if (atoul(buf,
1672132727Skan					    (u_long *)&$$->key32[i]) == -1) {
1673132727Skan						/* not hex */
1674132727Skan						free($$);
1675132727Skan						yyerror("invalid hex key");
1676132727Skan						YYERROR;
1677132727Skan					}
1678132727Skan				}
167990081Sobrien			} else {
1680132727Skan				MD5_CTX context;
1681132727Skan
1682132727Skan				$$ = calloc(1, sizeof(struct pf_poolhashkey));
1683132727Skan				if ($$ == NULL)
1684132727Skan					err(1, "hashkey: calloc");
1685132727Skan				MD5Init(&context);
1686132727Skan				MD5Update(&context, $1, strlen($1));
1687132727Skan				MD5Final((unsigned char *)$$, &context);
1688132727Skan			}
1689132727Skan		}
1690132727Skan		;
1691132727Skan
1692132727Skanpooltype	: /* empty */			{ $$.type = PF_POOL_NONE; }
1693132727Skan		| BITMASK			{ $$.type = PF_POOL_BITMASK; }
169490081Sobrien		| RANDOM			{ $$.type = PF_POOL_RANDOM; }
1695132727Skan		| SOURCEHASH hashkey
1696132727Skan		{
1697132727Skan			$$.type = PF_POOL_SRCHASH;
1698132727Skan			$$.key = $2;
1699132727Skan		}
1700132727Skan		| ROUNDROBIN			{ $$.type = PF_POOL_ROUNDROBIN; }
1701132727Skan		;
1702132727Skan
1703132727Skanstaticport	: /* empty */			{ $$ = 0; }
1704132727Skan		| STATICPORT			{ $$ = PF_POOL_STATICPORT; }
1705117404Skan		;
1706132727Skan
1707132727Skanredirection	: /* empty */			{ $$ = NULL; }
1708132727Skan		| ARROW host			{
1709132727Skan			$$ = calloc(1, sizeof(struct redirection));
1710132727Skan			if ($$ == NULL)
1711132727Skan				err(1, "redirection: calloc");
1712132727Skan			$$->host = $2;
1713132727Skan			$$->rport.a = $$->rport.b = $$->rport.t = 0;
1714132727Skan		}
1715132727Skan		| ARROW host PORT rport	{
1716132727Skan			$$ = calloc(1, sizeof(struct redirection));
1717132727Skan			if ($$ == NULL)
1718132727Skan				err(1, "redirection: calloc");
1719132727Skan			$$->host = $2;
1720132727Skan			$$->rport = $4;
1721132727Skan		}
1722132727Skan		;
1723132727Skan
1724132727Skannatrule		: no NAT interface af proto fromto redirpool pooltype staticport
1725132727Skan		{
1726132727Skan			struct pf_nat nat;
1727132727Skan
1728132727Skan			if (check_rulestate(PFCTL_STATE_NAT))
1729132727Skan				YYERROR;
1730132727Skan
1731132727Skan			memset(&nat, 0, sizeof(nat));
1732132727Skan
1733132727Skan			nat.no = $1;
1734132727Skan			nat.af = $4;
1735132727Skan
173690081Sobrien			if (!nat.af) {
1737132727Skan				if ($6.src.host && $6.src.host->af &&
1738117404Skan				    !$6.src.host->ifindex)
173990081Sobrien					nat.af = $6.src.host->af;
1740132727Skan				else if ($6.dst.host && $6.dst.host->af &&
1741132727Skan				    !$6.dst.host->ifindex)
1742132727Skan					nat.af = $6.dst.host->af;
1743132727Skan			}
1744132727Skan
1745132727Skan			if (nat.no) {
1746132727Skan				if ($7 != NULL) {
1747132727Skan					yyerror("'no nat' rule does not need "
1748117404Skan					    "'->'");
1749132727Skan					YYERROR;
1750132727Skan				}
1751132727Skan			} else {
1752132727Skan				if ($7 == NULL || $7->host == NULL) {
1753132727Skan					yyerror("'nat' rule requires '-> "
1754132727Skan					    "address'");
1755132727Skan					YYERROR;
1756132727Skan				}
1757117404Skan				if (!nat.af && ! $7->host->ifindex)
1758132727Skan					nat.af = $7->host->af;
175990081Sobrien
1760132727Skan				remove_invalid_hosts(&$7->host, &nat.af);
1761132727Skan				if ($7->host == NULL)
176290081Sobrien					YYERROR;
1763132727Skan				nat.proxy_port[0] = ntohs($7->rport.a);
1764132727Skan				nat.proxy_port[1] = ntohs($7->rport.b);
1765132727Skan				if (!nat.proxy_port[0] && !nat.proxy_port[1]) {
1766132727Skan					nat.proxy_port[0] =
176790081Sobrien					    PF_NAT_PROXY_PORT_LOW;
176896273Sobrien					nat.proxy_port[1] =
1769132727Skan					    PF_NAT_PROXY_PORT_HIGH;
1770132727Skan				} else if (!nat.proxy_port[1])
177190081Sobrien					nat.proxy_port[1] = nat.proxy_port[0];
1772132727Skan
1773132727Skan				if ($7->host->next) {
1774132727Skan					nat.rpool.opts = $8.type;
1775132727Skan					if (nat.rpool.opts == PF_POOL_NONE)
1776132727Skan						nat.rpool.opts =
177790081Sobrien						    PF_POOL_ROUNDROBIN;
1778132727Skan					if (nat.rpool.opts !=
1779132727Skan					    PF_POOL_ROUNDROBIN) {
1780117404Skan						yyerror("nat: only round-robin "
1781132727Skan						    "valid for multiple "
1782132727Skan						    "redirection addresses");
178390081Sobrien						YYERROR;
178490081Sobrien					}
1785132727Skan				} else {
1786132727Skan					if ((nat.af == AF_INET &&
178790081Sobrien					    unmask(&$7->host->addr.mask,
1788132727Skan					    nat.af) == 32) ||
1789132727Skan					    (nat.af == AF_INET6 &&
179090081Sobrien					    unmask(&$7->host->addr.mask,
1791132727Skan					    nat.af) == 128)) {
1792132727Skan						nat.rpool.opts = PF_POOL_NONE;
1793117404Skan					} else {
1794132727Skan						if ($8.type == PF_POOL_NONE)
1795132727Skan							nat.rpool.opts =
1796132727Skan							    PF_POOL_ROUNDROBIN;
1797132727Skan						else
1798132727Skan							nat.rpool.opts = $8.type;
1799117404Skan					}
1800132727Skan				}
1801132727Skan			}
1802132727Skan
1803132727Skan			if ($8.key != NULL) {
1804132727Skan				memcpy(&nat.rpool.key, $8.key,
1805132727Skan				    sizeof(struct pf_poolhashkey));
1806132727Skan			}
180790081Sobrien
1808132727Skan			expand_nat(&nat, $3, $5, $6.src.host, $6.src.port,
1809132727Skan			    $6.dst.host, $6.dst.port,
1810117404Skan			    $7 == NULL ? NULL : $7->host);
1811132727Skan			free($7);
1812132727Skan		}
1813132727Skan		;
1814132727Skan
1815132727Skanbinatrule	: no BINAT interface af proto FROM host TO ipspec redirection
1816132727Skan		{
1817132727Skan			struct pf_binat binat;
1818132727Skan
1819132727Skan			if (check_rulestate(PFCTL_STATE_NAT))
1820132727Skan				YYERROR;
1821132727Skan
1822132727Skan			memset(&binat, 0, sizeof(binat));
1823132727Skan
1824132727Skan			binat.no = $1;
1825132727Skan			if ($3 != NULL) {
1826132727Skan				memcpy(binat.ifname, $3->ifname,
1827132727Skan				    sizeof(binat.ifname));
1828132727Skan				free($3);
1829132727Skan			}
183090081Sobrien			binat.af = $4;
1831132727Skan			if ($5 != NULL) {
1832132727Skan				binat.proto = $5->proto;
1833132727Skan				free($5);
1834132727Skan			}
1835132727Skan			if ($7 != NULL && $9 != NULL && $7->af != $9->af) {
1836132727Skan				yyerror("binat ip versions must match");
1837132727Skan				YYERROR;
183818334Speter			}
1839132727Skan			if ($7 != NULL) {
184050448Sobrien				if ($7->next) {
184190081Sobrien					yyerror("multiple binat ip addresses");
184290081Sobrien					YYERROR;
184390081Sobrien				}
184490081Sobrien				if ($7->addr.addr_dyn != NULL) {
184590081Sobrien					if (!binat.af) {
184618334Speter						yyerror("address family (inet/"
184718334Speter						    "inet6) undefined");
184818334Speter						YYERROR;
184918334Speter					}
185018334Speter					$7->af = binat.af;
1851132727Skan				}
185218334Speter				if (binat.af && $7->af != binat.af) {
185318334Speter					yyerror("binat ip versions must match");
185418334Speter					YYERROR;
185518334Speter				}
1856132727Skan				binat.af = $7->af;
185718334Speter				memcpy(&binat.saddr.addr, &$7->addr.addr,
1858132727Skan				    sizeof(binat.saddr.addr));
1859132727Skan				memcpy(&binat.saddr.mask, &$7->addr.mask,
1860132727Skan				    sizeof(binat.saddr.mask));
1861132727Skan				free($7);
1862132727Skan			}
1863132727Skan			if ($9 != NULL) {
1864132727Skan				if ($9->next) {
1865132727Skan					yyerror("multiple binat ip addresses");
1866132727Skan					YYERROR;
186750448Sobrien				}
186890081Sobrien				if ($9->addr.addr_dyn != NULL) {
186918334Speter					if (!binat.af) {
187018334Speter						yyerror("address family (inet/"
187190081Sobrien						    "inet6) undefined");
187218334Speter						YYERROR;
187318334Speter					}
187418334Speter					$9->af = binat.af;
187518334Speter				}
187618334Speter				if (binat.af && $9->af != binat.af) {
187718334Speter					yyerror("binat ip versions must match");
187818334Speter					YYERROR;
187918334Speter				}
188018334Speter				binat.af = $9->af;
188118334Speter				memcpy(&binat.daddr.addr, &$9->addr.addr,
188250448Sobrien				    sizeof(binat.daddr.addr));
188318334Speter				memcpy(&binat.daddr.mask, &$9->addr.mask,
188418334Speter				    sizeof(binat.daddr.mask));
188518334Speter				binat.dnot  = $9->not;
188618334Speter				free($9);
188718334Speter			}
188818334Speter
188918334Speter			if (binat.no) {
189018334Speter				if ($10 != NULL) {
189118334Speter					yyerror("'no binat' rule does not need"
189218334Speter					    " '->'");
189318334Speter					YYERROR;
189450448Sobrien				}
189590081Sobrien			} else {
1896117404Skan				if ($10 == NULL || $10->host == NULL) {
189790081Sobrien					yyerror("'binat' rule requires"
189890081Sobrien					    " '-> address'");
189918334Speter					YYERROR;
1900117404Skan				}
1901117404Skan
1902117404Skan				remove_invalid_hosts(&$10->host, &binat.af);
1903117404Skan				if ($10->host == NULL)
1904117404Skan					YYERROR;
1905117404Skan				if ($10->host->next != NULL) {
1906132727Skan					yyerror("binat rule must redirect to a single "
1907132727Skan					    "address");
1908132727Skan					YYERROR;
1909132727Skan				}
1910132727Skan				memcpy(&binat.raddr.addr, &$10->host->addr.addr,
1911117404Skan				    sizeof(binat.raddr.addr));
1912132727Skan				memcpy(&binat.raddr.mask, &$10->host->addr.mask,
1913132727Skan				    sizeof(binat.raddr.mask));
1914117404Skan				if (!PF_AZERO(&binat.saddr.mask, binat.af) &&
191550448Sobrien				    !PF_AEQ(&binat.saddr.mask,
191690081Sobrien				    &binat.raddr.mask, binat.af)) {
1917117404Skan					yyerror("'binat' source mask and "
191890081Sobrien					    "redirect mask must be the same");
191990081Sobrien					YYERROR;
192018334Speter				}
192150448Sobrien				free($10);
192290081Sobrien			}
1923117404Skan
192490081Sobrien			pfctl_add_binat(pf, &binat);
192590081Sobrien		}
192618334Speter		;
192790081Sobrien
192890081Sobrienrdrrule		: no RDR interface af proto FROM ipspec TO ipspec dport redirpool pooltype
1929117404Skan		{
193090081Sobrien			struct pf_rdr rdr;
193190081Sobrien
193290081Sobrien			if (check_rulestate(PFCTL_STATE_NAT))
1933132727Skan				YYERROR;
1934132727Skan
1935132727Skan			memset(&rdr, 0, sizeof(rdr));
193690081Sobrien
193790081Sobrien			rdr.no = $1;
193818334Speter			rdr.af = $4;
193950448Sobrien			if ($7 != NULL) {
194090081Sobrien				memcpy(&rdr.saddr.addr, &$7->addr.addr,
1941117404Skan				    sizeof(rdr.saddr.addr));
194290081Sobrien				memcpy(&rdr.saddr.mask, &$7->addr.mask,
194390081Sobrien				    sizeof(rdr.saddr.mask));
194418334Speter				rdr.snot  = $7->not;
1945132727Skan				if (!rdr.af && !$7->ifindex)
1946132727Skan					rdr.af = $7->af;
1947132727Skan			}
194890081Sobrien			if ($9 != NULL) {
194990081Sobrien				memcpy(&rdr.daddr.addr, &$9->addr.addr,
195018334Speter				    sizeof(rdr.daddr.addr));
195150448Sobrien				memcpy(&rdr.daddr.mask, &$9->addr.mask,
195290081Sobrien				    sizeof(rdr.daddr.mask));
1953117404Skan				rdr.dnot  = $9->not;
195490081Sobrien				if (!rdr.af && !$9->ifindex)
195590081Sobrien					rdr.af = $9->af;
195618334Speter			}
1957132727Skan
1958132727Skan			rdr.dport  = $10.a;
195990081Sobrien			rdr.dport2 = $10.b;
196090081Sobrien			rdr.opts  |= $10.t;
196118334Speter
196250448Sobrien			if ($12.type == PF_POOL_NONE)
196390081Sobrien				rdr.rpool.opts = PF_POOL_RANDOM;
1964117404Skan			else
196590081Sobrien				rdr.rpool.opts = $12.type;
196690081Sobrien
196718334Speter			if (rdr.no) {
1968132727Skan				if ($11 != NULL) {
1969132727Skan					yyerror("'no rdr' rule does not need '->'");
197090081Sobrien					YYERROR;
197190081Sobrien				}
197218334Speter			} else {
197350448Sobrien				if ($11 == NULL || $11->host == NULL) {
197490081Sobrien					yyerror("'rdr' rule requires '-> "
1975117404Skan					    "address'");
197690081Sobrien					YYERROR;
197790081Sobrien				}
197818334Speter				if (!rdr.af && !$11->host->ifindex)
1979132727Skan					rdr.af = $11->host->af;
1980132727Skan
1981132727Skan				remove_invalid_hosts(&$11->host, &rdr.af);
198290081Sobrien				if ($11->host == NULL)
198390081Sobrien					YYERROR;
198418334Speter				rdr.rport  = $11->rport.a;
198550448Sobrien				rdr.opts  |= $11->rport.t;
198690081Sobrien
1987117404Skan				if ($11->host->next) {
198890081Sobrien					rdr.rpool.opts = $12.type;
198990081Sobrien					if (rdr.rpool.opts == PF_POOL_NONE)
199018334Speter						rdr.rpool.opts =
1991132727Skan						    PF_POOL_ROUNDROBIN;
1992132727Skan					if (rdr.rpool.opts !=
1993132727Skan					    PF_POOL_ROUNDROBIN) {
199490081Sobrien						yyerror("rdr: only round-robin "
199590081Sobrien						    "valid for multiple "
199618334Speter						    "redirection addresses");
199750448Sobrien						YYERROR;
199890081Sobrien					}
1999117404Skan				} else {
200090081Sobrien					if ((rdr.af == AF_INET &&
200190081Sobrien					    unmask(&$11->host->addr.mask,
200218334Speter					    rdr.af) == 32) ||
200350448Sobrien					    (rdr.af == AF_INET6 &&
200490081Sobrien					    unmask(&$11->host->addr.mask,
2005117404Skan					    rdr.af) == 128)) {
200690081Sobrien						rdr.rpool.opts = PF_POOL_NONE;
200790081Sobrien					} else {
200818334Speter						if ($12.type == PF_POOL_NONE)
2009132727Skan							rdr.rpool.opts =
2010132727Skan							    PF_POOL_ROUNDROBIN;
2011132727Skan						else
2012132727Skan							rdr.rpool.opts =
201390081Sobrien							    $12.type;
201490081Sobrien					}
201518334Speter				}
201650448Sobrien			}
201790081Sobrien
2018117404Skan			if ($12.key != NULL) {
201990081Sobrien				memcpy(&rdr.rpool.key, $12.key,
202090081Sobrien				    sizeof(struct pf_poolhashkey));
202150448Sobrien			}
2022132727Skan
2023132727Skan			expand_rdr(&rdr, $3, $5, $7, $9,
202450448Sobrien			    $11 == NULL ? NULL : $11->host);
202550448Sobrien		}
202650448Sobrien		;
2027132727Skan
2028117404Skandport		: /* empty */			{
202990081Sobrien			$$.a = $$.b = $$.t = 0;
2030117404Skan		}
203190081Sobrien		| PORT STRING			{
203290081Sobrien			char *p = strchr($2, ':');
203350448Sobrien
2034132727Skan			if (p == NULL) {
2035132727Skan				if (($$.a = getservice($2)) == -1)
2036132727Skan					YYERROR;
2037132727Skan				$$.b = $$.t = 0;
2038132727Skan			} else {
2039132727Skan				*p++ = 0;
2040132727Skan				if (($$.a = getservice($2)) == -1 ||
2041132727Skan				    ($$.b = getservice(p)) == -1)
2042132727Skan					YYERROR;
2043132727Skan				$$.t = PF_DPORT_RANGE;
2044132727Skan			}
2045132727Skan		}
2046132727Skan		;
204790081Sobrien
204890081Sobrienroute_host	: STRING			{
204990081Sobrien			$$ = calloc(1, sizeof(struct node_host));
2050117404Skan			if ($$ == NULL)
205190081Sobrien				err(1, "route_host: calloc");
205290081Sobrien			if (($$->ifname = strdup($1)) == NULL) {
205390081Sobrien				yyerror("routeto: strdup");
2054132727Skan				YYERROR;
2055132727Skan			}
2056132727Skan			if (ifa_exists($$->ifname) == NULL) {
2057132727Skan				yyerror("routeto: unknown interface %s",
2058132727Skan				    $$->ifname);
2059132727Skan				YYERROR;
2060117404Skan			}
2061132727Skan			$$->next = NULL;
2062132727Skan			$$->tail = $$;
2063132727Skan		}
2064117404Skan		| '(' STRING host ')'		{
2065117404Skan			$$ = $3;
2066117404Skan			if (($$->ifname = strdup($2)) == NULL) {
2067132727Skan				yyerror("routeto: strdup");
2068117404Skan				YYERROR;
2069132727Skan			}
2070117404Skan			if (ifa_exists($$->ifname) == NULL) {
2071117404Skan				yyerror("routeto: unknown interface %s",
2072117404Skan				    $$->ifname);
2073117404Skan				YYERROR;
2074117404Skan			}
2075117404Skan		}
2076117404Skan		;
2077117404Skan
2078132727Skanroute_host_list	: route_host				{ $$ = $1; }
2079132727Skan		| route_host_list comma route_host	{
2080132727Skan			if ($1->af == 0)
2081132727Skan				$1->af = $3->af;
2082132727Skan			if ($1->af != $3->af) {
2083132727Skan				yyerror("all pool addresses must be in the "
2084132727Skan				    "same address family");
2085132727Skan				YYERROR;
2086132727Skan			}
2087117404Skan			/* $3 may be a list, so use its tail pointer */
2088117404Skan			$1->tail->next = $3->tail;
2089117404Skan			$1->tail = $3->tail;
2090132727Skan			$$ = $1;
2091117404Skan		}
2092117404Skan		;
2093132727Skan
2094117404Skanroutespec	: route_host			{ $$ = $1; }
2095117404Skan		| '{' route_host_list '}'	{ $$ = $2; }
2096117404Skan		;
2097117404Skan
2098132727Skan
2099117404Skanroute		: /* empty */			{
2100117404Skan			$$.host = NULL;
2101117404Skan			$$.rt = 0;
2102117404Skan			$$.pool_opts = 0;
2103132727Skan		}
2104117404Skan		| FASTROUTE {
2105117404Skan			$$.host = NULL;
2106117404Skan			$$.rt = PF_FASTROUTE;
2107117404Skan			$$.pool_opts = 0;
2108132727Skan		}
2109117404Skan		| ROUTETO routespec pooltype {
2110117404Skan			$$.host = $2;
2111117404Skan			$$.rt = PF_ROUTETO;
2112117404Skan			if ($3.key != NULL)
2113117404Skan				$$.key = $3.key;
2114117404Skan		}
2115117404Skan		| REPLYTO routespec pooltype {
2116117404Skan			$$.host = $2;
2117117404Skan			$$.rt = PF_REPLYTO;
2118117404Skan			if ($3.key != NULL)
211950448Sobrien				$$.key = $3.key;
212018334Speter		}
2121132727Skan		| DUPTO routespec pooltype {
212218334Speter			$$.host = $2;
212318334Speter			$$.rt = PF_DUPTO;
212418334Speter			if ($3.key != NULL)
212518334Speter				$$.key = $3.key;
212690081Sobrien		}
212718334Speter		;
212818334Speter
212918334Spetertimeout_spec	: STRING number
2130132727Skan		{
2131132727Skan			if (pf->opts & PF_OPT_VERBOSE)
2132132727Skan				printf("set timeout %s %us\n", $1, $2);
213318334Speter			if (check_rulestate(PFCTL_STATE_OPTION))
2134132727Skan				YYERROR;
2135132727Skan			if (pfctl_set_timeout(pf, $1, $2) != 0) {
213690081Sobrien				yyerror("unknown timeout %s", $1);
2137132727Skan				YYERROR;
2138132727Skan			}
2139132727Skan		}
2140132727Skan		;
2141132727Skan
214218334Spetertimeout_list	: timeout_list comma timeout_spec
2143132727Skan		| timeout_spec
2144132727Skan		;
2145132727Skan
2146132727Skanlimit_spec	: STRING number
2147132727Skan		{
2148132727Skan			if (pf->opts & PF_OPT_VERBOSE)
214918334Speter				printf("set limit %s %u\n", $1, $2);
2150132727Skan			if (check_rulestate(PFCTL_STATE_OPTION))
2151132727Skan				YYERROR;
215218334Speter			if (pfctl_set_limit(pf, $1, $2) != 0) {
2153132727Skan				yyerror("unable to set limit %s %u", $1, $2);
2154132727Skan				YYERROR;
215518334Speter			}
2156132727Skan		}
2157132727Skan
215818334Speterlimit_list	: limit_list comma limit_spec
2159132727Skan		| limit_spec
2160132727Skan		;
216118334Speter
2162132727Skancomma		: ','
2163132727Skan		| /* empty */
216418334Speter		;
2165132727Skan
2166132727Skan%%
216718334Speter
2168132727Skanint
2169132727Skanyyerror(char *fmt, ...)
2170132727Skan{
2171132727Skan	va_list ap;
2172132727Skan	extern char *infile;
217318334Speter	errors = 1;
2174132727Skan
2175132727Skan	va_start(ap, fmt);
217618334Speter	fprintf(stderr, "%s:%d: ", infile, yylval.lineno);
2177132727Skan	vfprintf(stderr, fmt, ap);
2178132727Skan	fprintf(stderr, "\n");
217918334Speter	va_end(ap);
2180132727Skan	return (0);
2181132727Skan}
218218334Speter
2183132727Skanint
2184132727Skanrule_consistent(struct pf_rule *r)
218518334Speter{
2186132727Skan	int problems = 0;
2187132727Skan
218818334Speter	if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
2189132727Skan	    (r->src.port_op || r->dst.port_op)) {
2190132727Skan		yyerror("port only applies to tcp/udp");
219118334Speter		problems++;
2192132727Skan	}
2193132727Skan	if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 &&
219418334Speter	    (r->type || r->code)) {
2195117404Skan		yyerror("icmp-type/code only applies to icmp");
2196132727Skan		problems++;
2197132727Skan	}
2198132727Skan	if (!r->af && (r->type || r->code)) {
2199117404Skan		yyerror("must indicate address family with icmp-type/code");
2200132727Skan		problems++;
2201132727Skan	}
220218334Speter	if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) ||
2203132727Skan	    (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) {
2204132727Skan		yyerror("icmp version does not match address family");
220550448Sobrien		problems++;
2206132727Skan	}
2207132727Skan	if (r->keep_state == PF_STATE_MODULATE && r->proto &&
2208117404Skan	    r->proto != IPPROTO_TCP) {
2209132727Skan		yyerror("modulate state can only be applied to TCP rules");
2210132727Skan		problems++;
221190081Sobrien	}
2212132727Skan	if (r->allow_opts && r->action != PF_PASS) {
2213132727Skan		yyerror("allow-opts can only be specified for pass rules");
2214132727Skan		problems++;
221590081Sobrien	}
2216132727Skan	if (!r->af && (r->src.addr.addr_dyn != NULL ||
221750448Sobrien	    r->dst.addr.addr_dyn != NULL)) {
2218132727Skan		yyerror("dynamic addresses require address family (inet/inet6)");
2219132727Skan		problems++;
2220132727Skan	}
222150448Sobrien	if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op ||
2222132727Skan	    r->dst.port_op || r->flagset || r->type || r->code)) {
2223132727Skan		yyerror("fragments can be filtered only on IP header fields");
222490081Sobrien		problems++;
2225132727Skan	}
2226132727Skan	if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) {
2227132727Skan		yyerror("return-rst can only be applied to TCP rules");
222890081Sobrien		problems++;
2229132727Skan	}
2230132727Skan	if (r->action == PF_DROP && r->keep_state) {
2231117404Skan		yyerror("keep state on block rules doesn't make sense");
2232132727Skan		problems++;
2233132727Skan	}
2234132727Skan	return (-problems);
2235117404Skan}
2236132727Skan
2237132727Skanint
2238117404Skannat_consistent(struct pf_nat *r)
2239132727Skan{
2240132727Skan	int problems = 0;
2241132727Skan	struct pf_pooladdr *pa;
2242132727Skan
2243117404Skan	if (!r->af) {
2244132727Skan		TAILQ_FOREACH(pa, &r->rpool.list, entries) {
2245132727Skan			if (pa->addr.addr_dyn != NULL) {
2246132727Skan				yyerror("dynamic addresses require "
2247132727Skan				    "address family (inet/inet6)");
2248117404Skan				problems++;
2249132727Skan				break;
2250132727Skan			}
2251117404Skan		}
2252132727Skan	}
2253132727Skan	return (-problems);
2254117404Skan}
2255132727Skan
2256132727Skanint
2257132727Skanrdr_consistent(struct pf_rdr *r)
2258132727Skan{
2259132727Skan	int problems = 0;
2260117404Skan	struct pf_pooladdr *pa;
2261132727Skan
2262132727Skan	if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
2263117404Skan	    (r->dport || r->dport2 || r->rport)) {
226450448Sobrien		yyerror("port only applies to tcp/udp");
226518334Speter		problems++;
226618334Speter	}
2267117404Skan	if (!r->af) {
226890081Sobrien		if (r->saddr.addr_dyn != NULL || r->daddr.addr_dyn != NULL) {
2269132727Skan			yyerror("dynamic addresses require address family "
227090081Sobrien			    "(inet/inet6)");
2271117404Skan			problems++;
2272132727Skan		} else {
2273132727Skan			TAILQ_FOREACH(pa, &r->rpool.list, entries) {
227418334Speter				if (pa->addr.addr_dyn != NULL) {
2275132727Skan					yyerror("dynamic addresses require "
2276132727Skan					    "address family (inet/inet6)");
2277117404Skan					problems++;
2278132727Skan					break;
2279132727Skan				}
228018334Speter			}
2281132727Skan		}
2282117404Skan	}
2283117404Skan	return (-problems);
2284132727Skan}
2285132727Skan
228650448Sobrienstruct keywords {
2287132727Skan	const char	*k_name;
2288117404Skan	int	 k_val;
2289132727Skan};
2290132727Skan
229118334Speter/* macro gore, but you should've seen the prior indentation nightmare... */
2292132727Skan
2293117404Skan#define FREE_LIST(T,r) \
2294117404Skan	do { \
2295132727Skan		T *p, *n = r; \
2296117404Skan		while (n != NULL) { \
2297132727Skan			p = n; \
2298117404Skan			n = n->next; \
229918334Speter			free(p); \
2300132727Skan		} \
2301117404Skan	} while (0)
2302132727Skan
2303132727Skan#define LOOP_THROUGH(T,n,r,C) \
2304117404Skan	do { \
2305132727Skan		T *n; \
2306132727Skan		if (r == NULL) { \
2307132727Skan			r = calloc(1, sizeof(T)); \
2308132727Skan			if (r == NULL) \
230950448Sobrien				err(1, "LOOP: calloc"); \
231052298Sobrien			r->next = NULL; \
2311132727Skan		} \
231252298Sobrien		n = r; \
231352298Sobrien		while (n != NULL) { \
231490081Sobrien			do { \
231552298Sobrien				C; \
231652298Sobrien			} while (0); \
231718334Speter			n = n->next; \
231818334Speter		} \
231990081Sobrien	} while (0)
232090081Sobrien
232190081Sobrienvoid
2322132727Skanexpand_label_if(const char *name, char *label, const char *ifname)
232390081Sobrien{
232490081Sobrien	char tmp[PF_RULE_LABEL_SIZE];
2325132727Skan	char *p;
2326132727Skan
2327132727Skan	while ((p = strstr(label, name)) != NULL) {
232818334Speter		tmp[0] = 0;
2329117404Skan		strlcat(tmp, label, p-label+1);
2330132727Skan		if (!*ifname)
2331132727Skan			strlcat(tmp, "any", PF_RULE_LABEL_SIZE);
233218334Speter		else
233390081Sobrien			strlcat(tmp, ifname, PF_RULE_LABEL_SIZE);
2334132727Skan		strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE);
233518334Speter		strncpy(label, tmp, PF_RULE_LABEL_SIZE);
233690081Sobrien	}
233790081Sobrien}
233852298Sobrien
233990081Sobrienvoid
234052298Sobrienexpand_label_addr(const char *name, char *label, sa_family_t af,
234190081Sobrien    struct node_host *host)
234250448Sobrien{
2343132727Skan	char tmp[PF_RULE_LABEL_SIZE];
2344132727Skan	char *p;
2345132727Skan
2346132727Skan	while ((p = strstr(label, name)) != NULL) {
2347132727Skan		tmp[0] = 0;
2348132727Skan
2349132727Skan		strlcat(tmp, label, p-label+1);
2350132727Skan
2351132727Skan		if (host->not)
2352132727Skan			strlcat(tmp, "! ", PF_RULE_LABEL_SIZE);
2353132727Skan		if (host->addr.addr_dyn != NULL) {
235452298Sobrien			strlcat(tmp, "(", PF_RULE_LABEL_SIZE);
2355132727Skan			strlcat(tmp, host->addr.addr.pfa.ifname,
2356132727Skan			    PF_RULE_LABEL_SIZE);
235718334Speter			strlcat(tmp, ")", PF_RULE_LABEL_SIZE);
235890081Sobrien		} else if (!af || (PF_AZERO(&host->addr.addr, af) &&
235990081Sobrien		    PF_AZERO(&host->addr.mask, af)))
236018334Speter			strlcat(tmp, "any", PF_RULE_LABEL_SIZE);
236190081Sobrien		else {
2362132727Skan			char a[48];
2363132727Skan			int bits;
236490081Sobrien
236518334Speter			if (inet_ntop(af, &host->addr.addr, a,
236618334Speter			    sizeof(a)) == NULL)
236718334Speter				strlcat(a, "?", sizeof(a));
236850448Sobrien			strlcat(tmp, a, PF_RULE_LABEL_SIZE);
236918334Speter			bits = unmask(&host->addr.mask, af);
237096273Sobrien			a[0] = 0;
237118334Speter			if ((af == AF_INET && bits < 32) ||
237252298Sobrien			    (af == AF_INET6 && bits < 128))
237352298Sobrien				snprintf(a, sizeof(a), "/%d", bits);
237418334Speter			strlcat(tmp, a, PF_RULE_LABEL_SIZE);
237552298Sobrien		}
237652298Sobrien		strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE);
237752298Sobrien		strncpy(label, tmp, PF_RULE_LABEL_SIZE);
237890081Sobrien	}
2379132727Skan}
238090081Sobrien
238190081Sobrienvoid
238218334Speterexpand_label_port(const char *name, char *label, struct node_port *port)
238396273Sobrien{
238490081Sobrien	char tmp[PF_RULE_LABEL_SIZE];
238550448Sobrien	char *p;
238696273Sobrien	char a1[6], a2[6], op[13];
238790081Sobrien
238890081Sobrien	while ((p = strstr(label, name)) != NULL) {
238990081Sobrien		tmp[0] = 0;
239096273Sobrien
239196273Sobrien		strlcat(tmp, label, p-label+1);
239296273Sobrien
239318334Speter		snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0]));
239418334Speter		snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1]));
239518334Speter		if (!port->op)
239618334Speter			op[0] = 0;
239718334Speter		else if (port->op == PF_OP_IRG)
239890081Sobrien			snprintf(op, sizeof(op), "%s><%s", a1, a2);
239990081Sobrien		else if (port->op == PF_OP_XRG)
240018334Speter			snprintf(op, sizeof(op), "%s<>%s", a1, a2);
240118334Speter		else if (port->op == PF_OP_EQ)
240218334Speter			snprintf(op, sizeof(op), "%s", a1);
240318334Speter		else if (port->op == PF_OP_NE)
240418334Speter			snprintf(op, sizeof(op), "!=%s", a1);
240518334Speter		else if (port->op == PF_OP_LT)
240618334Speter			snprintf(op, sizeof(op), "<%s", a1);
240718334Speter		else if (port->op == PF_OP_LE)
240818334Speter			snprintf(op, sizeof(op), "<=%s", a1);
240918334Speter		else if (port->op == PF_OP_GT)
241090081Sobrien			snprintf(op, sizeof(op), ">%s", a1);
241118334Speter		else if (port->op == PF_OP_GE)
241218334Speter			snprintf(op, sizeof(op), ">=%s", a1);
241318334Speter		strlcat(tmp, op, PF_RULE_LABEL_SIZE);
241418334Speter		strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE);
241590081Sobrien		strncpy(label, tmp, PF_RULE_LABEL_SIZE);
241690081Sobrien	}
241790081Sobrien}
241818334Speter
241918334Spetervoid
242018334Speterexpand_label_proto(const char *name, char *label, u_int8_t proto)
242118334Speter{
242290081Sobrien	char tmp[PF_RULE_LABEL_SIZE];
242318334Speter	char *p;
242418334Speter	struct protoent *pe;
242518334Speter
242618334Speter	while ((p = strstr(label, name)) != NULL) {
242790081Sobrien		tmp[0] = 0;
242890081Sobrien		strlcat(tmp, label, p-label+1);
242990081Sobrien		pe = getprotobynumber(proto);
243018334Speter		if (pe != NULL)
243118334Speter		    strlcat(tmp, pe->p_name, PF_RULE_LABEL_SIZE);
243218334Speter		else
243350448Sobrien		    snprintf(tmp+strlen(tmp), PF_RULE_LABEL_SIZE-strlen(tmp),
2434132727Skan			"%u", proto);
2435132727Skan		strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE);
2436132727Skan		strncpy(label, tmp, PF_RULE_LABEL_SIZE);
2437132727Skan	}
2438132727Skan}
2439132727Skan
2440132727Skanvoid
2441132727Skanexpand_label_nr(const char *name, char *label)
2442132727Skan{
2443132727Skan	char tmp[PF_RULE_LABEL_SIZE];
244450448Sobrien	char *p;
2445132727Skan
2446132727Skan	while ((p = strstr(label, name)) != NULL) {
2447132727Skan		tmp[0] = 0;
244850448Sobrien		strlcat(tmp, label, p-label+1);
244950448Sobrien		snprintf(tmp+strlen(tmp), PF_RULE_LABEL_SIZE-strlen(tmp),
245090081Sobrien		    "%u", pf->rule_nr);
245152298Sobrien		strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE);
245252298Sobrien		strncpy(label, tmp, PF_RULE_LABEL_SIZE);
2453132727Skan	}
2454132727Skan}
2455132727Skan
245650448Sobrienvoid
245718334Speterexpand_label(char *label, const char *ifname, sa_family_t af,
245850448Sobrien    struct node_host *src_host, struct node_port *src_port,
245918334Speter    struct node_host *dst_host, struct node_port *dst_port,
246018334Speter    u_int8_t proto)
2461117404Skan{
246290081Sobrien	expand_label_if("$if", label, ifname);
246318334Speter	expand_label_addr("$srcaddr", label, af, src_host);
246418334Speter	expand_label_addr("$dstaddr", label, af, dst_host);
246518334Speter	expand_label_port("$srcport", label, src_port);
246618334Speter	expand_label_port("$dstport", label, dst_port);
246750448Sobrien	expand_label_proto("$proto", label, proto);
246890081Sobrien	expand_label_nr("$nr", label);
246918334Speter}
247018334Speter
247118334Speterint
247290081Sobrienexpand_altq(struct pf_altq *a, struct node_if *interfaces,
247350448Sobrien    struct node_queue *nqueues)
247450448Sobrien{
247550448Sobrien	struct	pf_altq pa, pb;
247618334Speter	char	qname[PF_QNAME_SIZE];
247718334Speter	struct	node_queue *n;
247818334Speter	int	errors = 0;
247918334Speter
248018334Speter	LOOP_THROUGH(struct node_if, interface, interfaces,
248118334Speter		memcpy(&pa, a, sizeof(struct pf_altq));
248218334Speter		strlcpy(pa.ifname, interface->ifname, IFNAMSIZ);
248318334Speter
248418334Speter		if (interface->not) {
248590081Sobrien			yyerror("altq on ! <interface> is not supported");
248618334Speter			errors++;
248790081Sobrien		} else {
248890081Sobrien			if (eval_pfaltq(pf, &pa))
248990081Sobrien				errors++;
249090081Sobrien			else
249190081Sobrien				if (pfctl_add_altq(pf, &pa))
249290081Sobrien					errors++;
249390081Sobrien
249490081Sobrien			if (pf->opts & PF_OPT_VERBOSE) {
249590081Sobrien				print_altq(&pf->paltq->altq, 0);
249618334Speter				if (nqueues && nqueues->tail) {
2497132727Skan					printf("queue { ");
2498132727Skan					LOOP_THROUGH(struct node_queue, queue,
2499132727Skan					    nqueues,
2500132727Skan						printf("%s ",
2501132727Skan						    queue->queue);
250252298Sobrien					);
250352298Sobrien					printf("}");
2504132727Skan				}
250590081Sobrien				printf("\n");
2506117404Skan			}
2507132727Skan
2508132727Skan			/* now create a root queue */
2509132727Skan			memset(&pb, 0, sizeof(struct pf_altq));
2510132727Skan			strlcpy(qname, "root_", sizeof(qname));
2511132727Skan			strlcat(qname, interface->ifname, sizeof(qname));
251250448Sobrien			strlcpy(pb.qname, qname, PF_QNAME_SIZE);
2513132727Skan			strlcpy(pb.ifname, interface->ifname, IFNAMSIZ);
2514132727Skan			pb.qlimit = pa.qlimit;
2515132727Skan			pb.scheduler = pa.scheduler;
2516132727Skan			pb.pq_u.cbq_opts.flags = pa.pq_u.cbq_opts.flags;
251718334Speter			if (eval_pfqueue(pf, &pb, pa.ifbandwidth, 0))
251852298Sobrien				errors++;
2519132727Skan			else
2520132727Skan				if (pfctl_add_altq(pf, &pb))
2521132727Skan					errors++;
2522132727Skan
2523132727Skan			LOOP_THROUGH(struct node_queue, queue, nqueues,
2524132727Skan				n = calloc(1, sizeof(struct node_queue));
252552298Sobrien				if (n == NULL)
252690081Sobrien					err(1, "expand_altq: calloc");
2527117404Skan				strlcpy(n->parent, qname, PF_QNAME_SIZE);
252890081Sobrien				strlcpy(n->queue, queue->queue, PF_QNAME_SIZE);
252990081Sobrien				strlcpy(n->ifname, interface->ifname, IFNAMSIZ);
2530117404Skan				n->next = NULL;
253190081Sobrien				n->tail = n;
253218334Speter				if (queues == NULL)
253318334Speter					queues = n;
253418334Speter				else {
253518334Speter					queues->tail->next = n;
253690081Sobrien					queues->tail = n;
253790081Sobrien				}
253890081Sobrien			);
253952298Sobrien		}
254018334Speter	);
2541132727Skan	FREE_LIST(struct node_if, interfaces);
254290081Sobrien	FREE_LIST(struct node_queue, nqueues);
254390081Sobrien
254418334Speter	return(errors);
254518334Speter}
2546132727Skan
254750448Sobrienint
254890081Sobrienexpand_queue(struct pf_altq *a, struct node_queue *nqueues,
254918334Speter    struct node_queue_bw bwspec)
255050448Sobrien{
255150448Sobrien	struct	node_queue *n;
255250448Sobrien	u_int8_t	added = 0;
255390081Sobrien	u_int8_t	found = 0;
255450448Sobrien
255518334Speter	LOOP_THROUGH(struct node_queue, tqueue, queues,
255690081Sobrien		if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE)) {
255790081Sobrien			/* found ourselve in queues */
2558132727Skan			found++;
2559132727Skan			LOOP_THROUGH(struct node_queue, queue, nqueues,
256018334Speter				n = calloc(1, sizeof(struct node_queue));
2561132727Skan				if (n == NULL)
256218334Speter					err(1, "expand_queue: calloc");
2563132727Skan				strlcpy(n->parent, a->qname, PF_QNAME_SIZE);
256418334Speter				strlcpy(n->queue, queue->queue, PF_QNAME_SIZE);
256590081Sobrien				strlcpy(n->ifname, tqueue->ifname, IFNAMSIZ);
256690081Sobrien				n->next = NULL;
256790081Sobrien				n->tail = n;
256818334Speter				if (queues == NULL)
256918334Speter					queues = n;
257018334Speter				else {
2571117404Skan					queues->tail->next = n;
257218334Speter					queues->tail = n;
257318334Speter				}
257418334Speter			);
257590081Sobrien			strlcpy(a->ifname, tqueue->ifname, IFNAMSIZ);
257690081Sobrien			strlcpy(a->parent, tqueue->parent, PF_QNAME_SIZE);
257790081Sobrien
2578132727Skan			if (!eval_pfqueue(pf, a, bwspec.bw_absolute,
2579132727Skan			    bwspec.bw_percent))
2580132727Skan				if(!pfctl_add_altq(pf, a))
258118334Speter					added++;
258290081Sobrien
2583132727Skan			if ((pf->opts & PF_OPT_VERBOSE) && found == 1) {
258418334Speter				print_altq(&pf->paltq->altq, 0);
2585132727Skan				if (nqueues && nqueues->tail) {
258618334Speter					printf("{ ");
258718334Speter					LOOP_THROUGH(struct node_queue, queue,
258818334Speter					    nqueues,
258918334Speter						printf("%s ", queue->queue);
259018334Speter					);
259190081Sobrien					printf("}");
259218334Speter				}
259318334Speter				printf("\n");
259418334Speter			}
259590081Sobrien		}
259618334Speter	);
259718334Speter
259890081Sobrien	FREE_LIST(struct node_queue, nqueues);
259918334Speter
260018334Speter	if (!added) {
260190081Sobrien		yyerror("queue has no parent");
260290081Sobrien		return (1);
260318334Speter	} else
260418334Speter		return (0);
260518334Speter}
260652298Sobrien
260752298Sobrienvoid
2608132727Skanexpand_rule(struct pf_rule *r,
260950448Sobrien    struct node_if *interfaces, struct node_host *rt_pool_hosts,
261090081Sobrien    struct node_proto *protos, struct node_host *src_hosts,
261150448Sobrien    struct node_port *src_ports, struct node_host *dst_hosts,
261290081Sobrien    struct node_port *dst_ports, struct node_uid *uids,
261318334Speter    struct node_gid *gids, struct node_icmp *icmp_types)
261490081Sobrien{
261550448Sobrien	sa_family_t	af = r->af;
261618334Speter	int added = 0, error = 0;
261718334Speter	char	ifname[IF_NAMESIZE];
261890081Sobrien	char	label[PF_RULE_LABEL_SIZE];
261918334Speter	struct pf_pooladdr *pa;
2620132727Skan	struct node_host *h;
2621132727Skan	char	qname[PF_QNAME_SIZE];
262218334Speter	u_int8_t flags, flagset;
2623132727Skan
262418334Speter	strlcpy(label, r->label, sizeof(label));
2625132727Skan	strlcpy(qname, r->qname, sizeof(qname));
2626132727Skan	flags = r->flags;
2627117404Skan	flagset = r->flagset;
2628132727Skan
2629117404Skan	LOOP_THROUGH(struct node_if, interface, interfaces,
2630132727Skan	LOOP_THROUGH(struct node_proto, proto, protos,
2631132727Skan	LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types,
2632132727Skan	LOOP_THROUGH(struct node_host, src_host, src_hosts,
2633132727Skan	LOOP_THROUGH(struct node_port, src_port, src_ports,
2634117404Skan	LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
2635132727Skan	LOOP_THROUGH(struct node_port, dst_port, dst_ports,
2636132727Skan	LOOP_THROUGH(struct node_uid, uid, uids,
2637132727Skan	LOOP_THROUGH(struct node_gid, gid, gids,
2638132727Skan
2639132727Skan		r->af = af;
2640132727Skan		/* for link-local IPv6 address, interface must match up */
2641117404Skan		if ((r->af && src_host->af && r->af != src_host->af) ||
2642132727Skan		    (r->af && dst_host->af && r->af != dst_host->af) ||
2643117404Skan		    (src_host->af && dst_host->af &&
2644132727Skan		    src_host->af != dst_host->af) ||
264590081Sobrien		    (src_host->ifindex && dst_host->ifindex &&
2646132727Skan		    src_host->ifindex != dst_host->ifindex) ||
2647132727Skan		    (src_host->ifindex && if_nametoindex(interface->ifname) &&
2648132727Skan		    src_host->ifindex != if_nametoindex(interface->ifname)) ||
2649117404Skan		    (dst_host->ifindex && if_nametoindex(interface->ifname) &&
2650132727Skan		    dst_host->ifindex != if_nametoindex(interface->ifname)))
2651132727Skan			continue;
2652132727Skan		if (!r->af && src_host->af)
2653132727Skan			r->af = src_host->af;
265490081Sobrien		else if (!r->af && dst_host->af)
2655132727Skan			r->af = dst_host->af;
2656132727Skan
2657132727Skan		if (if_indextoname(src_host->ifindex, ifname))
2658132727Skan			memcpy(r->ifname, ifname, sizeof(r->ifname));
2659132727Skan		else if (if_indextoname(dst_host->ifindex, ifname))
266090081Sobrien			memcpy(r->ifname, ifname, sizeof(r->ifname));
2661132727Skan		else
2662132727Skan			memcpy(r->ifname, interface->ifname, sizeof(r->ifname));
2663132727Skan
2664132727Skan		strlcpy(r->label, label, PF_RULE_LABEL_SIZE);
2665132727Skan		expand_label(r->label, r->ifname, r->af, src_host, src_port,
2666132727Skan		    dst_host, dst_port, proto->proto);
266718334Speter		strlcpy(r->qname, qname, PF_QNAME_SIZE);
2668132727Skan		r->qid = qname_to_qid(qname, r->ifname);
2669132727Skan		r->ifnot = interface->not;
2670132727Skan		r->proto = proto->proto;
2671132727Skan		r->src.addr = src_host->addr;
267218334Speter		r->src.noroute = src_host->noroute;
2673132727Skan		r->src.not = src_host->not;
2674132727Skan		r->src.port[0] = src_port->port[0];
267550448Sobrien		r->src.port[1] = src_port->port[1];
2676132727Skan		r->src.port_op = src_port->op;
2677132727Skan		r->dst.addr = dst_host->addr;
2678117404Skan		r->dst.noroute = dst_host->noroute;
2679132727Skan		r->dst.not = dst_host->not;
2680132727Skan		r->dst.port[0] = dst_port->port[0];
2681132727Skan		r->dst.port[1] = dst_port->port[1];
268290081Sobrien		r->dst.port_op = dst_port->op;
2683132727Skan		r->uid.op = uid->op;
268490081Sobrien		r->uid.uid[0] = uid->uid[0];
2685132727Skan		r->uid.uid[1] = uid->uid[1];
268690081Sobrien		r->gid.op = gid->op;
2687132727Skan		r->gid.gid[0] = gid->gid[0];
268890081Sobrien		r->gid.gid[1] = gid->gid[1];
2689132727Skan		r->type = icmp_type->type;
2690132727Skan		r->code = icmp_type->code;
269190081Sobrien
2692132727Skan		if (r->proto && r->proto != IPPROTO_TCP) {
2693132727Skan			r->flags = 0;
2694132727Skan			r->flagset = 0;
2695132727Skan		} else {
2696132727Skan			r->flags = flags;
269790081Sobrien			r->flagset = flagset;
2698132727Skan		}
2699132727Skan		if (icmp_type->proto && r->proto != icmp_type->proto) {
2700132727Skan			yyerror("icmp-type mismatch");
2701132727Skan			error++;
2702132727Skan		}
270390081Sobrien
2704132727Skan		TAILQ_INIT(&r->rt_pool.list);
2705132727Skan		for (h = rt_pool_hosts; h != NULL; h = h->next) {
2706132727Skan			pa = calloc(1, sizeof(struct pf_pooladdr));
270790081Sobrien			if (pa == NULL) {
2708132727Skan				yyerror("calloc");
2709132727Skan				error++;
2710132727Skan			}
2711132727Skan			pa->addr = h->addr;
2712132727Skan			if (h->ifname != NULL)
2713132727Skan				strncpy(pa->ifname, h->ifname, IFNAMSIZ);
2714132727Skan			else
2715132727Skan				pa->ifname[0] = 0;
2716132727Skan			TAILQ_INSERT_TAIL(&r->rt_pool.list, pa, entries);
2717132727Skan		}
2718132727Skan
2719132727Skan		if (rule_consistent(r) < 0 || error)
2720132727Skan			yyerror("skipping filter rule due to errors");
2721132727Skan		else {
2722132727Skan			r->nr = pf->rule_nr++;
2723132727Skan			pfctl_add_rule(pf, r);
272450448Sobrien			added++;
272518334Speter		}
272618334Speter
272718334Speter	)))))))));
272818334Speter
272918334Speter	FREE_LIST(struct node_if, interfaces);
273018334Speter	FREE_LIST(struct node_proto, protos);
273118334Speter	FREE_LIST(struct node_host, src_hosts);
273218334Speter	FREE_LIST(struct node_port, src_ports);
273318334Speter	FREE_LIST(struct node_host, dst_hosts);
273450448Sobrien	FREE_LIST(struct node_port, dst_ports);
273550448Sobrien	FREE_LIST(struct node_uid, uids);
273618334Speter	FREE_LIST(struct node_gid, gids);
273718334Speter	FREE_LIST(struct node_icmp, icmp_types);
2738132727Skan	FREE_LIST(struct node_host, rt_pool_hosts);
273918334Speter
2740117404Skan	if (!added)
274190081Sobrien		yyerror("rule expands to no valid combination");
274218334Speter}
2743117404Skan
2744117404Skanvoid
2745132727Skanexpand_nat(struct pf_nat *n,
274618334Speter    struct node_if *interfaces, struct node_proto *protos,
274790081Sobrien    struct node_host *src_hosts, struct node_port *src_ports,
274850448Sobrien    struct node_host *dst_hosts, struct node_port *dst_ports,
2749117404Skan    struct node_host *rpool_hosts)
2750132727Skan{
275150448Sobrien	char ifname[IF_NAMESIZE];
275250448Sobrien	struct pf_pooladdr *pa;
275318334Speter	struct node_host *h;
275418334Speter	sa_family_t af = n->af;
275590081Sobrien	int added = 0, error = 0;
275618334Speter
2757132727Skan	LOOP_THROUGH(struct node_if, interface, interfaces,
275890081Sobrien	LOOP_THROUGH(struct node_proto, proto, protos,
275918334Speter	LOOP_THROUGH(struct node_host, src_host, src_hosts,
276090081Sobrien	LOOP_THROUGH(struct node_port, src_port, src_ports,
276190081Sobrien	LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
276290081Sobrien	LOOP_THROUGH(struct node_port, dst_port, dst_ports,
276390081Sobrien
276490081Sobrien		n->af = af;
276518334Speter		/* for link-local IPv6 address, interface must match up */
276618334Speter		if ((n->af && src_host->af && n->af != src_host->af) ||
276718334Speter		    (n->af && dst_host->af && n->af != dst_host->af) ||
276818334Speter		    (src_host->af && dst_host->af &&
276918334Speter		    src_host->af != dst_host->af) ||
277018334Speter		    (src_host->ifindex && dst_host->ifindex &&
277118334Speter		    src_host->ifindex != dst_host->ifindex) ||
2772117404Skan		    (src_host->ifindex && if_nametoindex(interface->ifname) &&
2773117404Skan		    src_host->ifindex != if_nametoindex(interface->ifname)) ||
2774117404Skan		    (dst_host->ifindex && if_nametoindex(interface->ifname) &&
2775117404Skan		    dst_host->ifindex != if_nametoindex(interface->ifname)))
2776117404Skan			continue;
277718334Speter		if (!n->af && src_host->af)
277818334Speter			n->af = src_host->af;
277918334Speter		else if (!n->af && dst_host->af)
2780132727Skan			n->af = dst_host->af;
2781132727Skan
2782132727Skan		if (if_indextoname(src_host->ifindex, ifname))
2783132727Skan			memcpy(n->ifname, ifname, sizeof(n->ifname));
278490081Sobrien		else if (if_indextoname(dst_host->ifindex, ifname))
278590081Sobrien			memcpy(n->ifname, ifname, sizeof(n->ifname));
2786132727Skan		else
278718334Speter			memcpy(n->ifname, interface->ifname, sizeof(n->ifname));
278850448Sobrien
278918334Speter		n->ifnot = interface->not;
279018334Speter		n->proto = proto->proto;
279118334Speter		n->src.addr = src_host->addr;
279218334Speter		n->src.noroute = src_host->noroute;
279318334Speter		n->src.not = src_host->not;
279418334Speter		n->src.port[0] = src_port->port[0];
279518334Speter		n->src.port[1] = src_port->port[1];
2796132727Skan		n->src.port_op = src_port->op;
279790081Sobrien		n->dst.addr = dst_host->addr;
279890081Sobrien		n->dst.noroute = dst_host->noroute;
279990081Sobrien		n->dst.not = dst_host->not;
280090081Sobrien		n->dst.port[0] = dst_port->port[0];
280118334Speter		n->dst.port[1] = dst_port->port[1];
280218334Speter		n->dst.port_op = dst_port->op;
280318334Speter
2804132727Skan		TAILQ_INIT(&n->rpool.list);
280590081Sobrien		for (h = rpool_hosts; h != NULL; h = h->next) {
280690081Sobrien			pa = calloc(1, sizeof(struct pf_pooladdr));
280750448Sobrien			if (pa == NULL) {
280850448Sobrien				yyerror("calloc");
2809117404Skan				error++;
281050448Sobrien			}
2811132727Skan			pa->addr = h->addr;
2812132727Skan			pa->ifname[0] = 0;
281318334Speter			TAILQ_INSERT_TAIL(&n->rpool.list, pa, entries);
281450448Sobrien		}
2815117404Skan
2816117404Skan		if (nat_consistent(n) < 0 || error)
2817132727Skan			yyerror("skipping nat rule due to errors");
2818117404Skan		else {
281990081Sobrien			pfctl_add_nat(pf, n);
2820117404Skan			added++;
282190081Sobrien		}
282290081Sobrien
2823117404Skan	))))));
2824117404Skan
2825117404Skan	FREE_LIST(struct node_if, interfaces);
282618334Speter	FREE_LIST(struct node_proto, protos);
282750448Sobrien	FREE_LIST(struct node_host, src_hosts);
282818334Speter	FREE_LIST(struct node_port, src_ports);
282950448Sobrien	FREE_LIST(struct node_host, dst_hosts);
283050448Sobrien	FREE_LIST(struct node_port, dst_ports);
283150448Sobrien	FREE_LIST(struct node_host, rpool_hosts);
2832132727Skan
2833132727Skan	if (!added)
283490081Sobrien		yyerror("nat rule expands to no valid combinations");
283590081Sobrien}
2836132727Skan
283750448Sobrienvoid
283818334Speterexpand_rdr(struct pf_rdr *r, struct node_if *interfaces,
283918334Speter    struct node_proto *protos, struct node_host *src_hosts,
284018334Speter    struct node_host *dst_hosts, struct node_host *rpool_hosts)
284118334Speter{
284218334Speter	sa_family_t af = r->af;
284318334Speter	int added = 0, error = 0;
284490081Sobrien	char ifname[IF_NAMESIZE];
2845132727Skan	struct pf_pooladdr *pa;
284690081Sobrien	struct node_host *h;
284718334Speter
284850448Sobrien	LOOP_THROUGH(struct node_if, interface, interfaces,
284970638Sobrien	LOOP_THROUGH(struct node_proto, proto, protos,
2850132727Skan	LOOP_THROUGH(struct node_host, src_host, src_hosts,
2851132727Skan	LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
2852132727Skan
2853132727Skan		r->af = af;
2854132727Skan		if ((r->af && src_host->af && r->af != src_host->af) ||
2855132727Skan		    (r->af && dst_host->af && r->af != dst_host->af) ||
285650448Sobrien		    (src_host->af && dst_host->af &&
285750448Sobrien		    src_host->af != dst_host->af) ||
2858132727Skan		    (src_host->ifindex && dst_host->ifindex &&
285950448Sobrien		    src_host->ifindex != dst_host->ifindex) ||
2860110621Skan		    (src_host->ifindex && if_nametoindex(interface->ifname) &&
2861132727Skan		    src_host->ifindex != if_nametoindex(interface->ifname)) ||
2862110621Skan		    (dst_host->ifindex && if_nametoindex(interface->ifname) &&
2863110621Skan		    dst_host->ifindex != if_nametoindex(interface->ifname)))
2864110621Skan			continue;
2865110621Skan
2866110621Skan		if (!r->af && src_host->af)
2867110621Skan			r->af = src_host->af;
286818334Speter		else if (!r->af && dst_host->af)
286918334Speter			r->af = dst_host->af;
2870132727Skan
287118334Speter		if (if_indextoname(src_host->ifindex, ifname))
287218334Speter			memcpy(r->ifname, ifname, sizeof(r->ifname));
2873132727Skan		else if (if_indextoname(dst_host->ifindex, ifname))
2874132727Skan			memcpy(r->ifname, ifname, sizeof(r->ifname));
287518334Speter		else
287618334Speter			memcpy(r->ifname, interface->ifname, sizeof(r->ifname));
287718334Speter
287818334Speter		r->proto = proto->proto;
287918334Speter		r->ifnot = interface->not;
2880132727Skan		r->saddr = src_host->addr;
2881132727Skan		r->daddr = dst_host->addr;
288218334Speter
288318334Speter		TAILQ_INIT(&r->rpool.list);
288418334Speter		for (h = rpool_hosts; h != NULL; h = h->next) {
288518334Speter			pa = calloc(1, sizeof(struct pf_pooladdr));
2886110621Skan			if (pa == NULL) {
2887110621Skan				yyerror("calloc");
2888110621Skan				error++;
288918334Speter			}
289018334Speter			pa->addr = h->addr;
289118334Speter			pa->ifname[0] = 0;
289218334Speter			TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries);
2893110621Skan		}
2894132727Skan
2895110621Skan		if (rdr_consistent(r) < 0 || error)
289618334Speter			yyerror("skipping rdr rule due to errors");
289718334Speter		else {
2898132727Skan			pfctl_add_rdr(pf, r);
2899132727Skan			added++;
2900132727Skan		}
2901132727Skan
2902132727Skan	))));
2903132727Skan
2904132727Skan	FREE_LIST(struct node_if, interfaces);
2905132727Skan	FREE_LIST(struct node_proto, protos);
290618334Speter	FREE_LIST(struct node_host, src_hosts);
290750448Sobrien	FREE_LIST(struct node_host, dst_hosts);
290850448Sobrien	FREE_LIST(struct node_host, rpool_hosts);
290950448Sobrien
2910132727Skan	if (!added)
2911110621Skan		yyerror("rdr rule expands to no valid combination");
291250448Sobrien}
2913110621Skan
291418334Speter#undef FREE_LIST
2915132727Skan#undef LOOP_THROUGH
2916132727Skan
291752298Sobrienint
291890081Sobriencheck_rulestate(int desired_state)
2919132727Skan{
2920132727Skan	if (require_order && (rulestate > desired_state)) {
2921132727Skan		yyerror("Rules must be in order: options, scrub, "
2922132727Skan		    "queue, NAT, filter");
2923132727Skan		return (1);
292418334Speter	}
2925110621Skan	rulestate = desired_state;
2926110621Skan	return (0);
2927110621Skan}
292818334Speter
292918334Speterint
2930132727Skankw_cmp(const void *k, const void *e)
2931110621Skan{
2932132727Skan	return (strcmp(k, ((const struct keywords *)e)->k_name));
2933132727Skan}
293418334Speter
293518334Speterint
293618334Speterlookup(char *s)
293750448Sobrien{
293850448Sobrien	/* this has to be sorted always */
2939132727Skan	static const struct keywords keywords[] = {
2940132727Skan		{ "all",	ALL},
2941132727Skan		{ "allow-opts",	ALLOWOPTS},
2942132727Skan		{ "altq",	ALTQ},
2943132727Skan		{ "antispoof",	ANTISPOOF},
2944132727Skan		{ "any",	ANY},
2945132727Skan		{ "bandwidth",	BANDWIDTH},
2946132727Skan		{ "binat",	BINAT},
2947132727Skan		{ "bitmask",	BITMASK},
2948132727Skan		{ "block",	BLOCK},
2949132727Skan		{ "block-policy", BLOCKPOLICY},
295090081Sobrien		{ "borrow",	BORROW},
2951110621Skan		{ "cbq",	CBQ},
2952132727Skan		{ "code",	CODE},
295390081Sobrien		{ "control",	CONTROL},
295490081Sobrien		{ "crop",	FRAGCROP},
295550448Sobrien		{ "default",	DEFAULT},
2956132727Skan		{ "drop",	DROP},
2957132727Skan		{ "drop-ovl",	FRAGDROP},
295850448Sobrien		{ "dup-to",	DUPTO},
295950448Sobrien		{ "ecn",	ECN},
296018334Speter		{ "fastroute",	FASTROUTE},
296118334Speter		{ "flags",	FLAGS},
2962132727Skan		{ "for",	FOR},
2963132727Skan		{ "fragment",	FRAGMENT},
2964132727Skan		{ "from",	FROM},
2965132727Skan		{ "group",	GROUP},
2966132727Skan		{ "icmp-type",	ICMPTYPE},
2967132727Skan		{ "in",		IN},
2968132727Skan		{ "inet",	INET},
296918334Speter		{ "inet6",	INET6},
2970132727Skan		{ "ipv6-icmp-type", ICMP6TYPE},
2971132727Skan		{ "keep",	KEEP},
2972132727Skan		{ "label",	LABEL},
2973132727Skan		{ "limit",	LIMIT},
2974132727Skan		{ "log",	LOG},
2975132727Skan		{ "log-all",	LOGALL},
2976132727Skan		{ "loginterface", LOGINTERFACE},
2977132727Skan		{ "max",	MAXIMUM},
2978132727Skan		{ "max-mss",	MAXMSS},
2979132727Skan		{ "min-ttl",	MINTTL},
2980132727Skan		{ "modulate",	MODULATE},
2981132727Skan		{ "nat",	NAT},
2982132727Skan		{ "no",		NO},
2983132727Skan		{ "no-df",	NODF},
2984132727Skan		{ "no-route",	NOROUTE},
2985132727Skan		{ "on",		ON},
2986132727Skan		{ "optimization", OPTIMIZATION},
2987132727Skan		{ "out",	OUT},
2988132727Skan		{ "pass",	PASS},
2989132727Skan		{ "port",	PORT},
299018334Speter		{ "priority",	PRIORITY},
2991132727Skan		{ "proto",	PROTO},
2992132727Skan		{ "qlimit",	QLIMIT},
299390081Sobrien		{ "queue",	QUEUE},
2994132727Skan		{ "quick",	QUICK},
299590081Sobrien		{ "random",	RANDOM},
299690081Sobrien		{ "rdr",	RDR},
299718334Speter		{ "reassemble",	FRAGNORM},
2998132727Skan		{ "red",	RED},
299950448Sobrien		{ "reply-to",	REPLYTO},
3000132727Skan		{ "require-order", REQUIREORDER},
300190081Sobrien		{ "return",	RETURN},
3002132727Skan		{ "return-icmp",RETURNICMP},
300390081Sobrien		{ "return-icmp6",RETURNICMP6},
300490081Sobrien		{ "return-rst",	RETURNRST},
300518334Speter		{ "rio",	RIO},
300618334Speter		{ "round-robin",ROUNDROBIN},
300790081Sobrien		{ "route-to",	ROUTETO},
300818334Speter		{ "scheduler",	SCHEDULER},
300918334Speter		{ "scrub",	SCRUB},
301050448Sobrien		{ "set",	SET},
3011110621Skan		{ "source-hash",SOURCEHASH},
301218334Speter		{ "state",	STATE},
3013117404Skan		{ "tbrsize",	TBRSIZE},
301418334Speter		{ "timeout",	TIMEOUT},
3015110621Skan		{ "to",		TO},
301618334Speter		{ "tos",	TOS},
3017110621Skan		{ "ttl",	TTL},
3018110621Skan		{ "user",	USER},
301918334Speter		{ "yes",	YES},
302018334Speter	};
302118334Speter	const struct keywords *p;
302218334Speter
302318334Speter	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
302450448Sobrien	    sizeof(keywords[0]), kw_cmp);
3025110621Skan
3026110621Skan	if (p) {
3027110621Skan		if (debug > 1)
302818334Speter			fprintf(stderr, "%s: %d\n", s, p->k_val);
302918334Speter		return (p->k_val);
303090081Sobrien	} else {
303152298Sobrien		if (debug > 1)
303252298Sobrien			fprintf(stderr, "string: %s\n", s);
303352298Sobrien		return (STRING);
303452298Sobrien	}
3035117404Skan}
3036110621Skan
303718334Speter#define MAXPUSHBACK	128
303818334Speter
303918334Speterchar	*parsebuf;
304018334Speterint	parseindex;
304118334Speterchar	pushback_buffer[MAXPUSHBACK];
304290081Sobrienint	pushback_index = 0;
304352298Sobrien
3044117404Skanint
3045110621Skanlgetc(FILE *fin)
304618334Speter{
304790081Sobrien	int c, next;
304890081Sobrien
3049110621Skan	if (parsebuf) {
305018334Speter		/* Read character from the parsebuffer instead of input. */
3051132727Skan		if (parseindex >= 0) {
3052132727Skan			c = parsebuf[parseindex++];
3053117404Skan			if (c != '\0')
3054117404Skan				return (c);
3055117404Skan			parsebuf = NULL;
3056117404Skan		} else
3057132727Skan			parseindex++;
3058132727Skan	}
3059132727Skan
3060117404Skan	if (pushback_index)
3061117404Skan		return (pushback_buffer[--pushback_index]);
3062117404Skan
3063132727Skan	while ((c = getc(fin)) == '\\') {
3064117404Skan		next = getc(fin);
3065132727Skan		if (next != '\n') {
3066117404Skan			if (isspace(next))
3067117404Skan				yyerror("whitespace after \\");
3068132727Skan			ungetc(next, fin);
3069132727Skan			break;
3070117404Skan		}
3071132727Skan		yylval.lineno = lineno;
3072132727Skan		lineno++;
3073117404Skan	}
3074117404Skan	if (c == '\t' || c == ' ') {
3075132727Skan		/* Compress blanks to a single space. */
3076117404Skan		do {
3077132727Skan			c = getc(fin);
3078117404Skan		} while (c == '\t' || c == ' ');
3079117404Skan		ungetc(c, fin);
3080117404Skan		c = ' ';
3081132727Skan	}
3082132727Skan
3083132727Skan	return (c);
3084117404Skan}
3085132727Skan
3086117404Skanint
3087132727Skanlungetc(int c, FILE *fin)
3088132727Skan{
3089132727Skan	if (c == EOF)
3090132727Skan		return (EOF);
3091132727Skan	if (parsebuf) {
3092117404Skan		parseindex--;
309350448Sobrien		if (parseindex >= 0)
309450448Sobrien			return (c);
3095132727Skan	}
309618334Speter	if (pushback_index < MAXPUSHBACK-1)
3097132727Skan		return (pushback_buffer[pushback_index++] = c);
309818334Speter	else
309918334Speter		return (EOF);
3100132727Skan}
3101110621Skan
3102132727Skanint
3103110621Skanfindeol(void)
3104117404Skan{
3105117404Skan	int c;
3106117404Skan
3107117404Skan	parsebuf = NULL;
3108110621Skan	pushback_index = 0;
3109110621Skan
3110110621Skan	/* skip to either EOF or the first real EOL */
3111110621Skan	while (1) {
3112110621Skan		c = lgetc(fin);
3113110621Skan		if (c == '\n') {
3114110621Skan			lineno++;
3115110621Skan			break;
3116110621Skan		}
311750448Sobrien		if (c == EOF)
311890081Sobrien			break;
311950448Sobrien	}
312050448Sobrien	return (ERROR);
312150448Sobrien}
312250448Sobrien
312350448Sobrienint
312450448Sobrienyylex(void)
312550448Sobrien{
312690081Sobrien	char buf[8096], *p, *val;
312750448Sobrien	int endc, c, next;
312850448Sobrien	int token;
312950448Sobrien
313050448Sobrientop:
3131117404Skan	p = buf;
3132117404Skan	while ((c = lgetc(fin)) == ' ')
3133132727Skan		;
3134132727Skan
313550448Sobrien	yylval.lineno = lineno;
3136132727Skan	if (c == '#')
313750448Sobrien		while ((c = lgetc(fin)) != '\n' && c != EOF)
313850448Sobrien			;
3139132727Skan	if (c == '$' && parsebuf == NULL) {
314090081Sobrien		while (1) {
314190081Sobrien			if ((c = lgetc(fin)) == EOF)
314250448Sobrien				return (0);
314350448Sobrien
314450448Sobrien			if (p + 1 >= buf + sizeof(buf) - 1) {
314550448Sobrien				yyerror("string too long");
314650448Sobrien				return (findeol());
314750448Sobrien			}
314850448Sobrien			if (isalnum(c) || c == '_') {
314950448Sobrien				*p++ = (char)c;
315050448Sobrien				continue;
3151132727Skan			}
3152132727Skan			*p = '\0';
3153132727Skan			lungetc(c, fin);
3154132727Skan			break;
315550448Sobrien		}
315650448Sobrien		val = symget(buf);
315750448Sobrien		if (val == NULL) {
315850448Sobrien			yyerror("macro '%s' not defined", buf);
315950448Sobrien			return (findeol());
316050448Sobrien		}
316150448Sobrien		parsebuf = val;
316250448Sobrien		parseindex = 0;
316350448Sobrien		goto top;
316450448Sobrien	}
316550448Sobrien
3166132727Skan	switch (c) {
3167132727Skan	case '\'':
3168132727Skan	case '"':
3169132727Skan		endc = c;
3170117404Skan		while (1) {
3171132727Skan			if ((c = lgetc(fin)) == EOF)
3172117404Skan				return (0);
3173117404Skan			if (c == endc) {
3174117404Skan				*p = '\0';
3175132727Skan				break;
3176117404Skan			}
3177117404Skan			if (c == '\n') {
317850448Sobrien				lineno++;
317950448Sobrien				continue;
318050448Sobrien			}
318150448Sobrien			if (p + 1 >= buf + sizeof(buf) - 1) {
318250448Sobrien				yyerror("string too long");
318350448Sobrien				return (findeol());
3184117404Skan			}
318550448Sobrien			*p++ = (char)c;
318650448Sobrien		}
318750448Sobrien		yylval.v.string = strdup(buf);
318890081Sobrien		if (yylval.v.string == NULL)
318990081Sobrien			err(1, "yylex: strdup");
319090081Sobrien		return (STRING);
319190081Sobrien	case '=':
319290081Sobrien		yylval.v.i = PF_OP_EQ;
3193132727Skan		return (PORTUNARY);
3194132727Skan	case '!':
319590081Sobrien		next = lgetc(fin);
319690081Sobrien		if (next == '=') {
319790081Sobrien			yylval.v.i = PF_OP_NE;
319890081Sobrien			return (PORTUNARY);
319990081Sobrien		}
320090081Sobrien		lungetc(next, fin);
320150448Sobrien		break;
320290081Sobrien	case '<':
320390081Sobrien		next = lgetc(fin);
320490081Sobrien		if (next == '>') {
320590081Sobrien			yylval.v.i = PF_OP_XRG;
320690081Sobrien			return (PORTBINARY);
320790081Sobrien		} else  if (next == '=') {
320890081Sobrien			yylval.v.i = PF_OP_LE;
3209132727Skan		} else {
3210117404Skan			yylval.v.i = PF_OP_LT;
3211117404Skan			lungetc(next, fin);
321290081Sobrien		}
321350448Sobrien		return (PORTUNARY);
321450448Sobrien		break;
3215117404Skan	case '>':
321650448Sobrien		next = lgetc(fin);
3217132727Skan		if (next == '<') {
321850448Sobrien			yylval.v.i = PF_OP_IRG;
321990081Sobrien			return (PORTBINARY);
3220117404Skan		} else  if (next == '=') {
3221117404Skan			yylval.v.i = PF_OP_GE;
322252298Sobrien		} else {
322352298Sobrien			yylval.v.i = PF_OP_GT;
322452298Sobrien			lungetc(next, fin);
3225117404Skan		}
322690081Sobrien		return (PORTUNARY);
322790081Sobrien		break;
322852298Sobrien	case '-':
3229117404Skan		next = lgetc(fin);
3230117404Skan		if (next == '>')
3231117404Skan			return (ARROW);
3232117404Skan		lungetc(next, fin);
3233117404Skan		break;
3234117404Skan	}
3235117404Skan
3236117404Skan#define allowed_in_string(x) \
3237117404Skan	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
3238132727Skan	x != '{' && x != '}' && x != '<' && x != '>' && \
3239117404Skan	x != '!' && x != '=' && x != '/' && x != '#' && \
3240117404Skan	x != ','))
3241117404Skan
3242117404Skan	if (isalnum(c) || c == ':') {
3243117404Skan		do {
3244132727Skan			*p++ = c;
3245117404Skan			if ((unsigned)(p-buf) >= sizeof(buf)) {
3246117404Skan				yyerror("string too long");
3247117404Skan				return (findeol());
3248117404Skan			}
3249117404Skan		} while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
3250117404Skan		lungetc(c, fin);
3251117404Skan		*p = '\0';
3252117404Skan		token = lookup(buf);
3253132727Skan		yylval.v.string = strdup(buf);
3254132727Skan		if (yylval.v.string == NULL)
3255132727Skan			err(1, "yylex: strdup");
3256132727Skan		return (token);
3257117404Skan	}
3258117404Skan	if (c == '\n') {
3259117404Skan		yylval.lineno = lineno;
3260132727Skan		lineno++;
3261132727Skan	}
3262132727Skan	if (c == EOF)
3263132727Skan		return (0);
3264132727Skan	return (c);
3265132727Skan}
3266132727Skan
3267132727Skanint
3268132727Skanparse_rules(FILE *input, struct pfctl *xpf)
3269117404Skan{
3270117404Skan	struct sym *sym;
3271132727Skan
3272117404Skan	fin = input;
3273132727Skan	pf = xpf;
3274117404Skan	lineno = 1;
3275117404Skan	errors = 0;
3276117404Skan	rulestate = PFCTL_STATE_NONE;
3277117404Skan	yyparse();
3278117404Skan
3279117404Skan	/* Check which macros have not been used. */
3280117404Skan	for (sym = symhead; sym; sym = sym->next)
3281117404Skan		if (!sym->used)
3282117404Skan			fprintf(stderr, "warning: macro '%s' not used\n",
3283117404Skan			    sym->nam);
3284117404Skan
3285117404Skan	return (errors ? -1 : 0);
3286117404Skan}
3287117404Skan
3288117404Skanvoid
3289117404Skanset_ipmask(struct node_host *h, u_int8_t b)
329018334Speter{
329118334Speter	struct pf_addr *m, *n;
329218334Speter	int i, j = 0;
3293132727Skan
3294132727Skan	m = &h->addr.mask;
3295132727Skan
3296132727Skan	for (i = 0; i < 4; i++)
3297132727Skan		m->addr32[i] = 0;
3298132727Skan
3299132727Skan	while (b >= 32) {
3300132727Skan		m->addr32[j++] = 0xffffffff;
3301132727Skan		b -= 32;
3302132727Skan	}
3303132727Skan	for (i = 31; i > 31-b; --i)
3304132727Skan		m->addr32[j] |= (1 << i);
3305132727Skan	if (b)
3306132727Skan		m->addr32[j] = htonl(m->addr32[j]);
330718334Speter
3308132727Skan	/* Mask off bits of the address that will never be used. */
3309132727Skan	n = &h->addr.addr;
3310132727Skan	for (i = 0; i < 4; i++)
3311132727Skan		n->addr32[i] = n->addr32[i] & m->addr32[i];
331290081Sobrien}
331390081Sobrien
331418334Speter/*
331590081Sobrien * Over-designed efficiency is a French and German concept, so how about
331690081Sobrien * we wait until they discover this ugliness and make it all fancy.
331790081Sobrien */
3318132727Skanint
3319132727Skansymset(const char *nam, const char *val)
3320132727Skan{
332190081Sobrien	struct sym *sym;
332290081Sobrien
332390081Sobrien	sym = calloc(1, sizeof(*sym));
332490081Sobrien	if (sym == NULL)
332590081Sobrien		return (-1);
332690081Sobrien	sym->nam = strdup(nam);
3327132727Skan	if (sym->nam == NULL) {
3328132727Skan		free(sym);
332990081Sobrien		return (-1);
333090081Sobrien	}
333118334Speter	sym->val = strdup(val);
3332132727Skan	if (sym->val == NULL) {
3333132727Skan		free(sym->nam);
3334132727Skan		free(sym);
3335132727Skan		return (-1);
3336132727Skan	}
3337132727Skan	sym->next = symhead;
3338132727Skan	sym->used = 0;
3339132727Skan	symhead = sym;
3340132727Skan	return (0);
3341132727Skan}
3342132727Skan
3343132727Skanchar *
334490081Sobriensymget(const char *nam)
334590081Sobrien{
334690081Sobrien	struct sym *sym;
334790081Sobrien
334890081Sobrien	for (sym = symhead; sym; sym = sym->next)
334990081Sobrien		if (strcmp(nam, sym->nam) == 0) {
3350132727Skan			sym->used = 1;
335190081Sobrien			return (sym->val);
3352132727Skan		}
3353132727Skan	return (NULL);
335490081Sobrien}
335590081Sobrien
335618334Speter/* interface lookup routines */
335790081Sobrien
335890081Sobrienstruct node_host *iftab;
335990081Sobrien
336090081Sobrienvoid
336118334Speterifa_load(void)
336290081Sobrien{
3363132727Skan	struct ifaddrs *ifap, *ifa;
336490081Sobrien	struct node_host *n = NULL, *h = NULL;
3365132727Skan
336690081Sobrien	if (getifaddrs(&ifap) < 0)
336790081Sobrien		err(1, "getifaddrs");
336890081Sobrien
336918334Speter	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
337090081Sobrien		if (!(ifa->ifa_addr->sa_family == AF_INET ||
337190081Sobrien		    ifa->ifa_addr->sa_family == AF_INET6 ||
337290081Sobrien		    ifa->ifa_addr->sa_family == AF_LINK))
337390081Sobrien				continue;
337418334Speter		n = calloc(1, sizeof(struct node_host));
3375132727Skan		if (n == NULL)
3376132727Skan			err(1, "address: calloc");
3377132727Skan		n->af = ifa->ifa_addr->sa_family;
3378132727Skan		n->addr.addr_dyn = NULL;
3379132727Skan		n->ifa_flags = ifa->ifa_flags;
3380132727Skan#ifdef __KAME__
3381132727Skan		if (n->af == AF_INET6 &&
3382132727Skan		    IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr) &&
3383132727Skan		    ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == 0) {
3384132727Skan			struct sockaddr_in6 *sin6;
3385132727Skan
3386132727Skan			sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
3387132727Skan			sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 |
338890081Sobrien			    sin6->sin6_addr.s6_addr[3];
3389132727Skan			sin6->sin6_addr.s6_addr[2] = 0;
339090081Sobrien			sin6->sin6_addr.s6_addr[3] = 0;
3391132727Skan		}
339290081Sobrien#endif
339390081Sobrien		n->ifindex = 0;
339490081Sobrien		if (n->af == AF_INET) {
339552298Sobrien			memcpy(&n->addr.addr, &((struct sockaddr_in *)
3396132727Skan			    ifa->ifa_addr)->sin_addr.s_addr,
3397132727Skan			    sizeof(struct in_addr));
3398132727Skan			memcpy(&n->addr.mask, &((struct sockaddr_in *)
3399132727Skan			    ifa->ifa_netmask)->sin_addr.s_addr,
3400132727Skan			    sizeof(struct in_addr));
3401132727Skan			if (ifa->ifa_broadaddr != NULL)
3402132727Skan				memcpy(&n->bcast, &((struct sockaddr_in *)
3403132727Skan				    ifa->ifa_broadaddr)->sin_addr.s_addr,
3404132727Skan				    sizeof(struct in_addr));
3405132727Skan		} else if (n->af == AF_INET6) {
3406132727Skan			memcpy(&n->addr.addr, &((struct sockaddr_in6 *)
3407132727Skan			    ifa->ifa_addr)->sin6_addr.s6_addr,
3408132727Skan			    sizeof(struct in6_addr));
340990081Sobrien			memcpy(&n->addr.mask, &((struct sockaddr_in6 *)
341090081Sobrien			    ifa->ifa_netmask)->sin6_addr.s6_addr,
341190081Sobrien			    sizeof(struct in6_addr));
341290081Sobrien			if (ifa->ifa_broadaddr != NULL)
341390081Sobrien				memcpy(&n->bcast, &((struct sockaddr_in6 *)
341418334Speter				    ifa->ifa_broadaddr)->sin6_addr.s6_addr,
341590081Sobrien				    sizeof(struct in6_addr));
3416132727Skan			n->ifindex = ((struct sockaddr_in6 *)
341790081Sobrien			    ifa->ifa_addr)->sin6_scope_id;
3418132727Skan		}
341990081Sobrien		if ((n->ifname = strdup(ifa->ifa_name)) == NULL) {
342090081Sobrien			yyerror("strdup failed");
342190081Sobrien			exit(1);
342218334Speter		}
342390081Sobrien		n->next = NULL;
342490081Sobrien		n->tail = n;
342590081Sobrien		if (h == NULL)
342690081Sobrien			h = n;
342718334Speter		else {
342890081Sobrien			h->tail->next = n;
342990081Sobrien			h->tail = n;
343090081Sobrien		}
343118334Speter	}
343290081Sobrien	iftab = h;
343350448Sobrien	freeifaddrs(ifap);
343490081Sobrien}
343590081Sobrien
343690081Sobrienstruct node_host *
343790081Sobrienifa_exists(char *ifa_name)
3438117404Skan{
3439117404Skan	struct node_host *n;
344090081Sobrien
344190081Sobrien	if (iftab == NULL)
344290081Sobrien		ifa_load();
344390081Sobrien
344490081Sobrien	for (n = iftab; n; n = n->next) {
344590081Sobrien		if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ))
344690081Sobrien			return (n);
344790081Sobrien	}
344890081Sobrien	return (NULL);
344990081Sobrien}
345090081Sobrien
345190081Sobrienstruct node_host *
345290081Sobrienifa_lookup(char *ifa_name, enum pfctl_iflookup_mode mode)
345390081Sobrien{
3454132727Skan	struct node_host *p = NULL, *h = NULL, *n = NULL;
345590081Sobrien	int return_all = 0;
345690081Sobrien
345790081Sobrien	if (!strncmp(ifa_name, "self", IFNAMSIZ))
345890081Sobrien		return_all = 1;
345990081Sobrien
3460132727Skan	if (iftab == NULL)
346190081Sobrien		ifa_load();
346290081Sobrien
346390081Sobrien	for (p = iftab; p; p = p->next) {
346490081Sobrien		if (!((p->af == AF_INET || p->af == AF_INET6) &&
346590081Sobrien		    (!strncmp(p->ifname, ifa_name, IFNAMSIZ) || return_all)))
346690081Sobrien			continue;
346790081Sobrien		if (mode == PFCTL_IFLOOKUP_BCAST && p->af != AF_INET)
346890081Sobrien			continue;
346990081Sobrien		if (mode == PFCTL_IFLOOKUP_NET && p->ifindex > 0)
347090081Sobrien			continue;
347190081Sobrien		n = calloc(1, sizeof(struct node_host));
347290081Sobrien		if (n == NULL)
347390081Sobrien			err(1, "address: calloc");
3474132727Skan		n->af = p->af;
347590081Sobrien		n->addr.addr_dyn = NULL;
347690081Sobrien		if (mode == PFCTL_IFLOOKUP_BCAST) {
3477132727Skan				memcpy(&n->addr.addr, &p->bcast,
347890081Sobrien				    sizeof(struct pf_addr));
347990081Sobrien		} else
3480132727Skan			memcpy(&n->addr.addr, &p->addr.addr,
348190081Sobrien			    sizeof(struct pf_addr));
348290081Sobrien		if (mode == PFCTL_IFLOOKUP_NET)
3483132727Skan			memcpy(&n->addr.mask, &p->addr.mask,
348490081Sobrien			    sizeof(struct pf_addr));
3485132727Skan		else {
3486132727Skan			if (n->af == AF_INET) {
3487132727Skan				if (p->ifa_flags & IFF_LOOPBACK &&
3488132727Skan				    p->ifa_flags & IFF_LINK1)
3489132727Skan					memcpy(&n->addr.mask, &p->addr.mask,
3490132727Skan					    sizeof(struct pf_addr));
3491132727Skan				else
3492132727Skan					set_ipmask(n, 32);
349390081Sobrien			} else
3494132727Skan				set_ipmask(n, 128);
3495132727Skan		}
3496132727Skan		n->ifindex = p->ifindex;
3497132727Skan
3498132727Skan		n->next = NULL;
3499132727Skan		n->tail = n;
350090081Sobrien		if (h == NULL)
3501132727Skan			h = n;
3502132727Skan		else {
3503132727Skan			h->tail->next = n;
3504132727Skan			h->tail = n;
3505132727Skan		}
3506132727Skan	}
3507132727Skan	if (h == NULL && mode == PFCTL_IFLOOKUP_HOST) {
3508132727Skan		yyerror("no IP address found for %s", ifa_name);
3509132727Skan	}
3510132727Skan	return (h);
351190081Sobrien}
351290081Sobrien
351390081Sobrienvoid
3514132727Skandecide_address_family(struct node_host *n, sa_family_t *af)
351590081Sobrien{
3516132727Skan	sa_family_t target_af = 0;
351790081Sobrien
351890081Sobrien	while (!*af && n != NULL) {
351990081Sobrien		if (n->af) {
352090081Sobrien			if (target_af == 0)
3521132727Skan				target_af = n->af;
352290081Sobrien			if (target_af != n->af)
3523117404Skan				return;
3524117404Skan		}
3525117404Skan		n = n->next;
3526132727Skan	}
3527117404Skan	if (!*af && target_af)
3528117404Skan		*af = target_af;
3529117404Skan}
3530117404Skan
3531117404Skanvoid
3532132727Skanremove_invalid_hosts(struct node_host **nh, sa_family_t *af)
3533117404Skan{
3534132727Skan	struct node_host *n = *nh, *prev = NULL;
3535132727Skan
3536132727Skan	while (n != NULL) {
3537132727Skan		if (*af && n->af && n->af != *af) {
3538132727Skan			/* unlink and free n */
3539132727Skan			struct node_host *next = n->next;
3540132727Skan
3541132727Skan			/* adjust tail pointer */
3542132727Skan			if (n == (*nh)->tail)
3543132727Skan				(*nh)->tail = prev;
3544132727Skan			/* adjust previous node's next pointer */
3545132727Skan			if (prev == NULL)
3546132727Skan				*nh = next;
354750448Sobrien			else
3548132727Skan				prev->next = next;
3549132727Skan			/* free node */
355018334Speter			if (n->ifname != NULL)
355118334Speter				free(n->ifname);
3552132727Skan			free(n);
3553132727Skan			n = next;
3554132727Skan		} else {
3555132727Skan			if (n->af && !*af)
3556132727Skan				*af = n->af;
3557132727Skan			prev = n;
3558132727Skan			n = n->next;
3559132727Skan		}
3560132727Skan	}
3561132727Skan
3562132727Skan	if (!*af)
3563132727Skan		yyerror("address family not given and translation "
3564132727Skan		    "address expands to multiple address families");
3565132727Skan	else if (*nh == NULL)
3566132727Skan		yyerror("no translation address with matching address family "
356718334Speter		    "found.");
356852298Sobrien}
356918334Speter
357018334Speterstruct node_host *
3571132727Skanhost(char *s, int mask)
357250448Sobrien{
357350448Sobrien	struct node_host *h = NULL, *n;
357450448Sobrien	struct in_addr ina;
357550448Sobrien	struct addrinfo hints, *res0, *res;
357650448Sobrien	int bits, error, v4mask, v6mask;
357750448Sobrien	char *buf = NULL;
357850448Sobrien
357950448Sobrien	if (ifa_exists(s) || !strncmp(s, "self", IFNAMSIZ)) {
358050448Sobrien		/* interface with this name exists */
358150448Sobrien		h = ifa_lookup(s, PFCTL_IFLOOKUP_HOST);
358218334Speter		if (h != NULL && mask > -1)
3583132727Skan			set_ipmask(h, mask);
3584132727Skan		return (h);
3585132727Skan	}
3586132727Skan
3587132727Skan	if (mask == -1) {
3588132727Skan		if (asprintf(&buf, "%s", s) == -1)
3589132727Skan			err(1, "host: asprintf");
359018334Speter		v4mask = 32;
359118334Speter		v6mask = 128;
359218334Speter	} else if (mask <= 128) {
359318334Speter		if (asprintf(&buf, "%s/%d", s, mask) == -1)
359490081Sobrien			err(1, "host: asprintf");
3595132727Skan		v4mask = v6mask = mask;
359618334Speter	} else {
359718334Speter		yyerror("illegal mask");
359818334Speter		return (NULL);
3599132727Skan	}
3600132727Skan
360118334Speter	memset(&ina, 0, sizeof(struct in_addr));
360218334Speter	if ((bits = inet_net_pton(AF_INET, buf, &ina, sizeof(&ina))) > -1) {
360318334Speter		h = calloc(1, sizeof(struct node_host));
360490081Sobrien		if (h == NULL)
360590081Sobrien			err(1, "address: calloc");
360690081Sobrien		h->ifname = NULL;
3607132727Skan		h->af = AF_INET;
3608132727Skan		h->addr.addr_dyn = NULL;
360918334Speter		h->addr.addr.addr32[0] = ina.s_addr;
3610132727Skan		set_ipmask(h, bits);
3611132727Skan		h->next = NULL;
3612132727Skan		h->tail = h;
361390081Sobrien		free(buf);
361490081Sobrien		return (h);
3615132727Skan	}
3616132727Skan	free(buf);
361750448Sobrien
361850448Sobrien	memset(&hints, 0, sizeof(hints));
361950448Sobrien	hints.ai_family = AF_INET6;
362050448Sobrien	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
362118334Speter	hints.ai_flags = AI_NUMERICHOST;
3622132727Skan	if (getaddrinfo(s, "0", &hints, &res) == 0) {
3623132727Skan		n = calloc(1, sizeof(struct node_host));
3624132727Skan		if (n == NULL)
3625132727Skan			err(1, "address: calloc");
362618334Speter		n->ifname = NULL;
362718334Speter		n->af = AF_INET6;
362818334Speter		n->addr.addr_dyn = NULL;
362990081Sobrien		memcpy(&n->addr.addr,
3630132727Skan		    &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
363118334Speter		    sizeof(n->addr.addr));
363218334Speter		n->ifindex = ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
363318334Speter		set_ipmask(n, v6mask);
3634132727Skan		freeaddrinfo(res);
3635132727Skan		n->next = NULL;
363618334Speter		n->tail = n;
363718334Speter		return (n);
363818334Speter	}
363990081Sobrien
364090081Sobrien	memset(&hints, 0, sizeof(hints));
364190081Sobrien	hints.ai_family = PF_UNSPEC;
3642132727Skan	hints.ai_socktype = SOCK_STREAM; /* DUMMY */
3643132727Skan	error = getaddrinfo(s, NULL, &hints, &res0);
364418334Speter	if (error) {
3645132727Skan		yyerror("cannot resolve %s: %s",
3646132727Skan		    s, gai_strerror(error));
3647132727Skan		return (NULL);
364890081Sobrien	}
364990081Sobrien	for (res = res0; res; res = res->ai_next) {
3650132727Skan		if (res->ai_family != AF_INET &&
3651132727Skan		    res->ai_family != AF_INET6)
365250448Sobrien			continue;
365350448Sobrien		n = calloc(1, sizeof(struct node_host));
365450448Sobrien		if (n == NULL)
365550448Sobrien			err(1, "address: calloc");
365618334Speter		n->ifname = NULL;
365718334Speter		n->af = res->ai_family;
365818334Speter		n->addr.addr_dyn = NULL;
365918334Speter		if (res->ai_family == AF_INET) {
366090081Sobrien			memcpy(&n->addr.addr,
3661132727Skan			    &((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr,
366218334Speter			    sizeof(struct in_addr));
366318334Speter			set_ipmask(n, v4mask);
366418334Speter		} else {
3665132727Skan			memcpy(&n->addr.addr,
3666132727Skan			    &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr.s6_addr,
366718334Speter			    sizeof(struct in6_addr));
366818334Speter			n->ifindex =
366918334Speter			    ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
367090081Sobrien			set_ipmask(n, v6mask);
367190081Sobrien		}
367290081Sobrien		n->next = NULL;
3673132727Skan		n->tail = n;
3674132727Skan		if (h == NULL)
367518334Speter			h = n;
3676132727Skan		else {
3677132727Skan			h->tail->next = n;
3678132727Skan			h->tail = n;
367990081Sobrien		}
368090081Sobrien	}
3681132727Skan	freeaddrinfo(res0);
3682132727Skan	if (h == NULL) {
368350448Sobrien		yyerror("no IP address found for %s", s);
368450448Sobrien		return (NULL);
368550448Sobrien	}
368650448Sobrien	return (h);
368718334Speter}
368818334Speter
368918334Speterint
369018334Speteratoul(char *s, u_long *ulvalp)
369190081Sobrien{
3692132727Skan	u_long ulval;
369318334Speter	char *ep;
369418334Speter
369518334Speter	errno = 0;
3696132727Skan	ulval = strtoul(s, &ep, 0);
3697132727Skan	if (s[0] == '\0' || *ep != '\0')
369818334Speter		return (-1);
369918334Speter	if (errno == ERANGE && ulval == ULONG_MAX)
370018334Speter		return (-1);
370190081Sobrien	*ulvalp = ulval;
370290081Sobrien	return (0);
370390081Sobrien}
3704132727Skan
3705132727Skanint
370618334Spetergetservice(char *n)
3707132727Skan{
3708132727Skan	struct servent *s;
3709132727Skan	u_long ulval;
371090081Sobrien
371190081Sobrien	if (atoul(n, &ulval) == 0) {
3712132727Skan		if (ulval > 65535) {
3713132727Skan			yyerror("illegal port value %d", ulval);
371450448Sobrien			return (-1);
371550448Sobrien		}
371650448Sobrien		return (htons(ulval));
371750448Sobrien	} else {
371818334Speter		s = getservbyname(n, "tcp");
371918334Speter		if (s == NULL)
3720132727Skan			s = getservbyname(n, "udp");
3721132727Skan		if (s == NULL) {
3722132727Skan			yyerror("unknown port %s", n);
3723132727Skan			return (-1);
3724132727Skan		}
3725132727Skan		return (s->s_port);
3726132727Skan	}
3727132727Skan}
3728132727Skan
3729132727Skanu_int16_t
3730132727Skanparseicmpspec(char *w, sa_family_t af)
3731132727Skan{
3732132727Skan	const struct icmpcodeent *p;
3733132727Skan	u_long ulval;
3734132727Skan	u_int8_t icmptype;
3735132727Skan
3736132727Skan	if (af == AF_INET)
3737132727Skan		icmptype = returnicmpdefault >> 8;
3738132727Skan	else
3739132727Skan		icmptype = returnicmp6default >> 8;
3740132727Skan
3741132727Skan	if (atoul(w, &ulval) == -1) {
3742132727Skan		if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) {
3743132727Skan			yyerror("unknown icmp code %s", w);
3744132727Skan			return (0);
3745132727Skan		}
3746132727Skan		ulval = p->code;
3747132727Skan	}
3748132727Skan	return (icmptype << 8 | ulval);
3749132727Skan}
3750132727Skan