xref: /netbsd/usr.sbin/npf/npfctl/npf_parse.y (revision d6939920)
1f03cb1d4Srmind /*-
2*d6939920Srmind  * Copyright (c) 2011-2020 The NetBSD Foundation, Inc.
3f03cb1d4Srmind  * All rights reserved.
4f03cb1d4Srmind  *
5f03cb1d4Srmind  * This code is derived from software contributed to The NetBSD Foundation
6c6e77e2aSrmind  * by Martin Husemann, Christos Zoulas and Mindaugas Rasiukevicius.
7f03cb1d4Srmind  *
8f03cb1d4Srmind  * Redistribution and use in source and binary forms, with or without
9f03cb1d4Srmind  * modification, are permitted provided that the following conditions
10f03cb1d4Srmind  * are met:
11f03cb1d4Srmind  * 1. Redistributions of source code must retain the above copyright
12f03cb1d4Srmind  *    notice, this list of conditions and the following disclaimer.
13f03cb1d4Srmind  * 2. Redistributions in binary form must reproduce the above copyright
14f03cb1d4Srmind  *    notice, this list of conditions and the following disclaimer in the
15f03cb1d4Srmind  *    documentation and/or other materials provided with the distribution.
16f03cb1d4Srmind  *
17f03cb1d4Srmind  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18f03cb1d4Srmind  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19f03cb1d4Srmind  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20f03cb1d4Srmind  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21f03cb1d4Srmind  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22f03cb1d4Srmind  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23f03cb1d4Srmind  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24f03cb1d4Srmind  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25f03cb1d4Srmind  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26f03cb1d4Srmind  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27f03cb1d4Srmind  * POSSIBILITY OF SUCH DAMAGE.
28f03cb1d4Srmind  */
29f03cb1d4Srmind 
30f03cb1d4Srmind %{
31f03cb1d4Srmind 
32f03cb1d4Srmind #include <err.h>
33f03cb1d4Srmind #include <netdb.h>
346a296064Sjoerg #include <stdio.h>
356a296064Sjoerg #include <stdlib.h>
366a296064Sjoerg #include <string.h>
376c441296Srmind #ifdef __NetBSD__
386a296064Sjoerg #include <vis.h>
396c441296Srmind #endif
40f03cb1d4Srmind 
41f03cb1d4Srmind #include "npfctl.h"
42f03cb1d4Srmind 
438b3f8af5Srmind #define	YYSTACKSIZE	4096
448b3f8af5Srmind 
45b05f1f8bSrmind int			yystarttoken;
46f03cb1d4Srmind const char *		yyfilename;
47f03cb1d4Srmind 
48f03cb1d4Srmind extern int		yylineno, yycolumn;
49b05f1f8bSrmind extern int		yylex(int);
50f03cb1d4Srmind 
51f03cb1d4Srmind void
yyerror(const char * fmt,...)52f03cb1d4Srmind yyerror(const char *fmt, ...)
53f03cb1d4Srmind {
54f03cb1d4Srmind 	extern int yyleng;
55f03cb1d4Srmind 	extern char *yytext;
56f03cb1d4Srmind 
577c0a5ca2Srmind 	char *msg, *context = estrndup(yytext, yyleng);
584e3d5046Srmind 	bool eol = (*context == '\n');
59f03cb1d4Srmind 	va_list ap;
60f03cb1d4Srmind 
61f03cb1d4Srmind 	va_start(ap, fmt);
62f03cb1d4Srmind 	vasprintf(&msg, fmt, ap);
63f03cb1d4Srmind 	va_end(ap);
64f03cb1d4Srmind 
654e3d5046Srmind 	fprintf(stderr, "%s:%d:%d: %s", yyfilename,
664e3d5046Srmind 	    yylineno - (int)eol, yycolumn, msg);
674e3d5046Srmind 	if (!eol) {
686c441296Srmind #ifdef __NetBSD__
694e3d5046Srmind 		size_t len = strlen(context);
703c7c5558Srmind 		char *dst = ecalloc(1, len * 4 + 1);
714e3d5046Srmind 
72f03cb1d4Srmind 		strvisx(dst, context, len, VIS_WHITE|VIS_CSTYLE);
73f0764fe1Skre 		context = dst;
746c441296Srmind #endif
756c441296Srmind 		fprintf(stderr, " near '%s'", context);
764e3d5046Srmind 	}
774e3d5046Srmind 	fprintf(stderr, "\n");
78f03cb1d4Srmind 	exit(EXIT_FAILURE);
79f03cb1d4Srmind }
80f03cb1d4Srmind 
81f03cb1d4Srmind %}
82f03cb1d4Srmind 
836f4ca96cSrmind /*
846f4ca96cSrmind  * No conflicts allowed.  Keep it this way.
856f4ca96cSrmind  */
866f4ca96cSrmind %expect 0
876f4ca96cSrmind %expect-rr 0
886f4ca96cSrmind 
89b05f1f8bSrmind /*
90b05f1f8bSrmind  * Depending on the mode of operation, set a different start symbol.
91b05f1f8bSrmind  * Workaround yacc limitation by passing the start token.
92b05f1f8bSrmind  */
93b05f1f8bSrmind %start input
94b05f1f8bSrmind %token RULE_ENTRY_TOKEN MAP_ENTRY_TOKEN
95b05f1f8bSrmind %lex-param { int yystarttoken }
96b05f1f8bSrmind 
97b05f1f8bSrmind /*
98b05f1f8bSrmind  * General tokens.
99b05f1f8bSrmind  */
1003b895110Schristos %token			ALG
101a894e3f7Srmind %token			ALGO
102f03cb1d4Srmind %token			ALL
103f03cb1d4Srmind %token			ANY
104f03cb1d4Srmind %token			APPLY
105add921fbSrmind %token			ARROWBOTH
106add921fbSrmind %token			ARROWLEFT
107add921fbSrmind %token			ARROWRIGHT
108f03cb1d4Srmind %token			BLOCK
109820aad11Srmind %token			CDB
1106f4ca96cSrmind %token			CONST
111f03cb1d4Srmind %token			CURLY_CLOSE
112f03cb1d4Srmind %token			CURLY_OPEN
113f03cb1d4Srmind %token			CODE
114f03cb1d4Srmind %token			COLON
115f03cb1d4Srmind %token			COMMA
116f03cb1d4Srmind %token			DEFAULT
117f03cb1d4Srmind %token			TDYNAMIC
118add921fbSrmind %token			TSTATIC
119f03cb1d4Srmind %token			EQ
12035bd148cSrmind %token			EXCL_MARK
121f03cb1d4Srmind %token			TFILE
122f03cb1d4Srmind %token			FLAGS
123f03cb1d4Srmind %token			FROM
124f03cb1d4Srmind %token			GROUP
125f03cb1d4Srmind %token			HASH
126f03cb1d4Srmind %token			ICMPTYPE
127f03cb1d4Srmind %token			ID
1286f4ca96cSrmind %token			IFADDRS
129f03cb1d4Srmind %token			IN
130348a4177Srmind %token			INET4
131f03cb1d4Srmind %token			INET6
132f03cb1d4Srmind %token			INTERFACE
133*d6939920Srmind %token			INVALID
1346f4ca96cSrmind %token			IPHASH
1356f4ca96cSrmind %token			IPSET
1366f4ca96cSrmind %token			LPM
137add921fbSrmind %token			MAP
138bf40bfa8Srmind %token			NO_PORTS
139f03cb1d4Srmind %token			MINUS
140f03cb1d4Srmind %token			NAME
1416f4ca96cSrmind %token			NETMAP
142a894e3f7Srmind %token			NPT66
143f03cb1d4Srmind %token			ON
14493bbacf8Schristos %token			OFF
145f03cb1d4Srmind %token			OUT
146f03cb1d4Srmind %token			PAR_CLOSE
147f03cb1d4Srmind %token			PAR_OPEN
148f03cb1d4Srmind %token			PASS
149c6e77e2aSrmind %token			PCAP_FILTER
150f03cb1d4Srmind %token			PORT
151f03cb1d4Srmind %token			PROCEDURE
152f03cb1d4Srmind %token			PROTO
153f03cb1d4Srmind %token			FAMILY
154ba11b3c0Srmind %token			FINAL
15537527ec6Srmind %token			FORW
156f03cb1d4Srmind %token			RETURN
157f03cb1d4Srmind %token			RETURNICMP
158f03cb1d4Srmind %token			RETURNRST
1596f4ca96cSrmind %token			ROUNDROBIN
1607b486642Srmind %token			RULESET
161f03cb1d4Srmind %token			SEPLINE
16293bbacf8Schristos %token			SET
163f03cb1d4Srmind %token			SLASH
164ba11b3c0Srmind %token			STATEFUL
1657e3fb338Srmind %token			STATEFUL_ALL
166f03cb1d4Srmind %token			TABLE
167f03cb1d4Srmind %token			TCP
168f03cb1d4Srmind %token			TO
169f03cb1d4Srmind %token			TREE
170f03cb1d4Srmind %token			TYPE
171afd9e22aSspz %token	<num>		ICMP
172afd9e22aSspz %token	<num>		ICMP6
173f03cb1d4Srmind 
174f03cb1d4Srmind %token	<num>		HEX
175f03cb1d4Srmind %token	<str>		IDENTIFIER
176f03cb1d4Srmind %token	<str>		IPV4ADDR
177f03cb1d4Srmind %token	<str>		IPV6ADDR
178f03cb1d4Srmind %token	<num>		NUM
17948a1ec7dSrmind %token	<fpnum>		FPNUM
180f03cb1d4Srmind %token	<str>		STRING
1817e3fb338Srmind %token	<str>		PARAM
182f03cb1d4Srmind %token	<str>		TABLE_ID
183f03cb1d4Srmind %token	<str>		VAR_ID
184f03cb1d4Srmind 
1856f4ca96cSrmind %type	<str>		addr some_name table_store dynamic_ifaddrs
1866f4ca96cSrmind %type	<str>		proc_param_val opt_apply ifname on_ifname ifref
1876f4ca96cSrmind %type	<num>		port opt_final number afamily opt_family
1886f4ca96cSrmind %type	<num>		block_or_pass rule_dir group_dir block_opts
1896f4ca96cSrmind %type	<num>		maybe_not opt_stateful icmp_type table_type
1906f4ca96cSrmind %type	<num>		map_sd map_algo map_flags map_type
1917e3fb338Srmind %type	<num>		param_val
192*d6939920Srmind %type	<var>		static_ifaddrs filt_addr_element
193*d6939920Srmind %type	<var>		filt_port filt_port_list port_range icmp_type_and_code
1946f4ca96cSrmind %type	<var>		filt_addr addr_and_mask tcp_flags tcp_flags_and_mask
1956f4ca96cSrmind %type	<var>		procs proc_call proc_param_list proc_param
196*d6939920Srmind %type	<var>		element list_elems list value filt_addr_list
197*d6939920Srmind %type	<var>		opt_proto proto proto_elems
198add921fbSrmind %type	<addrport>	mapseg
1996f4ca96cSrmind %type	<filtopts>	filt_opts all_or_filt_opts
200*d6939920Srmind %type	<optproto>	rawproto
201c6e77e2aSrmind %type	<rulegroup>	group_opts
202f03cb1d4Srmind 
203f03cb1d4Srmind %union {
204f03cb1d4Srmind 	char *		str;
205f03cb1d4Srmind 	unsigned long	num;
20648a1ec7dSrmind 	double		fpnum;
207ec3d0e07Srmind 	npfvar_t *	var;
208add921fbSrmind 	addr_port_t	addrport;
209f03cb1d4Srmind 	filt_opts_t	filtopts;
210f03cb1d4Srmind 	opt_proto_t	optproto;
211f03cb1d4Srmind 	rule_group_t	rulegroup;
212f03cb1d4Srmind }
213f03cb1d4Srmind 
214f03cb1d4Srmind %%
215f03cb1d4Srmind 
216f03cb1d4Srmind input
217b05f1f8bSrmind 	: lines
218b05f1f8bSrmind 	| RULE_ENTRY_TOKEN	rule
219b05f1f8bSrmind 	| MAP_ENTRY_TOKEN	map
220f03cb1d4Srmind 	;
221f03cb1d4Srmind 
222f03cb1d4Srmind lines
2239ff93001Sriastradh 	: lines SEPLINE line
224f03cb1d4Srmind 	| line
225f03cb1d4Srmind 	;
226f03cb1d4Srmind 
227f03cb1d4Srmind line
2288f6547d8Srmind 	: vardef
229f03cb1d4Srmind 	| table
230add921fbSrmind 	| map
231f03cb1d4Srmind 	| group
232f03cb1d4Srmind 	| rproc
2333b895110Schristos 	| alg
23493bbacf8Schristos 	| set
235f03cb1d4Srmind 	|
236f03cb1d4Srmind 	;
237f03cb1d4Srmind 
2388f6547d8Srmind alg
2398f6547d8Srmind 	: ALG STRING
2408f6547d8Srmind 	{
2418f6547d8Srmind 		npfctl_build_alg($2);
2428f6547d8Srmind 	}
2438f6547d8Srmind 	;
2448f6547d8Srmind 
2457e3fb338Srmind param_val
2467e3fb338Srmind 	: number	{ $$ = $1; }
2477e3fb338Srmind 	| ON		{ $$ = true; }
2487e3fb338Srmind 	| OFF		{ $$ = false; }
24993bbacf8Schristos 	;
25093bbacf8Schristos 
25193bbacf8Schristos set
2527e3fb338Srmind 	: SET PARAM param_val {
2537e3fb338Srmind 		npfctl_setparam($2, $3);
25493bbacf8Schristos 	}
25593bbacf8Schristos 	;
25693bbacf8Schristos 
2578f6547d8Srmind /*
2588f6547d8Srmind  * A value - an element or a list of elements.
2598f6547d8Srmind  * Can be assigned to a variable or used inline.
2608f6547d8Srmind  */
2618f6547d8Srmind 
2628f6547d8Srmind vardef
263348a4177Srmind 	: VAR_ID EQ value
264f03cb1d4Srmind 	{
265348a4177Srmind 		npfvar_add($3, $1);
266f03cb1d4Srmind 	}
267f03cb1d4Srmind 	;
268f03cb1d4Srmind 
2698f6547d8Srmind value
2708f6547d8Srmind 	: element
2718f6547d8Srmind 	| list
272f03cb1d4Srmind 	;
273f03cb1d4Srmind 
2748f6547d8Srmind list
275f03cb1d4Srmind 	: CURLY_OPEN list_elems CURLY_CLOSE
276348a4177Srmind 	{
277348a4177Srmind 		$$ = $2;
278348a4177Srmind 	}
279f03cb1d4Srmind 	;
280f03cb1d4Srmind 
281f03cb1d4Srmind list_elems
2829ff93001Sriastradh 	: list_elems COMMA element
283348a4177Srmind 	{
284348a4177Srmind 		npfvar_add_elements($1, $3);
285348a4177Srmind 	}
2868f6547d8Srmind 	| element
287f03cb1d4Srmind 	;
288f03cb1d4Srmind 
2898f6547d8Srmind element
290f03cb1d4Srmind 	: IDENTIFIER
291f03cb1d4Srmind 	{
292348a4177Srmind 		$$ = npfvar_create_from_string(NPFVAR_IDENTIFIER, $1);
293f03cb1d4Srmind 	}
294f03cb1d4Srmind 	| STRING
295f03cb1d4Srmind 	{
296348a4177Srmind 		$$ = npfvar_create_from_string(NPFVAR_STRING, $1);
297f03cb1d4Srmind 	}
298f2174d83Schristos 	| number MINUS number
299ff24200fSchristos 	{
300348a4177Srmind 		$$ = npfctl_parse_port_range($1, $3);
301ff24200fSchristos 	}
302f2174d83Schristos 	| number
303f03cb1d4Srmind 	{
304348a4177Srmind 		$$ = npfvar_create_element(NPFVAR_NUM, &$1, sizeof($1));
305f03cb1d4Srmind 	}
306f03cb1d4Srmind 	| VAR_ID
307f03cb1d4Srmind 	{
308348a4177Srmind 		$$ = npfvar_create_from_string(NPFVAR_VAR_ID, $1);
309f03cb1d4Srmind 	}
310348a4177Srmind 	| TABLE_ID		{ $$ = npfctl_parse_table_id($1); }
311df8b1943Srmind 	| dynamic_ifaddrs	{ $$ = npfctl_ifnet_table($1); }
312df8b1943Srmind 	| static_ifaddrs	{ $$ = $1; }
313348a4177Srmind 	| addr_and_mask		{ $$ = $1; }
314f03cb1d4Srmind 	;
315f03cb1d4Srmind 
3168f6547d8Srmind /*
3178f6547d8Srmind  * Table definition.
3188f6547d8Srmind  */
3198f6547d8Srmind 
320f03cb1d4Srmind table
321f03cb1d4Srmind 	: TABLE TABLE_ID TYPE table_type table_store
322f03cb1d4Srmind 	{
323f03cb1d4Srmind 		npfctl_build_table($2, $4, $5);
324f03cb1d4Srmind 	}
325f03cb1d4Srmind 	;
326f03cb1d4Srmind 
327f03cb1d4Srmind table_type
3286f4ca96cSrmind 	: IPSET		{ $$ = NPF_TABLE_IPSET; }
3296f4ca96cSrmind 	| HASH
3306f4ca96cSrmind 	{
3316f4ca96cSrmind 		warnx("warning - table type \"hash\" is deprecated and may be "
3326f4ca96cSrmind 		    "deleted in\nthe future; please use the \"ipset\" type "
3336f4ca96cSrmind 		    "instead.");
3346f4ca96cSrmind 		$$ = NPF_TABLE_IPSET;
3356f4ca96cSrmind 	}
3366f4ca96cSrmind 	| LPM		{ $$ = NPF_TABLE_LPM; }
3376f4ca96cSrmind 	| TREE
3386f4ca96cSrmind 	{
3396f4ca96cSrmind 		warnx("warning - table type \"tree\" is deprecated and may be "
3406f4ca96cSrmind 		    "deleted in\nthe future; please use the \"lpm\" type "
3416f4ca96cSrmind 		    "instead.");
3426f4ca96cSrmind 		$$ = NPF_TABLE_LPM;
3436f4ca96cSrmind 	}
3446f4ca96cSrmind 	| CONST		{ $$ = NPF_TABLE_CONST; }
3456f4ca96cSrmind 	| CDB
3466f4ca96cSrmind 	{
3476f4ca96cSrmind 		warnx("warning -- table type \"cdb\" is deprecated and may be "
3486f4ca96cSrmind 		    "deleted in\nthe future; please use the \"const\" type "
3496f4ca96cSrmind 		    "instead.");
3506f4ca96cSrmind 		$$ = NPF_TABLE_CONST;
3516f4ca96cSrmind 	}
352f03cb1d4Srmind 	;
353f03cb1d4Srmind 
354f03cb1d4Srmind table_store
3556f4ca96cSrmind 	: TFILE STRING	{ $$ = $2; }
3566f4ca96cSrmind 	| TDYNAMIC
3576f4ca96cSrmind 	{
3586f4ca96cSrmind 		warnx("warning - the \"dynamic\" keyword for tables is obsolete");
3596f4ca96cSrmind 		$$ = NULL;
3606f4ca96cSrmind 	}
3616f4ca96cSrmind 	|		{ $$ = NULL; }
362f03cb1d4Srmind 	;
363f03cb1d4Srmind 
3648f6547d8Srmind /*
3658f6547d8Srmind  * Map definition.
3668f6547d8Srmind  */
3678f6547d8Srmind 
368add921fbSrmind map_sd
369add921fbSrmind 	: TSTATIC	{ $$ = NPFCTL_NAT_STATIC; }
370add921fbSrmind 	| TDYNAMIC	{ $$ = NPFCTL_NAT_DYNAMIC; }
371add921fbSrmind 	|		{ $$ = NPFCTL_NAT_DYNAMIC; }
372f03cb1d4Srmind 	;
373f03cb1d4Srmind 
374a894e3f7Srmind map_algo
3756f4ca96cSrmind 	: ALGO NETMAP		{ $$ = NPF_ALGO_NETMAP; }
3766f4ca96cSrmind 	| ALGO IPHASH		{ $$ = NPF_ALGO_IPHASH; }
3776f4ca96cSrmind 	| ALGO ROUNDROBIN	{ $$ = NPF_ALGO_RR; }
3786f4ca96cSrmind 	| ALGO NPT66		{ $$ = NPF_ALGO_NPT66; }
379a894e3f7Srmind 	|			{ $$ = 0; }
380a894e3f7Srmind 	;
381a894e3f7Srmind 
382bf40bfa8Srmind map_flags
383bf40bfa8Srmind 	: NO_PORTS	{ $$ = NPF_NAT_PORTS; }
384bf40bfa8Srmind 	|		{ $$ = 0; }
385bf40bfa8Srmind 	;
386bf40bfa8Srmind 
387add921fbSrmind map_type
388add921fbSrmind 	: ARROWBOTH	{ $$ = NPF_NATIN | NPF_NATOUT; }
389add921fbSrmind 	| ARROWLEFT	{ $$ = NPF_NATIN; }
390add921fbSrmind 	| ARROWRIGHT	{ $$ = NPF_NATOUT; }
391add921fbSrmind 	;
392add921fbSrmind 
393add921fbSrmind mapseg
394*d6939920Srmind 	: filt_addr filt_port
395f03cb1d4Srmind 	{
396add921fbSrmind 		$$.ap_netaddr = $1;
397add921fbSrmind 		$$.ap_portrange = $2;
398f03cb1d4Srmind 	}
399f03cb1d4Srmind 	;
400f03cb1d4Srmind 
401add921fbSrmind map
402bf40bfa8Srmind 	: MAP ifref map_sd map_algo map_flags mapseg map_type mapseg
4036f4ca96cSrmind 	  PASS opt_family opt_proto all_or_filt_opts
404f03cb1d4Srmind 	{
405*d6939920Srmind 		npfctl_build_natseg($3, $7, $5, $2, &$6, &$8, $11, &$12, $4);
406f03cb1d4Srmind 	}
407bf40bfa8Srmind 	| MAP ifref map_sd map_algo map_flags mapseg map_type mapseg
408a6f5b6a3Srmind 	{
409bf40bfa8Srmind 		npfctl_build_natseg($3, $7, $5, $2, &$6, &$8, NULL, NULL, $4);
410a6f5b6a3Srmind 	}
411bf40bfa8Srmind 	| MAP ifref map_sd map_algo map_flags proto mapseg map_type mapseg
412f03cb1d4Srmind 	{
413*d6939920Srmind 		npfctl_build_natseg($3, $8, $5, $2, &$7, &$9, $6, NULL, $4);
414f03cb1d4Srmind 	}
415c6e77e2aSrmind 	| MAP RULESET group_opts
4167b486642Srmind 	{
417d1d2e2c9Srmind 		npfctl_build_maprset($3.rg_name, $3.rg_attr, $3.rg_ifname);
4187b486642Srmind 	}
419f03cb1d4Srmind 	;
420f03cb1d4Srmind 
4218f6547d8Srmind /*
4228f6547d8Srmind  * Rule procedure definition and its parameters.
4238f6547d8Srmind  */
4248f6547d8Srmind 
425f03cb1d4Srmind rproc
426f03cb1d4Srmind 	: PROCEDURE STRING CURLY_OPEN procs CURLY_CLOSE
427f03cb1d4Srmind 	{
428f03cb1d4Srmind 		npfctl_build_rproc($2, $4);
429f03cb1d4Srmind 	}
430f03cb1d4Srmind 	;
431f03cb1d4Srmind 
432f03cb1d4Srmind procs
4339ff93001Sriastradh 	: procs SEPLINE proc_call
434f03cb1d4Srmind 	{
435f03cb1d4Srmind 		$$ = npfvar_add_elements($1, $3);
436f03cb1d4Srmind 	}
43748a1ec7dSrmind 	| proc_call	{ $$ = $1; }
43848a1ec7dSrmind 	;
43948a1ec7dSrmind 
44048a1ec7dSrmind proc_call
44148a1ec7dSrmind 	: IDENTIFIER COLON proc_param_list
44248a1ec7dSrmind 	{
44348a1ec7dSrmind 		proc_call_t pc;
44448a1ec7dSrmind 
4457c0a5ca2Srmind 		pc.pc_name = estrdup($1);
44648a1ec7dSrmind 		pc.pc_opts = $3;
447348a4177Srmind 
448348a4177Srmind 		$$ = npfvar_create_element(NPFVAR_PROC, &pc, sizeof(pc));
44948a1ec7dSrmind 	}
450f03cb1d4Srmind 	|		{ $$ = NULL; }
451f03cb1d4Srmind 	;
452f03cb1d4Srmind 
45348a1ec7dSrmind proc_param_list
4549ff93001Sriastradh 	: proc_param_list COMMA proc_param
455f03cb1d4Srmind 	{
45648a1ec7dSrmind 		$$ = npfvar_add_elements($1, $3);
45748a1ec7dSrmind 	}
45848a1ec7dSrmind 	| proc_param	{ $$ = $1; }
45948a1ec7dSrmind 	|		{ $$ = NULL; }
46048a1ec7dSrmind 	;
461f03cb1d4Srmind 
46248a1ec7dSrmind proc_param
46348a1ec7dSrmind 	: some_name proc_param_val
46448a1ec7dSrmind 	{
46548a1ec7dSrmind 		proc_param_t pp;
46648a1ec7dSrmind 
4677c0a5ca2Srmind 		pp.pp_param = estrdup($1);
4687c0a5ca2Srmind 		pp.pp_value = $2 ? estrdup($2) : NULL;
469348a4177Srmind 
470348a4177Srmind 		$$ = npfvar_create_element(NPFVAR_PROC_PARAM, &pp, sizeof(pp));
471f03cb1d4Srmind 	}
472f03cb1d4Srmind 	;
473f03cb1d4Srmind 
47448a1ec7dSrmind proc_param_val
47548a1ec7dSrmind 	: some_name	{ $$ = $1; }
476f2174d83Schristos 	| number	{ (void)asprintf(&$$, "%ld", $1); }
47748a1ec7dSrmind 	| FPNUM		{ (void)asprintf(&$$, "%lf", $1); }
478f03cb1d4Srmind 	|		{ $$ = NULL; }
479f03cb1d4Srmind 	;
480f03cb1d4Srmind 
4818f6547d8Srmind /*
4828f6547d8Srmind  * Group and dynamic ruleset definition.
4838f6547d8Srmind  */
4848f6547d8Srmind 
485f03cb1d4Srmind group
486c6e77e2aSrmind 	: GROUP group_opts
487f03cb1d4Srmind 	{
488348a4177Srmind 		/* Build a group.  Increase the nesting level. */
489c6e77e2aSrmind 		npfctl_build_group($2.rg_name, $2.rg_attr,
490d1d2e2c9Srmind 		    $2.rg_ifname, $2.rg_default);
491f03cb1d4Srmind 	}
49237527ec6Srmind 	  ruleset_block
49337527ec6Srmind 	{
49437527ec6Srmind 		/* Decrease the nesting level. */
49537527ec6Srmind 		npfctl_build_group_end();
49637527ec6Srmind 	}
497f03cb1d4Srmind 	;
498f03cb1d4Srmind 
4997b486642Srmind ruleset
500c6e77e2aSrmind 	: RULESET group_opts
5017b486642Srmind 	{
5027b486642Srmind 		/* Ruleset is a dynamic group. */
503c6e77e2aSrmind 		npfctl_build_group($2.rg_name, $2.rg_attr | NPF_RULE_DYNAMIC,
504d1d2e2c9Srmind 		    $2.rg_ifname, $2.rg_default);
5057b486642Srmind 		npfctl_build_group_end();
5067b486642Srmind 	}
507f03cb1d4Srmind 	;
508f03cb1d4Srmind 
509c6e77e2aSrmind group_dir
510c6e77e2aSrmind 	: FORW		{ $$ = NPF_RULE_FORW; }
511c6e77e2aSrmind 	| rule_dir
512c6e77e2aSrmind 	;
513c6e77e2aSrmind 
514c6e77e2aSrmind group_opts
515f03cb1d4Srmind 	: DEFAULT
516f03cb1d4Srmind 	{
51737527ec6Srmind 		memset(&$$, 0, sizeof(rule_group_t));
51837527ec6Srmind 		$$.rg_default = true;
519f03cb1d4Srmind 	}
520d1d2e2c9Srmind 	| STRING group_dir on_ifname
521f03cb1d4Srmind 	{
52237527ec6Srmind 		memset(&$$, 0, sizeof(rule_group_t));
523c6e77e2aSrmind 		$$.rg_name = $1;
524c6e77e2aSrmind 		$$.rg_attr = $2;
525d1d2e2c9Srmind 		$$.rg_ifname = $3;
526f03cb1d4Srmind 	}
527f03cb1d4Srmind 	;
528f03cb1d4Srmind 
52937527ec6Srmind ruleset_block
5307b486642Srmind 	: CURLY_OPEN ruleset_def CURLY_CLOSE
531f03cb1d4Srmind 	;
532f03cb1d4Srmind 
5337b486642Srmind ruleset_def
5349ff93001Sriastradh 	: ruleset_def SEPLINE rule_group
53537527ec6Srmind 	| rule_group
536f03cb1d4Srmind 	;
537f03cb1d4Srmind 
53837527ec6Srmind rule_group
53937527ec6Srmind 	: rule
54037527ec6Srmind 	| group
5417b486642Srmind 	| ruleset
54237527ec6Srmind 	|
54385aa89dfSrmind 	;
54437527ec6Srmind 
5458f6547d8Srmind /*
5468f6547d8Srmind  * Rule and misc.
5478f6547d8Srmind  */
5488f6547d8Srmind 
549f03cb1d4Srmind rule
550d1d2e2c9Srmind 	: block_or_pass opt_stateful rule_dir opt_final on_ifname
551ec3d0e07Srmind 	  opt_family opt_proto all_or_filt_opts opt_apply
552f03cb1d4Srmind 	{
553ba11b3c0Srmind 		npfctl_build_rule($1 | $2 | $3 | $4, $5,
554*d6939920Srmind 		    $6, $7, &$8, NULL, $9);
555c6e77e2aSrmind 	}
556d1d2e2c9Srmind 	| block_or_pass opt_stateful rule_dir opt_final on_ifname
557c6e77e2aSrmind 	  PCAP_FILTER STRING opt_apply
558c6e77e2aSrmind 	{
559c6e77e2aSrmind 		npfctl_build_rule($1 | $2 | $3 | $4, $5,
560c6e77e2aSrmind 		    AF_UNSPEC, NULL, NULL, $7, $8);
561f03cb1d4Srmind 	}
562f03cb1d4Srmind 	;
563f03cb1d4Srmind 
564f03cb1d4Srmind block_or_pass
565f03cb1d4Srmind 	: BLOCK block_opts	{ $$ = $2; }
566f03cb1d4Srmind 	| PASS			{ $$ = NPF_RULE_PASS; }
567f03cb1d4Srmind 	;
568f03cb1d4Srmind 
569f03cb1d4Srmind rule_dir
570f03cb1d4Srmind 	: IN			{ $$ = NPF_RULE_IN; }
571f03cb1d4Srmind 	| OUT			{ $$ = NPF_RULE_OUT; }
572f03cb1d4Srmind 	|			{ $$ = NPF_RULE_IN | NPF_RULE_OUT; }
573f03cb1d4Srmind 	;
574f03cb1d4Srmind 
575ba11b3c0Srmind opt_final
576ba11b3c0Srmind 	: FINAL			{ $$ = NPF_RULE_FINAL; }
577f03cb1d4Srmind 	|			{ $$ = 0; }
578f03cb1d4Srmind 	;
579f03cb1d4Srmind 
580d1d2e2c9Srmind on_ifname
581348a4177Srmind 	: ON ifref		{ $$ = $2; }
582d1d2e2c9Srmind 	|			{ $$ = NULL; }
583f03cb1d4Srmind 	;
584f03cb1d4Srmind 
585ec3d0e07Srmind afamily
586348a4177Srmind 	: INET4			{ $$ = AF_INET; }
587ec3d0e07Srmind 	| INET6			{ $$ = AF_INET6; }
588ec3d0e07Srmind 	;
589ec3d0e07Srmind 
59035bd148cSrmind maybe_not
59135bd148cSrmind 	: EXCL_MARK		{ $$ = true; }
59235bd148cSrmind 	|			{ $$ = false; }
59335bd148cSrmind 	;
59435bd148cSrmind 
595f75d4435Srmind opt_family
596ec3d0e07Srmind 	: FAMILY afamily	{ $$ = $2; }
597f75d4435Srmind 	|			{ $$ = AF_UNSPEC; }
598f03cb1d4Srmind 	;
599f03cb1d4Srmind 
600*d6939920Srmind rawproto
601*d6939920Srmind 	: TCP tcp_flags_and_mask
602f03cb1d4Srmind 	{
603f03cb1d4Srmind 		$$.op_proto = IPPROTO_TCP;
604*d6939920Srmind 		$$.op_opts = $2;
605f03cb1d4Srmind 	}
606*d6939920Srmind 	| ICMP icmp_type_and_code
607f03cb1d4Srmind 	{
608f03cb1d4Srmind 		$$.op_proto = IPPROTO_ICMP;
609*d6939920Srmind 		$$.op_opts = $2;
610f03cb1d4Srmind 	}
611*d6939920Srmind 	| ICMP6 icmp_type_and_code
612afd9e22aSspz 	{
613afd9e22aSspz 		$$.op_proto = IPPROTO_ICMPV6;
614*d6939920Srmind 		$$.op_opts = $2;
615afd9e22aSspz 	}
616*d6939920Srmind 	| some_name
617f03cb1d4Srmind 	{
618*d6939920Srmind 		$$.op_proto = npfctl_protono($1);
619f75d4435Srmind 		$$.op_opts = NULL;
620f75d4435Srmind 	}
621*d6939920Srmind 	| number
622f75d4435Srmind 	{
623*d6939920Srmind 		$$.op_proto = $1;
624f03cb1d4Srmind 		$$.op_opts = NULL;
625f03cb1d4Srmind 	}
626a6f5b6a3Srmind 	;
627a6f5b6a3Srmind 
628*d6939920Srmind proto_elems
629*d6939920Srmind 	: proto_elems COMMA rawproto
630*d6939920Srmind 	{
631*d6939920Srmind 		npfvar_t *pvar = npfvar_create_element(
632*d6939920Srmind 		    NPFVAR_PROTO, &$3, sizeof($3));
633*d6939920Srmind 		$$ = npfvar_add_elements($1, pvar);
634*d6939920Srmind 	}
635*d6939920Srmind 	| rawproto
636*d6939920Srmind 	{
637*d6939920Srmind 		$$ = npfvar_create_element(NPFVAR_PROTO, &$1, sizeof($1));
638*d6939920Srmind 	}
639*d6939920Srmind 	;
640*d6939920Srmind 
641*d6939920Srmind proto
642*d6939920Srmind 	: PROTO rawproto
643*d6939920Srmind 	{
644*d6939920Srmind 		$$ = npfvar_create_element(NPFVAR_PROTO, &$2, sizeof($2));
645*d6939920Srmind 	}
646*d6939920Srmind 	| PROTO CURLY_OPEN proto_elems CURLY_CLOSE
647*d6939920Srmind 	{
648*d6939920Srmind 		$$ = $3;
649*d6939920Srmind 	}
650*d6939920Srmind 	;
651*d6939920Srmind 
652a6f5b6a3Srmind opt_proto
653a6f5b6a3Srmind 	: proto			{ $$ = $1; }
654*d6939920Srmind 	|			{ $$ = NULL; }
655f03cb1d4Srmind 	;
656f03cb1d4Srmind 
657f03cb1d4Srmind all_or_filt_opts
658f03cb1d4Srmind 	: ALL
659f03cb1d4Srmind 	{
66035bd148cSrmind 		$$.fo_finvert = false;
661add921fbSrmind 		$$.fo_from.ap_netaddr = NULL;
662add921fbSrmind 		$$.fo_from.ap_portrange = NULL;
66335bd148cSrmind 		$$.fo_tinvert = false;
664add921fbSrmind 		$$.fo_to.ap_netaddr = NULL;
665add921fbSrmind 		$$.fo_to.ap_portrange = NULL;
666f03cb1d4Srmind 	}
667f03cb1d4Srmind 	| filt_opts	{ $$ = $1; }
668f03cb1d4Srmind 	;
669f03cb1d4Srmind 
670ba11b3c0Srmind opt_stateful
671f75d4435Srmind 	: STATEFUL	{ $$ = NPF_RULE_STATEFUL; }
6727e3fb338Srmind 	| STATEFUL_ALL	{ $$ = NPF_RULE_STATEFUL | NPF_RULE_GSTATEFUL; }
673f03cb1d4Srmind 	|		{ $$ = 0; }
674f03cb1d4Srmind 	;
675f03cb1d4Srmind 
676f03cb1d4Srmind opt_apply
677f03cb1d4Srmind 	: APPLY STRING	{ $$ = $2; }
678f03cb1d4Srmind 	|		{ $$ = NULL; }
679f03cb1d4Srmind 	;
680f03cb1d4Srmind 
681f03cb1d4Srmind block_opts
682f03cb1d4Srmind 	: RETURNRST	{ $$ = NPF_RULE_RETRST; }
683f03cb1d4Srmind 	| RETURNICMP	{ $$ = NPF_RULE_RETICMP; }
684f03cb1d4Srmind 	| RETURN	{ $$ = NPF_RULE_RETRST | NPF_RULE_RETICMP; }
685f03cb1d4Srmind 	|		{ $$ = 0; }
686f03cb1d4Srmind 	;
687f03cb1d4Srmind 
688f03cb1d4Srmind filt_opts
689*d6939920Srmind 	: FROM maybe_not filt_addr filt_port TO maybe_not filt_addr filt_port
690f03cb1d4Srmind 	{
69135bd148cSrmind 		$$.fo_finvert = $2;
69235bd148cSrmind 		$$.fo_from.ap_netaddr = $3;
69335bd148cSrmind 		$$.fo_from.ap_portrange = $4;
69435bd148cSrmind 		$$.fo_tinvert = $6;
69535bd148cSrmind 		$$.fo_to.ap_netaddr = $7;
69635bd148cSrmind 		$$.fo_to.ap_portrange = $8;
697f03cb1d4Srmind 	}
698*d6939920Srmind 	| FROM maybe_not filt_addr filt_port
699f03cb1d4Srmind 	{
70035bd148cSrmind 		$$.fo_finvert = $2;
70135bd148cSrmind 		$$.fo_from.ap_netaddr = $3;
70235bd148cSrmind 		$$.fo_from.ap_portrange = $4;
70335bd148cSrmind 		$$.fo_tinvert = false;
704add921fbSrmind 		$$.fo_to.ap_netaddr = NULL;
705add921fbSrmind 		$$.fo_to.ap_portrange = NULL;
706f03cb1d4Srmind 	}
707*d6939920Srmind 	| TO maybe_not filt_addr filt_port
708f03cb1d4Srmind 	{
70935bd148cSrmind 		$$.fo_finvert = false;
710add921fbSrmind 		$$.fo_from.ap_netaddr = NULL;
711add921fbSrmind 		$$.fo_from.ap_portrange = NULL;
71235bd148cSrmind 		$$.fo_tinvert = $2;
71335bd148cSrmind 		$$.fo_to.ap_netaddr = $3;
71435bd148cSrmind 		$$.fo_to.ap_portrange = $4;
715f03cb1d4Srmind 	}
716f03cb1d4Srmind 	;
717f03cb1d4Srmind 
718*d6939920Srmind filt_addr_list
719*d6939920Srmind 	: filt_addr_list COMMA filt_addr_element
720*d6939920Srmind 	{
721*d6939920Srmind 		npfvar_add_elements($1, $3);
722*d6939920Srmind 	}
723*d6939920Srmind 	| filt_addr_element
724*d6939920Srmind 	;
725*d6939920Srmind 
726f03cb1d4Srmind filt_addr
727*d6939920Srmind 	: CURLY_OPEN filt_addr_list CURLY_CLOSE
728*d6939920Srmind 	{
729*d6939920Srmind 		$$ = $2;
730*d6939920Srmind 	}
731*d6939920Srmind 	| filt_addr_element	{ $$ = $1; }
732f03cb1d4Srmind 	| ANY			{ $$ = NULL; }
733f03cb1d4Srmind 	;
734f03cb1d4Srmind 
735f03cb1d4Srmind addr_and_mask
736f2174d83Schristos 	: addr SLASH number
737f03cb1d4Srmind 	{
738f03cb1d4Srmind 		$$ = npfctl_parse_fam_addr_mask($1, NULL, &$3);
739f03cb1d4Srmind 	}
740f03cb1d4Srmind 	| addr SLASH addr
741f03cb1d4Srmind 	{
742f03cb1d4Srmind 		$$ = npfctl_parse_fam_addr_mask($1, $3, NULL);
743f03cb1d4Srmind 	}
744f03cb1d4Srmind 	| addr
745f03cb1d4Srmind 	{
746f03cb1d4Srmind 		$$ = npfctl_parse_fam_addr_mask($1, NULL, NULL);
747f03cb1d4Srmind 	}
748f03cb1d4Srmind 	;
749f03cb1d4Srmind 
750*d6939920Srmind filt_addr_element
7516f4ca96cSrmind 	: addr_and_mask		{ assert($1 != NULL); $$ = $1; }
752df8b1943Srmind 	| static_ifaddrs
7538094cc3dSrmind 	{
7545a32644fSchristos 		if (npfvar_get_count($1) != 1)
7555a32644fSchristos 			yyerror("multiple interfaces are not supported");
756ec3d0e07Srmind 		ifnet_addr_t *ifna = npfvar_get_data($1, NPFVAR_INTERFACE, 0);
757ec3d0e07Srmind 		$$ = ifna->ifna_addrs;
7588094cc3dSrmind 	}
7596f4ca96cSrmind 	| dynamic_ifaddrs	{ $$ = npfctl_ifnet_table($1); }
7606f4ca96cSrmind 	| TABLE_ID		{ $$ = npfctl_parse_table_id($1); }
7618094cc3dSrmind 	| VAR_ID
7628094cc3dSrmind 	{
7638094cc3dSrmind 		npfvar_t *vp = npfvar_lookup($1);
764f0ae964eSchristos 		int type = npfvar_get_type(vp, 0);
765ec3d0e07Srmind 		ifnet_addr_t *ifna;
766f0ae964eSchristos again:
7678094cc3dSrmind 		switch (type) {
768f0ae964eSchristos 		case NPFVAR_IDENTIFIER:
769f0ae964eSchristos 		case NPFVAR_STRING:
770f0ae964eSchristos 			vp = npfctl_parse_ifnet(npfvar_expand_string(vp),
771f0ae964eSchristos 			    AF_UNSPEC);
772f0ae964eSchristos 			type = npfvar_get_type(vp, 0);
773f0ae964eSchristos 			goto again;
7748094cc3dSrmind 		case NPFVAR_FAM:
775df8b1943Srmind 		case NPFVAR_TABLE:
7768094cc3dSrmind 			$$ = vp;
7778094cc3dSrmind 			break;
778ec3d0e07Srmind 		case NPFVAR_INTERFACE:
77915718026Srmind 			$$ = NULL;
78015718026Srmind 			for (u_int i = 0; i < npfvar_get_count(vp); i++) {
78115718026Srmind 				ifna = npfvar_get_data(vp, type, i);
78215718026Srmind 				$$ = npfvar_add_elements($$, ifna->ifna_addrs);
78315718026Srmind 			}
784ec3d0e07Srmind 			break;
7858094cc3dSrmind 		case -1:
786ec3d0e07Srmind 			yyerror("undefined variable '%s'", $1);
7878094cc3dSrmind 			break;
7888094cc3dSrmind 		default:
789ec3d0e07Srmind 			yyerror("wrong variable '%s' type '%s' for address "
790ec3d0e07Srmind 			    "or interface", $1, npfvar_type(type));
7918094cc3dSrmind 			break;
7928094cc3dSrmind 		}
7938094cc3dSrmind 	}
794f03cb1d4Srmind 	;
795f03cb1d4Srmind 
796f03cb1d4Srmind addr
797f03cb1d4Srmind 	: IPV4ADDR	{ $$ = $1; }
798f03cb1d4Srmind 	| IPV6ADDR	{ $$ = $1; }
799f03cb1d4Srmind 	;
800f03cb1d4Srmind 
801*d6939920Srmind filt_port
802*d6939920Srmind 	: PORT CURLY_OPEN filt_port_list CURLY_CLOSE
803f03cb1d4Srmind 	{
804*d6939920Srmind 		$$ = npfctl_parse_port_range_variable(NULL, $3);
805f03cb1d4Srmind 	}
806*d6939920Srmind 	| PORT port_range	{ $$ = $2; }
8076c441296Srmind 	|			{ $$ = NULL; }
808f03cb1d4Srmind 	;
809f03cb1d4Srmind 
810*d6939920Srmind filt_port_list
811*d6939920Srmind 	: filt_port_list COMMA port_range
812*d6939920Srmind 	{
813*d6939920Srmind 		npfvar_add_elements($1, $3);
814*d6939920Srmind 	}
815*d6939920Srmind 	| port_range
816*d6939920Srmind 	;
817*d6939920Srmind 
818*d6939920Srmind port_range
819*d6939920Srmind 	: port		/* just port */
820*d6939920Srmind 	{
821*d6939920Srmind 		$$ = npfctl_parse_port_range($1, $1);
822*d6939920Srmind 	}
823*d6939920Srmind 	| port MINUS port	/* port from-to */
824*d6939920Srmind 	{
825*d6939920Srmind 		$$ = npfctl_parse_port_range($1, $3);
826*d6939920Srmind 	}
827*d6939920Srmind 	| VAR_ID
828*d6939920Srmind 	{
829*d6939920Srmind 		npfvar_t *vp = npfvar_lookup($1);
830*d6939920Srmind 		$$ = npfctl_parse_port_range_variable($1, vp);
831*d6939920Srmind 	}
832*d6939920Srmind 	;
833*d6939920Srmind 
834f03cb1d4Srmind port
835f2174d83Schristos 	: number	{ $$ = $1; }
836f03cb1d4Srmind 	| IDENTIFIER	{ $$ = npfctl_portno($1); }
837bd928debSchristos 	| STRING	{ $$ = npfctl_portno($1); }
838f03cb1d4Srmind 	;
839f03cb1d4Srmind 
840f03cb1d4Srmind icmp_type_and_code
841f03cb1d4Srmind 	: ICMPTYPE icmp_type
842f03cb1d4Srmind 	{
843afd9e22aSspz 		$$ = npfctl_parse_icmp($<num>0, $2, -1);
844f03cb1d4Srmind 	}
845f2174d83Schristos 	| ICMPTYPE icmp_type CODE number
846f03cb1d4Srmind 	{
847afd9e22aSspz 		$$ = npfctl_parse_icmp($<num>0, $2, $4);
848f03cb1d4Srmind 	}
849f03cb1d4Srmind 	| ICMPTYPE icmp_type CODE IDENTIFIER
850f03cb1d4Srmind 	{
851ec3d0e07Srmind 		$$ = npfctl_parse_icmp($<num>0, $2,
852ec3d0e07Srmind 		    npfctl_icmpcode($<num>0, $2, $4));
853f03cb1d4Srmind 	}
854f03cb1d4Srmind 	| ICMPTYPE icmp_type CODE VAR_ID
855f03cb1d4Srmind 	{
856f03cb1d4Srmind 		char *s = npfvar_expand_string(npfvar_lookup($4));
857ec3d0e07Srmind 		$$ = npfctl_parse_icmp($<num>0, $2,
858ec3d0e07Srmind 		    npfctl_icmpcode($<num>0, $2, s));
859f03cb1d4Srmind 	}
86011243735Srmind 	|		{ $$ = NULL; }
861f03cb1d4Srmind 	;
862f03cb1d4Srmind 
863f03cb1d4Srmind tcp_flags_and_mask
864f03cb1d4Srmind 	: FLAGS tcp_flags SLASH tcp_flags
865f03cb1d4Srmind 	{
866f03cb1d4Srmind 		npfvar_add_elements($2, $4);
867f03cb1d4Srmind 		$$ = $2;
868f03cb1d4Srmind 	}
869f03cb1d4Srmind 	| FLAGS tcp_flags
870f03cb1d4Srmind 	{
8715a32644fSchristos 		if (npfvar_get_count($2) != 1)
8725a32644fSchristos 			yyerror("multiple tcpflags are not supported");
873f03cb1d4Srmind 		char *s = npfvar_get_data($2, NPFVAR_TCPFLAG, 0);
874f03cb1d4Srmind 		npfvar_add_elements($2, npfctl_parse_tcpflag(s));
875f03cb1d4Srmind 		$$ = $2;
876f03cb1d4Srmind 	}
877f03cb1d4Srmind 	|		{ $$ = NULL; }
878f03cb1d4Srmind 	;
879f03cb1d4Srmind 
880f03cb1d4Srmind tcp_flags
881f03cb1d4Srmind 	: IDENTIFIER	{ $$ = npfctl_parse_tcpflag($1); }
882f03cb1d4Srmind 	;
883f03cb1d4Srmind 
884f03cb1d4Srmind icmp_type
885f2174d83Schristos 	: number	{ $$ = $1; }
886afd9e22aSspz 	| IDENTIFIER	{ $$ = npfctl_icmptype($<num>-1, $1); }
887f03cb1d4Srmind 	| VAR_ID
888f03cb1d4Srmind 	{
889f03cb1d4Srmind 		char *s = npfvar_expand_string(npfvar_lookup($1));
890afd9e22aSspz 		$$ = npfctl_icmptype($<num>-1, s);
891f03cb1d4Srmind 	}
892f03cb1d4Srmind 	;
893f03cb1d4Srmind 
894d1d2e2c9Srmind ifname
895f75d4435Srmind 	: some_name
896f03cb1d4Srmind 	{
897d1d2e2c9Srmind 		npfctl_note_interface($1);
898d1d2e2c9Srmind 		$$ = $1;
899f03cb1d4Srmind 	}
900f03cb1d4Srmind 	| VAR_ID
901f03cb1d4Srmind 	{
902f03cb1d4Srmind 		npfvar_t *vp = npfvar_lookup($1);
903ff24200fSchristos 		const int type = npfvar_get_type(vp, 0);
904ec3d0e07Srmind 		ifnet_addr_t *ifna;
9056f4ca96cSrmind 		const char *name;
9066f4ca96cSrmind 		unsigned *tid;
9076f4ca96cSrmind 		bool ifaddr;
908f03cb1d4Srmind 
909f03cb1d4Srmind 		switch (type) {
910f03cb1d4Srmind 		case NPFVAR_STRING:
911ec3d0e07Srmind 		case NPFVAR_IDENTIFIER:
912d1d2e2c9Srmind 			$$ = npfvar_expand_string(vp);
913f03cb1d4Srmind 			break;
914ec3d0e07Srmind 		case NPFVAR_INTERFACE:
9155a32644fSchristos 			if (npfvar_get_count(vp) != 1)
9165a32644fSchristos 				yyerror(
9175a32644fSchristos 				    "multiple interfaces are not supported");
918ec3d0e07Srmind 			ifna = npfvar_get_data(vp, type, 0);
919d1d2e2c9Srmind 			$$ = ifna->ifna_name;
920ec3d0e07Srmind 			break;
9216f4ca96cSrmind 		case NPFVAR_TABLE:
9226f4ca96cSrmind 			tid = npfvar_get_data(vp, type, 0);
9236f4ca96cSrmind 			name = npfctl_table_getname(npfctl_config_ref(),
9246f4ca96cSrmind 			    *tid, &ifaddr);
9256f4ca96cSrmind 			if (!ifaddr) {
9266f4ca96cSrmind 				yyerror("variable '%s' references a table "
9276f4ca96cSrmind 				    "%s instead of an interface", $1, name);
9286f4ca96cSrmind 			}
9296f4ca96cSrmind 			$$ = estrdup(name);
9306f4ca96cSrmind 			break;
931f03cb1d4Srmind 		case -1:
932f03cb1d4Srmind 			yyerror("undefined variable '%s' for interface", $1);
933f03cb1d4Srmind 			break;
934f03cb1d4Srmind 		default:
935f03cb1d4Srmind 			yyerror("wrong variable '%s' type '%s' for interface",
936f03cb1d4Srmind 			    $1, npfvar_type(type));
937f03cb1d4Srmind 			break;
938f03cb1d4Srmind 		}
939d1d2e2c9Srmind 		npfctl_note_interface($$);
940f03cb1d4Srmind 	}
941f03cb1d4Srmind 	;
942f03cb1d4Srmind 
943df8b1943Srmind static_ifaddrs
944348a4177Srmind 	: afamily PAR_OPEN ifname PAR_CLOSE
945348a4177Srmind 	{
946348a4177Srmind 		$$ = npfctl_parse_ifnet($3, $1);
947348a4177Srmind 	}
948348a4177Srmind 	;
949348a4177Srmind 
950df8b1943Srmind dynamic_ifaddrs
951df8b1943Srmind 	: IFADDRS PAR_OPEN ifname PAR_CLOSE
952df8b1943Srmind 	{
953df8b1943Srmind 		$$ = $3;
954df8b1943Srmind 	}
955df8b1943Srmind 	;
956df8b1943Srmind 
957348a4177Srmind ifref
958348a4177Srmind 	: ifname
959df8b1943Srmind 	| dynamic_ifaddrs
960df8b1943Srmind 	| static_ifaddrs
961348a4177Srmind 	{
9627e3fb338Srmind 		ifnet_addr_t *ifna;
9637e3fb338Srmind 
9647e3fb338Srmind 		if (npfvar_get_count($1) != 1) {
9655a32644fSchristos 			yyerror("multiple interfaces are not supported");
9667e3fb338Srmind 		}
9677e3fb338Srmind 		ifna = npfvar_get_data($1, NPFVAR_INTERFACE, 0);
968348a4177Srmind 		npfctl_note_interface(ifna->ifna_name);
969348a4177Srmind 		$$ = ifna->ifna_name;
970348a4177Srmind 	}
971348a4177Srmind 	;
972348a4177Srmind 
973f2174d83Schristos number
974f2174d83Schristos 	: HEX		{ $$ = $1; }
975f2174d83Schristos 	| NUM		{ $$ = $1; }
976f2174d83Schristos 	;
977f2174d83Schristos 
978f75d4435Srmind some_name
979f03cb1d4Srmind 	: IDENTIFIER	{ $$ = $1; }
980f03cb1d4Srmind 	| STRING	{ $$ = $1; }
981f03cb1d4Srmind 	;
982f03cb1d4Srmind 
983f03cb1d4Srmind %%
984