xref: /netbsd-src/usr.sbin/npf/npfctl/npf_parse.y (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: npf_parse.y,v 1.35 2014/03/15 15:22:37 riastradh Exp $	*/
2 
3 /*-
4  * Copyright (c) 2011-2014 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Martin Husemann, Christos Zoulas and Mindaugas Rasiukevicius.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 %{
33 
34 #include <stdio.h>
35 #include <err.h>
36 #include <vis.h>
37 #include <netdb.h>
38 
39 #include "npfctl.h"
40 
41 #define	YYSTACKSIZE	4096
42 
43 int			yyparsetarget;
44 const char *		yyfilename;
45 
46 extern int		yylineno, yycolumn;
47 extern int		yylex(void);
48 
49 void
50 yyerror(const char *fmt, ...)
51 {
52 	extern int yyleng;
53 	extern char *yytext;
54 
55 	char *msg, *context = estrndup(yytext, yyleng);
56 	bool eol = (*context == '\n');
57 	va_list ap;
58 
59 	va_start(ap, fmt);
60 	vasprintf(&msg, fmt, ap);
61 	va_end(ap);
62 
63 	fprintf(stderr, "%s:%d:%d: %s", yyfilename,
64 	    yylineno - (int)eol, yycolumn, msg);
65 	if (!eol) {
66 		size_t len = strlen(context);
67 		char *dst = ecalloc(1, len * 4 + 1);
68 
69 		strvisx(dst, context, len, VIS_WHITE|VIS_CSTYLE);
70 		fprintf(stderr, " near '%s'", dst);
71 	}
72 	fprintf(stderr, "\n");
73 	exit(EXIT_FAILURE);
74 }
75 
76 #define	CHECK_PARSER_FILE				\
77 	if (yyparsetarget != NPFCTL_PARSE_FILE)		\
78 		yyerror("rule must be in the group");
79 
80 #define	CHECK_PARSER_STRING				\
81 	if (yyparsetarget != NPFCTL_PARSE_STRING)	\
82 		yyerror("invalid rule syntax");
83 
84 %}
85 
86 %token			ALG
87 %token			ALGO
88 %token			ALL
89 %token			ANY
90 %token			APPLY
91 %token			ARROWBOTH
92 %token			ARROWLEFT
93 %token			ARROWRIGHT
94 %token			BLOCK
95 %token			CDB
96 %token			CURLY_CLOSE
97 %token			CURLY_OPEN
98 %token			CODE
99 %token			COLON
100 %token			COMMA
101 %token			DEFAULT
102 %token			TDYNAMIC
103 %token			TSTATIC
104 %token			EQ
105 %token			TFILE
106 %token			FLAGS
107 %token			FROM
108 %token			GROUP
109 %token			HASH
110 %token			ICMPTYPE
111 %token			ID
112 %token			IN
113 %token			INET4
114 %token			INET6
115 %token			INTERFACE
116 %token			MAP
117 %token			MINUS
118 %token			NAME
119 %token			NPT66
120 %token			ON
121 %token			OUT
122 %token			PAR_CLOSE
123 %token			PAR_OPEN
124 %token			PASS
125 %token			PCAP_FILTER
126 %token			PORT
127 %token			PROCEDURE
128 %token			PROTO
129 %token			FAMILY
130 %token			FINAL
131 %token			FORW
132 %token			RETURN
133 %token			RETURNICMP
134 %token			RETURNRST
135 %token			RULESET
136 %token			SEPLINE
137 %token			SLASH
138 %token			STATEFUL
139 %token			STATEFUL_ENDS
140 %token			TABLE
141 %token			TCP
142 %token			TO
143 %token			TREE
144 %token			TYPE
145 %token	<num>		ICMP
146 %token	<num>		ICMP6
147 
148 %token	<num>		HEX
149 %token	<str>		IDENTIFIER
150 %token	<str>		IPV4ADDR
151 %token	<str>		IPV6ADDR
152 %token	<num>		NUM
153 %token	<fpnum>		FPNUM
154 %token	<str>		STRING
155 %token	<str>		TABLE_ID
156 %token	<str>		VAR_ID
157 
158 %type	<str>		addr, some_name, table_store
159 %type	<str>		proc_param_val, opt_apply, ifname, on_ifname, ifref
160 %type	<num>		port, opt_final, number, afamily, opt_family
161 %type	<num>		block_or_pass, rule_dir, group_dir, block_opts
162 %type	<num>		opt_stateful, icmp_type, table_type
163 %type	<num>		map_sd, map_algo, map_type
164 %type	<var>		ifaddrs, addr_or_ifaddr, port_range, icmp_type_and_code
165 %type	<var>		filt_addr, addr_and_mask, tcp_flags, tcp_flags_and_mask
166 %type	<var>		procs, proc_call, proc_param_list, proc_param
167 %type	<var>		element, list_elems, list, value
168 %type	<addrport>	mapseg
169 %type	<filtopts>	filt_opts, all_or_filt_opts
170 %type	<optproto>	opt_proto
171 %type	<rulegroup>	group_opts
172 
173 %union {
174 	char *		str;
175 	unsigned long	num;
176 	double		fpnum;
177 	npfvar_t *	var;
178 	addr_port_t	addrport;
179 	filt_opts_t	filtopts;
180 	opt_proto_t	optproto;
181 	rule_group_t	rulegroup;
182 }
183 
184 %%
185 
186 input
187 	: { CHECK_PARSER_FILE	} lines
188 	| { CHECK_PARSER_STRING	} rule
189 	;
190 
191 lines
192 	: lines SEPLINE line
193 	| line
194 	;
195 
196 line
197 	: vardef
198 	| table
199 	| map
200 	| group
201 	| rproc
202 	| alg
203 	|
204 	;
205 
206 alg
207 	: ALG STRING
208 	{
209 		npfctl_build_alg($2);
210 	}
211 	;
212 
213 /*
214  * A value - an element or a list of elements.
215  * Can be assigned to a variable or used inline.
216  */
217 
218 vardef
219 	: VAR_ID EQ value
220 	{
221 		npfvar_add($3, $1);
222 	}
223 	;
224 
225 value
226 	: element
227 	| list
228 	;
229 
230 list
231 	: CURLY_OPEN list_elems CURLY_CLOSE
232 	{
233 		$$ = $2;
234 	}
235 	;
236 
237 list_elems
238 	: list_elems COMMA element
239 	{
240 		npfvar_add_elements($1, $3);
241 	}
242 	| element
243 	;
244 
245 element
246 	: IDENTIFIER
247 	{
248 		$$ = npfvar_create_from_string(NPFVAR_IDENTIFIER, $1);
249 	}
250 	| STRING
251 	{
252 		$$ = npfvar_create_from_string(NPFVAR_STRING, $1);
253 	}
254 	| number MINUS number
255 	{
256 		$$ = npfctl_parse_port_range($1, $3);
257 	}
258 	| number
259 	{
260 		$$ = npfvar_create_element(NPFVAR_NUM, &$1, sizeof($1));
261 	}
262 	| VAR_ID
263 	{
264 		$$ = npfvar_create_from_string(NPFVAR_VAR_ID, $1);
265 	}
266 	| TABLE_ID		{ $$ = npfctl_parse_table_id($1); }
267 	| ifaddrs		{ $$ = $1; }
268 	| addr_and_mask		{ $$ = $1; }
269 	;
270 
271 /*
272  * Table definition.
273  */
274 
275 table
276 	: TABLE TABLE_ID TYPE table_type table_store
277 	{
278 		npfctl_build_table($2, $4, $5);
279 	}
280 	;
281 
282 table_type
283 	: HASH		{ $$ = NPF_TABLE_HASH; }
284 	| TREE		{ $$ = NPF_TABLE_TREE; }
285 	| CDB		{ $$ = NPF_TABLE_CDB; }
286 	;
287 
288 table_store
289 	: TDYNAMIC	{ $$ = NULL; }
290 	| TFILE STRING	{ $$ = $2; }
291 	;
292 
293 /*
294  * Map definition.
295  */
296 
297 map_sd
298 	: TSTATIC	{ $$ = NPFCTL_NAT_STATIC; }
299 	| TDYNAMIC	{ $$ = NPFCTL_NAT_DYNAMIC; }
300 	|		{ $$ = NPFCTL_NAT_DYNAMIC; }
301 	;
302 
303 map_algo
304 	: ALGO NPT66	{ $$ = NPF_ALGO_NPT66; }
305 	|		{ $$ = 0; }
306 	;
307 
308 map_type
309 	: ARROWBOTH	{ $$ = NPF_NATIN | NPF_NATOUT; }
310 	| ARROWLEFT	{ $$ = NPF_NATIN; }
311 	| ARROWRIGHT	{ $$ = NPF_NATOUT; }
312 	;
313 
314 mapseg
315 	: addr_or_ifaddr port_range
316 	{
317 		$$.ap_netaddr = $1;
318 		$$.ap_portrange = $2;
319 	}
320 	;
321 
322 map
323 	: MAP ifref map_sd map_algo mapseg map_type mapseg PASS filt_opts
324 	{
325 		npfctl_build_natseg($3, $6, $2, &$5, &$7, &$9, $4);
326 	}
327 	| MAP ifref map_sd map_algo mapseg map_type mapseg
328 	{
329 		npfctl_build_natseg($3, $6, $2, &$5, &$7, NULL, $4);
330 	}
331 	| MAP RULESET group_opts
332 	{
333 		npfctl_build_maprset($3.rg_name, $3.rg_attr, $3.rg_ifname);
334 	}
335 	;
336 
337 /*
338  * Rule procedure definition and its parameters.
339  */
340 
341 rproc
342 	: PROCEDURE STRING CURLY_OPEN procs CURLY_CLOSE
343 	{
344 		npfctl_build_rproc($2, $4);
345 	}
346 	;
347 
348 procs
349 	: procs SEPLINE proc_call
350 	{
351 		$$ = npfvar_add_elements($1, $3);
352 	}
353 	| proc_call	{ $$ = $1; }
354 	;
355 
356 proc_call
357 	: IDENTIFIER COLON proc_param_list
358 	{
359 		proc_call_t pc;
360 
361 		pc.pc_name = estrdup($1);
362 		pc.pc_opts = $3;
363 
364 		$$ = npfvar_create_element(NPFVAR_PROC, &pc, sizeof(pc));
365 	}
366 	|		{ $$ = NULL; }
367 	;
368 
369 proc_param_list
370 	: proc_param_list COMMA proc_param
371 	{
372 		$$ = npfvar_add_elements($1, $3);
373 	}
374 	| proc_param	{ $$ = $1; }
375 	|		{ $$ = NULL; }
376 	;
377 
378 proc_param
379 	: some_name proc_param_val
380 	{
381 		proc_param_t pp;
382 
383 		pp.pp_param = estrdup($1);
384 		pp.pp_value = $2 ? estrdup($2) : NULL;
385 
386 		$$ = npfvar_create_element(NPFVAR_PROC_PARAM, &pp, sizeof(pp));
387 	}
388 	;
389 
390 proc_param_val
391 	: some_name	{ $$ = $1; }
392 	| number	{ (void)asprintf(&$$, "%ld", $1); }
393 	| FPNUM		{ (void)asprintf(&$$, "%lf", $1); }
394 	|		{ $$ = NULL; }
395 	;
396 
397 /*
398  * Group and dynamic ruleset definition.
399  */
400 
401 group
402 	: GROUP group_opts
403 	{
404 		/* Build a group.  Increase the nesting level. */
405 		npfctl_build_group($2.rg_name, $2.rg_attr,
406 		    $2.rg_ifname, $2.rg_default);
407 	}
408 	  ruleset_block
409 	{
410 		/* Decrease the nesting level. */
411 		npfctl_build_group_end();
412 	}
413 	;
414 
415 ruleset
416 	: RULESET group_opts
417 	{
418 		/* Ruleset is a dynamic group. */
419 		npfctl_build_group($2.rg_name, $2.rg_attr | NPF_RULE_DYNAMIC,
420 		    $2.rg_ifname, $2.rg_default);
421 		npfctl_build_group_end();
422 	}
423 	;
424 
425 group_dir
426 	: FORW		{ $$ = NPF_RULE_FORW; }
427 	| rule_dir
428 	;
429 
430 group_opts
431 	: DEFAULT
432 	{
433 		memset(&$$, 0, sizeof(rule_group_t));
434 		$$.rg_default = true;
435 	}
436 	| STRING group_dir on_ifname
437 	{
438 		memset(&$$, 0, sizeof(rule_group_t));
439 		$$.rg_name = $1;
440 		$$.rg_attr = $2;
441 		$$.rg_ifname = $3;
442 	}
443 	;
444 
445 ruleset_block
446 	: CURLY_OPEN ruleset_def CURLY_CLOSE
447 	;
448 
449 ruleset_def
450 	: ruleset_def SEPLINE rule_group
451 	| rule_group
452 	;
453 
454 rule_group
455 	: rule
456 	| group
457 	| ruleset
458 	|
459 	;
460 
461 /*
462  * Rule and misc.
463  */
464 
465 rule
466 	: block_or_pass opt_stateful rule_dir opt_final on_ifname
467 	  opt_family opt_proto all_or_filt_opts opt_apply
468 	{
469 		npfctl_build_rule($1 | $2 | $3 | $4, $5,
470 		    $6, &$7, &$8, NULL, $9);
471 	}
472 	| block_or_pass opt_stateful rule_dir opt_final on_ifname
473 	  PCAP_FILTER STRING opt_apply
474 	{
475 		npfctl_build_rule($1 | $2 | $3 | $4, $5,
476 		    AF_UNSPEC, NULL, NULL, $7, $8);
477 	}
478 	;
479 
480 block_or_pass
481 	: BLOCK block_opts	{ $$ = $2; }
482 	| PASS			{ $$ = NPF_RULE_PASS; }
483 	;
484 
485 rule_dir
486 	: IN			{ $$ = NPF_RULE_IN; }
487 	| OUT			{ $$ = NPF_RULE_OUT; }
488 	|			{ $$ = NPF_RULE_IN | NPF_RULE_OUT; }
489 	;
490 
491 opt_final
492 	: FINAL			{ $$ = NPF_RULE_FINAL; }
493 	|			{ $$ = 0; }
494 	;
495 
496 on_ifname
497 	: ON ifref		{ $$ = $2; }
498 	|			{ $$ = NULL; }
499 	;
500 
501 afamily
502 	: INET4			{ $$ = AF_INET; }
503 	| INET6			{ $$ = AF_INET6; }
504 	;
505 
506 opt_family
507 	: FAMILY afamily	{ $$ = $2; }
508 	|			{ $$ = AF_UNSPEC; }
509 	;
510 
511 opt_proto
512 	: PROTO TCP tcp_flags_and_mask
513 	{
514 		$$.op_proto = IPPROTO_TCP;
515 		$$.op_opts = $3;
516 	}
517 	| PROTO ICMP icmp_type_and_code
518 	{
519 		$$.op_proto = IPPROTO_ICMP;
520 		$$.op_opts = $3;
521 	}
522 	| PROTO ICMP6 icmp_type_and_code
523 	{
524 		$$.op_proto = IPPROTO_ICMPV6;
525 		$$.op_opts = $3;
526 	}
527 	| PROTO some_name
528 	{
529 		$$.op_proto = npfctl_protono($2);
530 		$$.op_opts = NULL;
531 	}
532 	| PROTO number
533 	{
534 		$$.op_proto = $2;
535 		$$.op_opts = NULL;
536 	}
537 	|
538 	{
539 		$$.op_proto = -1;
540 		$$.op_opts = NULL;
541 	}
542 	;
543 
544 all_or_filt_opts
545 	: ALL
546 	{
547 		$$.fo_from.ap_netaddr = NULL;
548 		$$.fo_from.ap_portrange = NULL;
549 		$$.fo_to.ap_netaddr = NULL;
550 		$$.fo_to.ap_portrange = NULL;
551 	}
552 	| filt_opts	{ $$ = $1; }
553 	;
554 
555 opt_stateful
556 	: STATEFUL	{ $$ = NPF_RULE_STATEFUL; }
557 	| STATEFUL_ENDS	{ $$ = NPF_RULE_STATEFUL | NPF_RULE_MULTIENDS; }
558 	|		{ $$ = 0; }
559 	;
560 
561 opt_apply
562 	: APPLY STRING	{ $$ = $2; }
563 	|		{ $$ = NULL; }
564 	;
565 
566 block_opts
567 	: RETURNRST	{ $$ = NPF_RULE_RETRST; }
568 	| RETURNICMP	{ $$ = NPF_RULE_RETICMP; }
569 	| RETURN	{ $$ = NPF_RULE_RETRST | NPF_RULE_RETICMP; }
570 	|		{ $$ = 0; }
571 	;
572 
573 filt_opts
574 	: FROM filt_addr port_range TO filt_addr port_range
575 	{
576 		$$.fo_from.ap_netaddr = $2;
577 		$$.fo_from.ap_portrange = $3;
578 		$$.fo_to.ap_netaddr = $5;
579 		$$.fo_to.ap_portrange = $6;
580 	}
581 	| FROM filt_addr port_range
582 	{
583 		$$.fo_from.ap_netaddr = $2;
584 		$$.fo_from.ap_portrange = $3;
585 		$$.fo_to.ap_netaddr = NULL;
586 		$$.fo_to.ap_portrange = NULL;
587 	}
588 	| TO filt_addr port_range
589 	{
590 		$$.fo_from.ap_netaddr = NULL;
591 		$$.fo_from.ap_portrange = NULL;
592 		$$.fo_to.ap_netaddr = $2;
593 		$$.fo_to.ap_portrange = $3;
594 	}
595 	;
596 
597 filt_addr
598 	: addr_or_ifaddr	{ $$ = $1; }
599 	| TABLE_ID		{ $$ = npfctl_parse_table_id($1); }
600 	| ANY			{ $$ = NULL; }
601 	;
602 
603 addr_and_mask
604 	: addr SLASH number
605 	{
606 		$$ = npfctl_parse_fam_addr_mask($1, NULL, &$3);
607 	}
608 	| addr SLASH addr
609 	{
610 		$$ = npfctl_parse_fam_addr_mask($1, $3, NULL);
611 	}
612 	| addr
613 	{
614 		$$ = npfctl_parse_fam_addr_mask($1, NULL, NULL);
615 	}
616 	;
617 
618 addr_or_ifaddr
619 	: addr_and_mask
620 	{
621 		assert($1 != NULL);
622 		$$ = $1;
623 	}
624 	| ifaddrs
625 	{
626 		ifnet_addr_t *ifna = npfvar_get_data($1, NPFVAR_INTERFACE, 0);
627 		$$ = ifna->ifna_addrs;
628 	}
629 	| VAR_ID
630 	{
631 		npfvar_t *vp = npfvar_lookup($1);
632 		int type = npfvar_get_type(vp, 0);
633 		ifnet_addr_t *ifna;
634 
635 again:
636 		switch (type) {
637 		case NPFVAR_IDENTIFIER:
638 		case NPFVAR_STRING:
639 			vp = npfctl_parse_ifnet(npfvar_expand_string(vp),
640 			    AF_UNSPEC);
641 			type = npfvar_get_type(vp, 0);
642 			goto again;
643 		case NPFVAR_FAM:
644 			$$ = vp;
645 			break;
646 		case NPFVAR_INTERFACE:
647 			$$ = NULL;
648 			for (u_int i = 0; i < npfvar_get_count(vp); i++) {
649 				ifna = npfvar_get_data(vp, type, i);
650 				$$ = npfvar_add_elements($$, ifna->ifna_addrs);
651 			}
652 			break;
653 		case -1:
654 			yyerror("undefined variable '%s'", $1);
655 			break;
656 		default:
657 			yyerror("wrong variable '%s' type '%s' for address "
658 			    "or interface", $1, npfvar_type(type));
659 			break;
660 		}
661 	}
662 	;
663 
664 addr
665 	: IPV4ADDR	{ $$ = $1; }
666 	| IPV6ADDR	{ $$ = $1; }
667 	;
668 
669 port_range
670 	: PORT port		/* just port */
671 	{
672 		$$ = npfctl_parse_port_range($2, $2);
673 	}
674 	| PORT port MINUS port	/* port from-to */
675 	{
676 		$$ = npfctl_parse_port_range($2, $4);
677 	}
678 	| PORT VAR_ID
679 	{
680 		$$ = npfctl_parse_port_range_variable($2);
681 	}
682 	|
683 	{
684 		$$ = NULL;
685 	}
686 	;
687 
688 port
689 	: number	{ $$ = $1; }
690 	| IDENTIFIER	{ $$ = npfctl_portno($1); }
691 	| STRING	{ $$ = npfctl_portno($1); }
692 	;
693 
694 icmp_type_and_code
695 	: ICMPTYPE icmp_type
696 	{
697 		$$ = npfctl_parse_icmp($<num>0, $2, -1);
698 	}
699 	| ICMPTYPE icmp_type CODE number
700 	{
701 		$$ = npfctl_parse_icmp($<num>0, $2, $4);
702 	}
703 	| ICMPTYPE icmp_type CODE IDENTIFIER
704 	{
705 		$$ = npfctl_parse_icmp($<num>0, $2,
706 		    npfctl_icmpcode($<num>0, $2, $4));
707 	}
708 	| ICMPTYPE icmp_type CODE VAR_ID
709 	{
710 		char *s = npfvar_expand_string(npfvar_lookup($4));
711 		$$ = npfctl_parse_icmp($<num>0, $2,
712 		    npfctl_icmpcode($<num>0, $2, s));
713 	}
714 	|		{ $$ = NULL; }
715 	;
716 
717 tcp_flags_and_mask
718 	: FLAGS tcp_flags SLASH tcp_flags
719 	{
720 		npfvar_add_elements($2, $4);
721 		$$ = $2;
722 	}
723 	| FLAGS tcp_flags
724 	{
725 		char *s = npfvar_get_data($2, NPFVAR_TCPFLAG, 0);
726 		npfvar_add_elements($2, npfctl_parse_tcpflag(s));
727 		$$ = $2;
728 	}
729 	|		{ $$ = NULL; }
730 	;
731 
732 tcp_flags
733 	: IDENTIFIER	{ $$ = npfctl_parse_tcpflag($1); }
734 	;
735 
736 icmp_type
737 	: number	{ $$ = $1; }
738 	| IDENTIFIER	{ $$ = npfctl_icmptype($<num>-1, $1); }
739 	| VAR_ID
740 	{
741 		char *s = npfvar_expand_string(npfvar_lookup($1));
742 		$$ = npfctl_icmptype($<num>-1, s);
743 	}
744 	;
745 
746 ifname
747 	: some_name
748 	{
749 		npfctl_note_interface($1);
750 		$$ = $1;
751 	}
752 	| VAR_ID
753 	{
754 		npfvar_t *vp = npfvar_lookup($1);
755 		const int type = npfvar_get_type(vp, 0);
756 		ifnet_addr_t *ifna;
757 
758 		switch (type) {
759 		case NPFVAR_STRING:
760 		case NPFVAR_IDENTIFIER:
761 			$$ = npfvar_expand_string(vp);
762 			break;
763 		case NPFVAR_INTERFACE:
764 			ifna = npfvar_get_data(vp, type, 0);
765 			$$ = ifna->ifna_name;
766 			break;
767 		case -1:
768 			yyerror("undefined variable '%s' for interface", $1);
769 			break;
770 		default:
771 			yyerror("wrong variable '%s' type '%s' for interface",
772 			    $1, npfvar_type(type));
773 			break;
774 		}
775 		npfctl_note_interface($$);
776 	}
777 	;
778 
779 ifaddrs
780 	: afamily PAR_OPEN ifname PAR_CLOSE
781 	{
782 		$$ = npfctl_parse_ifnet($3, $1);
783 	}
784 	;
785 
786 ifref
787 	: ifname
788 	| ifaddrs
789 	{
790 		ifnet_addr_t *ifna = npfvar_get_data($1, NPFVAR_INTERFACE, 0);
791 		npfctl_note_interface(ifna->ifna_name);
792 		$$ = ifna->ifna_name;
793 	}
794 	;
795 
796 number
797 	: HEX		{ $$ = $1; }
798 	| NUM		{ $$ = $1; }
799 	;
800 
801 some_name
802 	: IDENTIFIER	{ $$ = $1; }
803 	| STRING	{ $$ = $1; }
804 	;
805 
806 %%
807