Home | History | Annotate | Line # | Download | only in npfctl
npf_parse.y revision 1.33
      1 /*	$NetBSD: npf_parse.y,v 1.33 2014/02/17 00:45:24 rmind 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			TABLE
    140 %token			TCP
    141 %token			TO
    142 %token			TREE
    143 %token			TYPE
    144 %token	<num>		ICMP
    145 %token	<num>		ICMP6
    146 
    147 %token	<num>		HEX
    148 %token	<str>		IDENTIFIER
    149 %token	<str>		IPV4ADDR
    150 %token	<str>		IPV6ADDR
    151 %token	<num>		NUM
    152 %token	<fpnum>		FPNUM
    153 %token	<str>		STRING
    154 %token	<str>		TABLE_ID
    155 %token	<str>		VAR_ID
    156 
    157 %type	<str>		addr, some_name, table_store
    158 %type	<str>		proc_param_val, opt_apply, ifname, on_ifname, ifref
    159 %type	<num>		port, opt_final, number, afamily, opt_family
    160 %type	<num>		block_or_pass, rule_dir, group_dir, block_opts
    161 %type	<num>		opt_stateful, icmp_type, table_type
    162 %type	<num>		map_sd, map_algo, map_type
    163 %type	<var>		ifaddrs, addr_or_ifaddr, port_range, icmp_type_and_code
    164 %type	<var>		filt_addr, addr_and_mask, tcp_flags, tcp_flags_and_mask
    165 %type	<var>		procs, proc_call, proc_param_list, proc_param
    166 %type	<var>		element, list_elems, list, value
    167 %type	<addrport>	mapseg
    168 %type	<filtopts>	filt_opts, all_or_filt_opts
    169 %type	<optproto>	opt_proto
    170 %type	<rulegroup>	group_opts
    171 
    172 %union {
    173 	char *		str;
    174 	unsigned long	num;
    175 	double		fpnum;
    176 	npfvar_t *	var;
    177 	addr_port_t	addrport;
    178 	filt_opts_t	filtopts;
    179 	opt_proto_t	optproto;
    180 	rule_group_t	rulegroup;
    181 }
    182 
    183 %%
    184 
    185 input
    186 	: { CHECK_PARSER_FILE	} lines
    187 	| { CHECK_PARSER_STRING	} rule
    188 	;
    189 
    190 lines
    191 	: line SEPLINE lines
    192 	| line
    193 	;
    194 
    195 line
    196 	: vardef
    197 	| table
    198 	| map
    199 	| group
    200 	| rproc
    201 	| alg
    202 	|
    203 	;
    204 
    205 alg
    206 	: ALG STRING
    207 	{
    208 		npfctl_build_alg($2);
    209 	}
    210 	;
    211 
    212 /*
    213  * A value - an element or a list of elements.
    214  * Can be assigned to a variable or used inline.
    215  */
    216 
    217 vardef
    218 	: VAR_ID EQ value
    219 	{
    220 		npfvar_add($3, $1);
    221 	}
    222 	;
    223 
    224 value
    225 	: element
    226 	| list
    227 	;
    228 
    229 list
    230 	: CURLY_OPEN list_elems CURLY_CLOSE
    231 	{
    232 		$$ = $2;
    233 	}
    234 	;
    235 
    236 list_elems
    237 	: element COMMA list_elems
    238 	{
    239 		npfvar_add_elements($1, $3);
    240 	}
    241 	| element
    242 	;
    243 
    244 element
    245 	: IDENTIFIER
    246 	{
    247 		$$ = npfvar_create_from_string(NPFVAR_IDENTIFIER, $1);
    248 	}
    249 	| STRING
    250 	{
    251 		$$ = npfvar_create_from_string(NPFVAR_STRING, $1);
    252 	}
    253 	| number MINUS number
    254 	{
    255 		$$ = npfctl_parse_port_range($1, $3);
    256 	}
    257 	| number
    258 	{
    259 		$$ = npfvar_create_element(NPFVAR_NUM, &$1, sizeof($1));
    260 	}
    261 	| VAR_ID
    262 	{
    263 		$$ = npfvar_create_from_string(NPFVAR_VAR_ID, $1);
    264 	}
    265 	| TABLE_ID		{ $$ = npfctl_parse_table_id($1); }
    266 	| ifaddrs		{ $$ = $1; }
    267 	| addr_and_mask		{ $$ = $1; }
    268 	;
    269 
    270 /*
    271  * Table definition.
    272  */
    273 
    274 table
    275 	: TABLE TABLE_ID TYPE table_type table_store
    276 	{
    277 		npfctl_build_table($2, $4, $5);
    278 	}
    279 	;
    280 
    281 table_type
    282 	: HASH		{ $$ = NPF_TABLE_HASH; }
    283 	| TREE		{ $$ = NPF_TABLE_TREE; }
    284 	| CDB		{ $$ = NPF_TABLE_CDB; }
    285 	;
    286 
    287 table_store
    288 	: TDYNAMIC	{ $$ = NULL; }
    289 	| TFILE STRING	{ $$ = $2; }
    290 	;
    291 
    292 /*
    293  * Map definition.
    294  */
    295 
    296 map_sd
    297 	: TSTATIC	{ $$ = NPFCTL_NAT_STATIC; }
    298 	| TDYNAMIC	{ $$ = NPFCTL_NAT_DYNAMIC; }
    299 	|		{ $$ = NPFCTL_NAT_DYNAMIC; }
    300 	;
    301 
    302 map_algo
    303 	: ALGO NPT66	{ $$ = NPF_ALGO_NPT66; }
    304 	|		{ $$ = 0; }
    305 	;
    306 
    307 map_type
    308 	: ARROWBOTH	{ $$ = NPF_NATIN | NPF_NATOUT; }
    309 	| ARROWLEFT	{ $$ = NPF_NATIN; }
    310 	| ARROWRIGHT	{ $$ = NPF_NATOUT; }
    311 	;
    312 
    313 mapseg
    314 	: addr_or_ifaddr port_range
    315 	{
    316 		$$.ap_netaddr = $1;
    317 		$$.ap_portrange = $2;
    318 	}
    319 	;
    320 
    321 map
    322 	: MAP ifref map_sd map_algo mapseg map_type mapseg PASS filt_opts
    323 	{
    324 		npfctl_build_natseg($3, $6, $2, &$5, &$7, &$9, $4);
    325 	}
    326 	| MAP ifref map_sd map_algo mapseg map_type mapseg
    327 	{
    328 		npfctl_build_natseg($3, $6, $2, &$5, &$7, NULL, $4);
    329 	}
    330 	| MAP RULESET group_opts
    331 	{
    332 		npfctl_build_maprset($3.rg_name, $3.rg_attr, $3.rg_ifname);
    333 	}
    334 	;
    335 
    336 /*
    337  * Rule procedure definition and its parameters.
    338  */
    339 
    340 rproc
    341 	: PROCEDURE STRING CURLY_OPEN procs CURLY_CLOSE
    342 	{
    343 		npfctl_build_rproc($2, $4);
    344 	}
    345 	;
    346 
    347 procs
    348 	: proc_call SEPLINE procs
    349 	{
    350 		$$ = npfvar_add_elements($1, $3);
    351 	}
    352 	| proc_call	{ $$ = $1; }
    353 	;
    354 
    355 proc_call
    356 	: IDENTIFIER COLON proc_param_list
    357 	{
    358 		proc_call_t pc;
    359 
    360 		pc.pc_name = estrdup($1);
    361 		pc.pc_opts = $3;
    362 
    363 		$$ = npfvar_create_element(NPFVAR_PROC, &pc, sizeof(pc));
    364 	}
    365 	|		{ $$ = NULL; }
    366 	;
    367 
    368 proc_param_list
    369 	: proc_param COMMA proc_param_list
    370 	{
    371 		$$ = npfvar_add_elements($1, $3);
    372 	}
    373 	| proc_param	{ $$ = $1; }
    374 	|		{ $$ = NULL; }
    375 	;
    376 
    377 proc_param
    378 	: some_name proc_param_val
    379 	{
    380 		proc_param_t pp;
    381 
    382 		pp.pp_param = estrdup($1);
    383 		pp.pp_value = $2 ? estrdup($2) : NULL;
    384 
    385 		$$ = npfvar_create_element(NPFVAR_PROC_PARAM, &pp, sizeof(pp));
    386 	}
    387 	;
    388 
    389 proc_param_val
    390 	: some_name	{ $$ = $1; }
    391 	| number	{ (void)asprintf(&$$, "%ld", $1); }
    392 	| FPNUM		{ (void)asprintf(&$$, "%lf", $1); }
    393 	|		{ $$ = NULL; }
    394 	;
    395 
    396 /*
    397  * Group and dynamic ruleset definition.
    398  */
    399 
    400 group
    401 	: GROUP group_opts
    402 	{
    403 		/* Build a group.  Increase the nesting level. */
    404 		npfctl_build_group($2.rg_name, $2.rg_attr,
    405 		    $2.rg_ifname, $2.rg_default);
    406 	}
    407 	  ruleset_block
    408 	{
    409 		/* Decrease the nesting level. */
    410 		npfctl_build_group_end();
    411 	}
    412 	;
    413 
    414 ruleset
    415 	: RULESET group_opts
    416 	{
    417 		/* Ruleset is a dynamic group. */
    418 		npfctl_build_group($2.rg_name, $2.rg_attr | NPF_RULE_DYNAMIC,
    419 		    $2.rg_ifname, $2.rg_default);
    420 		npfctl_build_group_end();
    421 	}
    422 	;
    423 
    424 group_dir
    425 	: FORW		{ $$ = NPF_RULE_FORW; }
    426 	| rule_dir
    427 	;
    428 
    429 group_opts
    430 	: DEFAULT
    431 	{
    432 		memset(&$$, 0, sizeof(rule_group_t));
    433 		$$.rg_default = true;
    434 	}
    435 	| STRING group_dir on_ifname
    436 	{
    437 		memset(&$$, 0, sizeof(rule_group_t));
    438 		$$.rg_name = $1;
    439 		$$.rg_attr = $2;
    440 		$$.rg_ifname = $3;
    441 	}
    442 	;
    443 
    444 ruleset_block
    445 	: CURLY_OPEN ruleset_def CURLY_CLOSE
    446 	;
    447 
    448 ruleset_def
    449 	: rule_group SEPLINE ruleset_def
    450 	| rule_group
    451 	;
    452 
    453 rule_group
    454 	: rule
    455 	| group
    456 	| ruleset
    457 	|
    458 	;
    459 
    460 /*
    461  * Rule and misc.
    462  */
    463 
    464 rule
    465 	: block_or_pass opt_stateful rule_dir opt_final on_ifname
    466 	  opt_family opt_proto all_or_filt_opts opt_apply
    467 	{
    468 		npfctl_build_rule($1 | $2 | $3 | $4, $5,
    469 		    $6, &$7, &$8, NULL, $9);
    470 	}
    471 	| block_or_pass opt_stateful rule_dir opt_final on_ifname
    472 	  PCAP_FILTER STRING opt_apply
    473 	{
    474 		npfctl_build_rule($1 | $2 | $3 | $4, $5,
    475 		    AF_UNSPEC, NULL, NULL, $7, $8);
    476 	}
    477 	;
    478 
    479 block_or_pass
    480 	: BLOCK block_opts	{ $$ = $2; }
    481 	| PASS			{ $$ = NPF_RULE_PASS; }
    482 	;
    483 
    484 rule_dir
    485 	: IN			{ $$ = NPF_RULE_IN; }
    486 	| OUT			{ $$ = NPF_RULE_OUT; }
    487 	|			{ $$ = NPF_RULE_IN | NPF_RULE_OUT; }
    488 	;
    489 
    490 opt_final
    491 	: FINAL			{ $$ = NPF_RULE_FINAL; }
    492 	|			{ $$ = 0; }
    493 	;
    494 
    495 on_ifname
    496 	: ON ifref		{ $$ = $2; }
    497 	|			{ $$ = NULL; }
    498 	;
    499 
    500 afamily
    501 	: INET4			{ $$ = AF_INET; }
    502 	| INET6			{ $$ = AF_INET6; }
    503 	;
    504 
    505 opt_family
    506 	: FAMILY afamily	{ $$ = $2; }
    507 	|			{ $$ = AF_UNSPEC; }
    508 	;
    509 
    510 opt_proto
    511 	: PROTO TCP tcp_flags_and_mask
    512 	{
    513 		$$.op_proto = IPPROTO_TCP;
    514 		$$.op_opts = $3;
    515 	}
    516 	| PROTO ICMP icmp_type_and_code
    517 	{
    518 		$$.op_proto = IPPROTO_ICMP;
    519 		$$.op_opts = $3;
    520 	}
    521 	| PROTO ICMP6 icmp_type_and_code
    522 	{
    523 		$$.op_proto = IPPROTO_ICMPV6;
    524 		$$.op_opts = $3;
    525 	}
    526 	| PROTO some_name
    527 	{
    528 		$$.op_proto = npfctl_protono($2);
    529 		$$.op_opts = NULL;
    530 	}
    531 	| PROTO number
    532 	{
    533 		$$.op_proto = $2;
    534 		$$.op_opts = NULL;
    535 	}
    536 	|
    537 	{
    538 		$$.op_proto = -1;
    539 		$$.op_opts = NULL;
    540 	}
    541 	;
    542 
    543 all_or_filt_opts
    544 	: ALL
    545 	{
    546 		$$.fo_from.ap_netaddr = NULL;
    547 		$$.fo_from.ap_portrange = NULL;
    548 		$$.fo_to.ap_netaddr = NULL;
    549 		$$.fo_to.ap_portrange = NULL;
    550 	}
    551 	| filt_opts	{ $$ = $1; }
    552 	;
    553 
    554 opt_stateful
    555 	: STATEFUL	{ $$ = NPF_RULE_STATEFUL; }
    556 	|		{ $$ = 0; }
    557 	;
    558 
    559 opt_apply
    560 	: APPLY STRING	{ $$ = $2; }
    561 	|		{ $$ = NULL; }
    562 	;
    563 
    564 block_opts
    565 	: RETURNRST	{ $$ = NPF_RULE_RETRST; }
    566 	| RETURNICMP	{ $$ = NPF_RULE_RETICMP; }
    567 	| RETURN	{ $$ = NPF_RULE_RETRST | NPF_RULE_RETICMP; }
    568 	|		{ $$ = 0; }
    569 	;
    570 
    571 filt_opts
    572 	: FROM filt_addr port_range TO filt_addr port_range
    573 	{
    574 		$$.fo_from.ap_netaddr = $2;
    575 		$$.fo_from.ap_portrange = $3;
    576 		$$.fo_to.ap_netaddr = $5;
    577 		$$.fo_to.ap_portrange = $6;
    578 	}
    579 	| FROM filt_addr port_range
    580 	{
    581 		$$.fo_from.ap_netaddr = $2;
    582 		$$.fo_from.ap_portrange = $3;
    583 		$$.fo_to.ap_netaddr = NULL;
    584 		$$.fo_to.ap_portrange = NULL;
    585 	}
    586 	| TO filt_addr port_range
    587 	{
    588 		$$.fo_from.ap_netaddr = NULL;
    589 		$$.fo_from.ap_portrange = NULL;
    590 		$$.fo_to.ap_netaddr = $2;
    591 		$$.fo_to.ap_portrange = $3;
    592 	}
    593 	;
    594 
    595 filt_addr
    596 	: addr_or_ifaddr	{ $$ = $1; }
    597 	| TABLE_ID		{ $$ = npfctl_parse_table_id($1); }
    598 	| ANY			{ $$ = NULL; }
    599 	;
    600 
    601 addr_and_mask
    602 	: addr SLASH number
    603 	{
    604 		$$ = npfctl_parse_fam_addr_mask($1, NULL, &$3);
    605 	}
    606 	| addr SLASH addr
    607 	{
    608 		$$ = npfctl_parse_fam_addr_mask($1, $3, NULL);
    609 	}
    610 	| addr
    611 	{
    612 		$$ = npfctl_parse_fam_addr_mask($1, NULL, NULL);
    613 	}
    614 	;
    615 
    616 addr_or_ifaddr
    617 	: addr_and_mask
    618 	{
    619 		assert($1 != NULL);
    620 		$$ = $1;
    621 	}
    622 	| ifaddrs
    623 	{
    624 		ifnet_addr_t *ifna = npfvar_get_data($1, NPFVAR_INTERFACE, 0);
    625 		$$ = ifna->ifna_addrs;
    626 	}
    627 	| VAR_ID
    628 	{
    629 		npfvar_t *vp = npfvar_lookup($1);
    630 		int type = npfvar_get_type(vp, 0);
    631 		ifnet_addr_t *ifna;
    632 
    633 again:
    634 		switch (type) {
    635 		case NPFVAR_IDENTIFIER:
    636 		case NPFVAR_STRING:
    637 			vp = npfctl_parse_ifnet(npfvar_expand_string(vp),
    638 			    AF_UNSPEC);
    639 			type = npfvar_get_type(vp, 0);
    640 			goto again;
    641 		case NPFVAR_FAM:
    642 			$$ = vp;
    643 			break;
    644 		case NPFVAR_INTERFACE:
    645 			$$ = NULL;
    646 			for (u_int i = 0; i < npfvar_get_count(vp); i++) {
    647 				ifna = npfvar_get_data(vp, type, i);
    648 				$$ = npfvar_add_elements($$, ifna->ifna_addrs);
    649 			}
    650 			break;
    651 		case -1:
    652 			yyerror("undefined variable '%s'", $1);
    653 			break;
    654 		default:
    655 			yyerror("wrong variable '%s' type '%s' for address "
    656 			    "or interface", $1, npfvar_type(type));
    657 			break;
    658 		}
    659 	}
    660 	;
    661 
    662 addr
    663 	: IPV4ADDR	{ $$ = $1; }
    664 	| IPV6ADDR	{ $$ = $1; }
    665 	;
    666 
    667 port_range
    668 	: PORT port		/* just port */
    669 	{
    670 		$$ = npfctl_parse_port_range($2, $2);
    671 	}
    672 	| PORT port MINUS port	/* port from-to */
    673 	{
    674 		$$ = npfctl_parse_port_range($2, $4);
    675 	}
    676 	| PORT VAR_ID
    677 	{
    678 		$$ = npfctl_parse_port_range_variable($2);
    679 	}
    680 	|
    681 	{
    682 		$$ = NULL;
    683 	}
    684 	;
    685 
    686 port
    687 	: number	{ $$ = $1; }
    688 	| IDENTIFIER	{ $$ = npfctl_portno($1); }
    689 	| STRING	{ $$ = npfctl_portno($1); }
    690 	;
    691 
    692 icmp_type_and_code
    693 	: ICMPTYPE icmp_type
    694 	{
    695 		$$ = npfctl_parse_icmp($<num>0, $2, -1);
    696 	}
    697 	| ICMPTYPE icmp_type CODE number
    698 	{
    699 		$$ = npfctl_parse_icmp($<num>0, $2, $4);
    700 	}
    701 	| ICMPTYPE icmp_type CODE IDENTIFIER
    702 	{
    703 		$$ = npfctl_parse_icmp($<num>0, $2,
    704 		    npfctl_icmpcode($<num>0, $2, $4));
    705 	}
    706 	| ICMPTYPE icmp_type CODE VAR_ID
    707 	{
    708 		char *s = npfvar_expand_string(npfvar_lookup($4));
    709 		$$ = npfctl_parse_icmp($<num>0, $2,
    710 		    npfctl_icmpcode($<num>0, $2, s));
    711 	}
    712 	|		{ $$ = NULL; }
    713 	;
    714 
    715 tcp_flags_and_mask
    716 	: FLAGS tcp_flags SLASH tcp_flags
    717 	{
    718 		npfvar_add_elements($2, $4);
    719 		$$ = $2;
    720 	}
    721 	| FLAGS tcp_flags
    722 	{
    723 		char *s = npfvar_get_data($2, NPFVAR_TCPFLAG, 0);
    724 		npfvar_add_elements($2, npfctl_parse_tcpflag(s));
    725 		$$ = $2;
    726 	}
    727 	|		{ $$ = NULL; }
    728 	;
    729 
    730 tcp_flags
    731 	: IDENTIFIER	{ $$ = npfctl_parse_tcpflag($1); }
    732 	;
    733 
    734 icmp_type
    735 	: number	{ $$ = $1; }
    736 	| IDENTIFIER	{ $$ = npfctl_icmptype($<num>-1, $1); }
    737 	| VAR_ID
    738 	{
    739 		char *s = npfvar_expand_string(npfvar_lookup($1));
    740 		$$ = npfctl_icmptype($<num>-1, s);
    741 	}
    742 	;
    743 
    744 ifname
    745 	: some_name
    746 	{
    747 		npfctl_note_interface($1);
    748 		$$ = $1;
    749 	}
    750 	| VAR_ID
    751 	{
    752 		npfvar_t *vp = npfvar_lookup($1);
    753 		const int type = npfvar_get_type(vp, 0);
    754 		ifnet_addr_t *ifna;
    755 
    756 		switch (type) {
    757 		case NPFVAR_STRING:
    758 		case NPFVAR_IDENTIFIER:
    759 			$$ = npfvar_expand_string(vp);
    760 			break;
    761 		case NPFVAR_INTERFACE:
    762 			ifna = npfvar_get_data(vp, type, 0);
    763 			$$ = ifna->ifna_name;
    764 			break;
    765 		case -1:
    766 			yyerror("undefined variable '%s' for interface", $1);
    767 			break;
    768 		default:
    769 			yyerror("wrong variable '%s' type '%s' for interface",
    770 			    $1, npfvar_type(type));
    771 			break;
    772 		}
    773 		npfctl_note_interface($$);
    774 	}
    775 	;
    776 
    777 ifaddrs
    778 	: afamily PAR_OPEN ifname PAR_CLOSE
    779 	{
    780 		$$ = npfctl_parse_ifnet($3, $1);
    781 	}
    782 	;
    783 
    784 ifref
    785 	: ifname
    786 	| ifaddrs
    787 	{
    788 		ifnet_addr_t *ifna = npfvar_get_data($1, NPFVAR_INTERFACE, 0);
    789 		npfctl_note_interface(ifna->ifna_name);
    790 		$$ = ifna->ifna_name;
    791 	}
    792 	;
    793 
    794 number
    795 	: HEX		{ $$ = $1; }
    796 	| NUM		{ $$ = $1; }
    797 	;
    798 
    799 some_name
    800 	: IDENTIFIER	{ $$ = $1; }
    801 	| STRING	{ $$ = $1; }
    802 	;
    803 
    804 %%
    805