Home | History | Annotate | Line # | Download | only in npfctl
npf_parse.y revision 1.21
      1 /*	$NetBSD: npf_parse.y,v 1.21 2013/03/18 02:17:49 rmind Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2011-2012 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 and Christos Zoulas.
      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 /* Variable under construction (bottom up). */
     50 static npfvar_t *	cvar;
     51 
     52 void
     53 yyerror(const char *fmt, ...)
     54 {
     55 	extern int yyleng;
     56 	extern char *yytext;
     57 
     58 	char *msg, *context = estrndup(yytext, yyleng);
     59 	bool eol = (*context == '\n');
     60 	va_list ap;
     61 
     62 	va_start(ap, fmt);
     63 	vasprintf(&msg, fmt, ap);
     64 	va_end(ap);
     65 
     66 	fprintf(stderr, "%s:%d:%d: %s", yyfilename,
     67 	    yylineno - (int)eol, yycolumn, msg);
     68 	if (!eol) {
     69 		size_t len = strlen(context);
     70 		char *dst = ecalloc(1, len * 4 + 1);
     71 
     72 		strvisx(dst, context, len, VIS_WHITE|VIS_CSTYLE);
     73 		fprintf(stderr, " near '%s'", dst);
     74 	}
     75 	fprintf(stderr, "\n");
     76 	exit(EXIT_FAILURE);
     77 }
     78 
     79 #define	CHECK_PARSER_FILE				\
     80 	if (yyparsetarget != NPFCTL_PARSE_FILE)		\
     81 		yyerror("rule must be in the group");
     82 
     83 #define	CHECK_PARSER_STRING				\
     84 	if (yyparsetarget != NPFCTL_PARSE_STRING)	\
     85 		yyerror("invalid rule syntax");
     86 
     87 %}
     88 
     89 %token			ALL
     90 %token			ANY
     91 %token			APPLY
     92 %token			ARROWBOTH
     93 %token			ARROWLEFT
     94 %token			ARROWRIGHT
     95 %token			BLOCK
     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			IFNET
    113 %token			IN
    114 %token			INET
    115 %token			INET6
    116 %token			INTERFACE
    117 %token			MAP
    118 %token			MINUS
    119 %token			NAME
    120 %token			ON
    121 %token			OUT
    122 %token			PAR_CLOSE
    123 %token			PAR_OPEN
    124 %token			PASS
    125 %token			PORT
    126 %token			PROCEDURE
    127 %token			PROTO
    128 %token			FAMILY
    129 %token			FINAL
    130 %token			FORW
    131 %token			RETURN
    132 %token			RETURNICMP
    133 %token			RETURNRST
    134 %token			RULESET
    135 %token			SEPLINE
    136 %token			SLASH
    137 %token			STATEFUL
    138 %token			TABLE
    139 %token			TCP
    140 %token			TO
    141 %token			TREE
    142 %token			TYPE
    143 %token	<num>		ICMP
    144 %token	<num>		ICMP6
    145 
    146 %token	<num>		HEX
    147 %token	<str>		IDENTIFIER
    148 %token	<str>		IPV4ADDR
    149 %token	<str>		IPV6ADDR
    150 %token	<num>		NUM
    151 %token	<fpnum>		FPNUM
    152 %token	<str>		STRING
    153 %token	<str>		TABLE_ID
    154 %token	<str>		VAR_ID
    155 
    156 %type	<str>		addr, some_name, list_elem, table_store, string
    157 %type	<str>		proc_param_val, opt_apply
    158 %type	<num>		ifindex, port, opt_final, on_ifindex
    159 %type	<num>		afamily, opt_family
    160 %type	<num>		block_or_pass, rule_dir, block_opts
    161 %type	<num>		opt_stateful, icmp_type, table_type, map_sd, map_type
    162 %type	<var>		ifnet, addr_or_ifnet, port_range, icmp_type_and_code
    163 %type	<var>		filt_addr, addr_and_mask, tcp_flags, tcp_flags_and_mask
    164 %type	<var>		procs, proc_call, proc_param_list, proc_param
    165 %type	<addrport>	mapseg
    166 %type	<filtopts>	filt_opts, all_or_filt_opts
    167 %type	<optproto>	opt_proto
    168 %type	<rulegroup>	group_attr, group_opt
    169 
    170 %union {
    171 	char *		str;
    172 	unsigned long	num;
    173 	double		fpnum;
    174 	npfvar_t *	var;
    175 	addr_port_t	addrport;
    176 	filt_opts_t	filtopts;
    177 	opt_proto_t	optproto;
    178 	rule_group_t	rulegroup;
    179 }
    180 
    181 %%
    182 
    183 input
    184 	: { CHECK_PARSER_FILE	} lines
    185 	| { CHECK_PARSER_STRING	} rule
    186 	;
    187 
    188 lines
    189 	: line SEPLINE lines
    190 	| line
    191 	;
    192 
    193 line
    194 	: def
    195 	| table
    196 	| map
    197 	| group
    198 	| rproc
    199 	|
    200 	;
    201 
    202 def
    203 	: VAR_ID
    204 	{
    205 		cvar = npfvar_create($1);
    206 		npfvar_add(cvar);
    207 	}
    208 	  EQ definition
    209 	{
    210 		cvar = NULL;
    211 	}
    212 	;
    213 
    214 definition
    215 	: list_elem
    216 	| listdef
    217 	;
    218 
    219 listdef
    220 	: CURLY_OPEN list_elems CURLY_CLOSE
    221 	;
    222 
    223 list_elems
    224 	: list_elem COMMA list_elems
    225 	| list_elem
    226 	;
    227 
    228 list_elem
    229 	: IDENTIFIER
    230 	{
    231 		npfvar_t *vp = npfvar_create(".identifier");
    232 		npfvar_add_element(vp, NPFVAR_IDENTIFIER, $1, strlen($1) + 1);
    233 		npfvar_add_elements(cvar, vp);
    234 	}
    235 	| STRING
    236 	{
    237 		npfvar_t *vp = npfvar_create(".string");
    238 		npfvar_add_element(vp, NPFVAR_STRING, $1, strlen($1) + 1);
    239 		npfvar_add_elements(cvar, vp);
    240 	}
    241 	| NUM MINUS NUM
    242 	{
    243 		npfvar_t *vp = npfctl_parse_port_range($1, $3);
    244 		npfvar_add_elements(cvar, vp);
    245 	}
    246 	| NUM
    247 	{
    248 		npfvar_t *vp = npfvar_create(".num");
    249 		npfvar_add_element(vp, NPFVAR_NUM, &$1, sizeof($1));
    250 		npfvar_add_elements(cvar, vp);
    251 	}
    252 	| VAR_ID
    253 	{
    254 		npfvar_t *vp = npfvar_create(".var_id");
    255 		npfvar_add_element(vp, NPFVAR_VAR_ID, $1, strlen($1) + 1);
    256 		npfvar_add_elements(cvar, vp);
    257 	}
    258 	| ifnet
    259 	{
    260 		npfvar_add_elements(cvar, $1);
    261 	}
    262 	| addr_and_mask
    263 	{
    264 		npfvar_add_elements(cvar, $1);
    265 	}
    266 	;
    267 
    268 table
    269 	: TABLE TABLE_ID TYPE table_type table_store
    270 	{
    271 		npfctl_build_table($2, $4, $5);
    272 	}
    273 	;
    274 
    275 table_type
    276 	: HASH		{ $$ = NPF_TABLE_HASH; }
    277 	| TREE		{ $$ = NPF_TABLE_TREE; }
    278 	;
    279 
    280 table_store
    281 	: TDYNAMIC	{ $$ = NULL; }
    282 	| TFILE STRING	{ $$ = $2; }
    283 	;
    284 
    285 map_sd
    286 	: TSTATIC	{ $$ = NPFCTL_NAT_STATIC; }
    287 	| TDYNAMIC	{ $$ = NPFCTL_NAT_DYNAMIC; }
    288 	|		{ $$ = NPFCTL_NAT_DYNAMIC; }
    289 	;
    290 
    291 map_type
    292 	: ARROWBOTH	{ $$ = NPF_NATIN | NPF_NATOUT; }
    293 	| ARROWLEFT	{ $$ = NPF_NATIN; }
    294 	| ARROWRIGHT	{ $$ = NPF_NATOUT; }
    295 	;
    296 
    297 mapseg
    298 	: addr_or_ifnet port_range
    299 	{
    300 		$$.ap_netaddr = $1;
    301 		$$.ap_portrange = $2;
    302 	}
    303 	;
    304 
    305 map
    306 	: MAP ifindex map_sd mapseg map_type mapseg PASS filt_opts
    307 	{
    308 		npfctl_build_natseg($3, $5, $2, &$4, &$6, &$8);
    309 	}
    310 	| MAP ifindex map_sd mapseg map_type mapseg
    311 	{
    312 		npfctl_build_natseg($3, $5, $2, &$4, &$6, NULL);
    313 	}
    314 	| MAP RULESET PAR_OPEN group_attr PAR_CLOSE
    315 	{
    316 		npfctl_build_maprset($4.rg_name, $4.rg_attr, $4.rg_ifnum);
    317 	}
    318 	;
    319 
    320 rproc
    321 	: PROCEDURE STRING CURLY_OPEN procs CURLY_CLOSE
    322 	{
    323 		npfctl_build_rproc($2, $4);
    324 	}
    325 	;
    326 
    327 procs
    328 	: proc_call SEPLINE procs
    329 	{
    330 		$$ = npfvar_add_elements($1, $3);
    331 	}
    332 	| proc_call	{ $$ = $1; }
    333 	;
    334 
    335 proc_call
    336 	: IDENTIFIER COLON proc_param_list
    337 	{
    338 		proc_call_t pc;
    339 
    340 		pc.pc_name = estrdup($1);
    341 		pc.pc_opts = $3;
    342 		$$ = npfvar_create(".proc_call");
    343 		npfvar_add_element($$, NPFVAR_PROC, &pc, sizeof(pc));
    344 	}
    345 	|	{ $$ = NULL; }
    346 	;
    347 
    348 proc_param_list
    349 	: proc_param COMMA proc_param_list
    350 	{
    351 		$$ = npfvar_add_elements($1, $3);
    352 	}
    353 	| proc_param	{ $$ = $1; }
    354 	|		{ $$ = NULL; }
    355 	;
    356 
    357 proc_param
    358 	/* Key and value pair. */
    359 	: some_name proc_param_val
    360 	{
    361 		proc_param_t pp;
    362 
    363 		pp.pp_param = estrdup($1);
    364 		pp.pp_value = $2 ? estrdup($2) : NULL;
    365 		$$ = npfvar_create(".proc_param");
    366 		npfvar_add_element($$, NPFVAR_PROC_PARAM, &pp, sizeof(pp));
    367 	}
    368 	;
    369 
    370 proc_param_val
    371 	: some_name	{ $$ = $1; }
    372 	| NUM		{ (void)asprintf(&$$, "%ld", $1); }
    373 	| FPNUM		{ (void)asprintf(&$$, "%lf", $1); }
    374 	|		{ $$ = NULL; }
    375 	;
    376 
    377 group
    378 	: GROUP PAR_OPEN group_attr PAR_CLOSE
    379 	{
    380 		/* Build a group.  Increases the nesting level. */
    381 		npfctl_build_group($3.rg_name, $3.rg_attr,
    382 		    $3.rg_ifnum, $3.rg_default);
    383 	}
    384 	  ruleset_block
    385 	{
    386 		/* Decrease the nesting level. */
    387 		npfctl_build_group_end();
    388 	}
    389 	;
    390 
    391 ruleset
    392 	: RULESET PAR_OPEN group_attr PAR_CLOSE
    393 	{
    394 		/* Ruleset is a dynamic group. */
    395 		npfctl_build_group($3.rg_name, $3.rg_attr | NPF_RULE_DYNAMIC,
    396 		    $3.rg_ifnum, $3.rg_default);
    397 		npfctl_build_group_end();
    398 	}
    399 
    400 group_attr
    401 	: group_opt COMMA group_attr
    402 	{
    403 		$$ = $3;
    404 
    405 		if (($1.rg_name && $$.rg_name) ||
    406 		    ($1.rg_ifnum && $$.rg_ifnum) ||
    407 		    ($1.rg_attr & $$.rg_attr) != 0)
    408 			yyerror("duplicate group option");
    409 
    410 		if ($1.rg_name) {
    411 			$$.rg_name = $1.rg_name;
    412 		}
    413 		if ($1.rg_attr) {
    414 			$$.rg_attr |= $1.rg_attr;
    415 		}
    416 		if ($1.rg_ifnum) {
    417 			$$.rg_ifnum = $1.rg_ifnum;
    418 		}
    419 		if ($1.rg_default) {
    420 			$$.rg_default = $1.rg_default;
    421 		}
    422 	}
    423 	| group_opt		{ $$ = $1; }
    424 	;
    425 
    426 group_opt
    427 	: DEFAULT
    428 	{
    429 		memset(&$$, 0, sizeof(rule_group_t));
    430 		$$.rg_default = true;
    431 	}
    432 	| NAME STRING
    433 	{
    434 		memset(&$$, 0, sizeof(rule_group_t));
    435 		$$.rg_name = $2;
    436 	}
    437 	| INTERFACE ifindex
    438 	{
    439 		memset(&$$, 0, sizeof(rule_group_t));
    440 		$$.rg_ifnum = $2;
    441 	}
    442 	| TDYNAMIC
    443 	{
    444 		memset(&$$, 0, sizeof(rule_group_t));
    445 		$$.rg_attr = NPF_RULE_DYNAMIC;
    446 	}
    447 	| FORW
    448 	{
    449 		memset(&$$, 0, sizeof(rule_group_t));
    450 		$$.rg_attr = NPF_RULE_FORW;
    451 	}
    452 	| rule_dir
    453 	{
    454 		memset(&$$, 0, sizeof(rule_group_t));
    455 		$$.rg_attr = $1;
    456 	}
    457 	;
    458 
    459 ruleset_block
    460 	: CURLY_OPEN ruleset_def CURLY_CLOSE
    461 	;
    462 
    463 ruleset_def
    464 	: rule_group SEPLINE ruleset_def
    465 	| rule_group
    466 	;
    467 
    468 rule_group
    469 	: rule
    470 	| group
    471 	| ruleset
    472 	|
    473 
    474 rule
    475 	: block_or_pass opt_stateful rule_dir opt_final on_ifindex
    476 	  opt_family opt_proto all_or_filt_opts opt_apply
    477 	{
    478 		npfctl_build_rule($1 | $2 | $3 | $4, $5,
    479 		    $6, &$7, &$8, $9);
    480 	}
    481 	;
    482 
    483 block_or_pass
    484 	: BLOCK block_opts	{ $$ = $2; }
    485 	| PASS			{ $$ = NPF_RULE_PASS; }
    486 	;
    487 
    488 rule_dir
    489 	: IN			{ $$ = NPF_RULE_IN; }
    490 	| OUT			{ $$ = NPF_RULE_OUT; }
    491 	|			{ $$ = NPF_RULE_IN | NPF_RULE_OUT; }
    492 	;
    493 
    494 opt_final
    495 	: FINAL			{ $$ = NPF_RULE_FINAL; }
    496 	|			{ $$ = 0; }
    497 	;
    498 
    499 on_ifindex
    500 	: ON ifindex		{ $$ = $2; }
    501 	|			{ $$ = 0; }
    502 	;
    503 
    504 afamily
    505 	: INET			{ $$ = AF_INET; }
    506 	| INET6			{ $$ = AF_INET6; }
    507 	;
    508 
    509 opt_family
    510 	: FAMILY afamily	{ $$ = $2; }
    511 	|			{ $$ = AF_UNSPEC; }
    512 	;
    513 
    514 opt_proto
    515 	: PROTO TCP tcp_flags_and_mask
    516 	{
    517 		$$.op_proto = IPPROTO_TCP;
    518 		$$.op_opts = $3;
    519 	}
    520 	| PROTO ICMP icmp_type_and_code
    521 	{
    522 		$$.op_proto = IPPROTO_ICMP;
    523 		$$.op_opts = $3;
    524 	}
    525 	| PROTO ICMP6 icmp_type_and_code
    526 	{
    527 		$$.op_proto = IPPROTO_ICMPV6;
    528 		$$.op_opts = $3;
    529 	}
    530 	| PROTO some_name
    531 	{
    532 		$$.op_proto = npfctl_protono($2);
    533 		$$.op_opts = NULL;
    534 	}
    535 	| PROTO NUM
    536 	{
    537 		$$.op_proto = $2;
    538 		$$.op_opts = NULL;
    539 	}
    540 	|
    541 	{
    542 		$$.op_proto = -1;
    543 		$$.op_opts = NULL;
    544 	}
    545 	;
    546 
    547 all_or_filt_opts
    548 	: ALL
    549 	{
    550 		$$.fo_from.ap_netaddr = NULL;
    551 		$$.fo_from.ap_portrange = NULL;
    552 		$$.fo_to.ap_netaddr = NULL;
    553 		$$.fo_to.ap_portrange = NULL;
    554 	}
    555 	| filt_opts	{ $$ = $1; }
    556 	;
    557 
    558 opt_stateful
    559 	: STATEFUL	{ $$ = NPF_RULE_STATEFUL; }
    560 	|		{ $$ = 0; }
    561 	;
    562 
    563 opt_apply
    564 	: APPLY STRING	{ $$ = $2; }
    565 	|		{ $$ = NULL; }
    566 	;
    567 
    568 block_opts
    569 	: RETURNRST	{ $$ = NPF_RULE_RETRST; }
    570 	| RETURNICMP	{ $$ = NPF_RULE_RETICMP; }
    571 	| RETURN	{ $$ = NPF_RULE_RETRST | NPF_RULE_RETICMP; }
    572 	|		{ $$ = 0; }
    573 	;
    574 
    575 filt_opts
    576 	: FROM filt_addr port_range TO filt_addr port_range
    577 	{
    578 		$$.fo_from.ap_netaddr = $2;
    579 		$$.fo_from.ap_portrange = $3;
    580 		$$.fo_to.ap_netaddr = $5;
    581 		$$.fo_to.ap_portrange = $6;
    582 	}
    583 	| FROM filt_addr port_range
    584 	{
    585 		$$.fo_from.ap_netaddr = $2;
    586 		$$.fo_from.ap_portrange = $3;
    587 		$$.fo_to.ap_netaddr = NULL;
    588 		$$.fo_to.ap_portrange = NULL;
    589 	}
    590 	| TO filt_addr port_range
    591 	{
    592 		$$.fo_from.ap_netaddr = NULL;
    593 		$$.fo_from.ap_portrange = NULL;
    594 		$$.fo_to.ap_netaddr = $2;
    595 		$$.fo_to.ap_portrange = $3;
    596 	}
    597 	;
    598 
    599 filt_addr
    600 	: addr_or_ifnet		{ $$ = $1; }
    601 	| TABLE_ID		{ $$ = npfctl_parse_table_id($1); }
    602 	| ANY			{ $$ = NULL; }
    603 	;
    604 
    605 addr_and_mask
    606 	: addr SLASH NUM
    607 	{
    608 		$$ = npfctl_parse_fam_addr_mask($1, NULL, &$3);
    609 	}
    610 	| addr SLASH HEX
    611 	{
    612 		$$ = npfctl_parse_fam_addr_mask($1, NULL, &$3);
    613 	}
    614 	| addr SLASH addr
    615 	{
    616 		$$ = npfctl_parse_fam_addr_mask($1, $3, NULL);
    617 	}
    618 	| addr
    619 	{
    620 		$$ = npfctl_parse_fam_addr_mask($1, NULL, NULL);
    621 	}
    622 	;
    623 
    624 addr_or_ifnet
    625 	: addr_and_mask
    626 	{
    627 		assert($1 != NULL);
    628 		$$ = $1;
    629 	}
    630 	| ifnet
    631 	{
    632 		ifnet_addr_t *ifna = npfvar_get_data($1, NPFVAR_INTERFACE, 0);
    633 		$$ = ifna->ifna_addrs;
    634 	}
    635 	| VAR_ID
    636 	{
    637 		npfvar_t *vp = npfvar_lookup($1);
    638 		int type = npfvar_get_type(vp, 0);
    639 		ifnet_addr_t *ifna;
    640 
    641 again:
    642 		switch (type) {
    643 		case NPFVAR_IDENTIFIER:
    644 		case NPFVAR_STRING:
    645 			vp = npfctl_parse_ifnet(npfvar_expand_string(vp),
    646 			    AF_UNSPEC);
    647 			type = npfvar_get_type(vp, 0);
    648 			goto again;
    649 		case NPFVAR_FAM:
    650 			$$ = vp;
    651 			break;
    652 		case NPFVAR_INTERFACE:
    653 			ifna = npfvar_get_data(vp, type, 0);
    654 			$$ = ifna->ifna_addrs;
    655 			break;
    656 		case -1:
    657 			yyerror("undefined variable '%s'", $1);
    658 			break;
    659 		default:
    660 			yyerror("wrong variable '%s' type '%s' for address "
    661 			    "or interface", $1, npfvar_type(type));
    662 			break;
    663 		}
    664 	}
    665 	;
    666 
    667 addr
    668 	: IPV4ADDR	{ $$ = $1; }
    669 	| IPV6ADDR	{ $$ = $1; }
    670 	;
    671 
    672 port_range
    673 	: PORT port		/* just port */
    674 	{
    675 		$$ = npfctl_parse_port_range($2, $2);
    676 	}
    677 	| PORT port MINUS port	/* port from-to */
    678 	{
    679 		$$ = npfctl_parse_port_range($2, $4);
    680 	}
    681 	| PORT VAR_ID
    682 	{
    683 		$$ = npfctl_parse_port_range_variable($2);
    684 	}
    685 	|
    686 	{
    687 		$$ = NULL;
    688 	}
    689 	;
    690 
    691 port
    692 	: NUM		{ $$ = $1; }
    693 	| IDENTIFIER	{ $$ = npfctl_portno($1); }
    694 	| STRING	{ $$ = npfctl_portno($1); }
    695 	;
    696 
    697 icmp_type_and_code
    698 	: ICMPTYPE icmp_type
    699 	{
    700 		$$ = npfctl_parse_icmp($<num>0, $2, -1);
    701 	}
    702 	| ICMPTYPE icmp_type CODE NUM
    703 	{
    704 		$$ = npfctl_parse_icmp($<num>0, $2, $4);
    705 	}
    706 	| ICMPTYPE icmp_type CODE IDENTIFIER
    707 	{
    708 		$$ = npfctl_parse_icmp($<num>0, $2,
    709 		    npfctl_icmpcode($<num>0, $2, $4));
    710 	}
    711 	| ICMPTYPE icmp_type CODE VAR_ID
    712 	{
    713 		char *s = npfvar_expand_string(npfvar_lookup($4));
    714 		$$ = npfctl_parse_icmp($<num>0, $2,
    715 		    npfctl_icmpcode($<num>0, $2, s));
    716 	}
    717 	|
    718 	{
    719 		$$ = npfctl_parse_icmp($<num>0, -1, -1);
    720 	}
    721 	;
    722 
    723 tcp_flags_and_mask
    724 	: FLAGS tcp_flags SLASH tcp_flags
    725 	{
    726 		npfvar_add_elements($2, $4);
    727 		$$ = $2;
    728 	}
    729 	| FLAGS tcp_flags
    730 	{
    731 		char *s = npfvar_get_data($2, NPFVAR_TCPFLAG, 0);
    732 		npfvar_add_elements($2, npfctl_parse_tcpflag(s));
    733 		$$ = $2;
    734 	}
    735 	|		{ $$ = NULL; }
    736 	;
    737 
    738 tcp_flags
    739 	: IDENTIFIER	{ $$ = npfctl_parse_tcpflag($1); }
    740 	;
    741 
    742 icmp_type
    743 	: NUM		{ $$ = $1; }
    744 	| IDENTIFIER	{ $$ = npfctl_icmptype($<num>-1, $1); }
    745 	| VAR_ID
    746 	{
    747 		char *s = npfvar_expand_string(npfvar_lookup($1));
    748 		$$ = npfctl_icmptype($<num>-1, s);
    749 	}
    750 	;
    751 
    752 string
    753 	: IDENTIFIER
    754 	{
    755 		$$ = $1;
    756 	}
    757 	| VAR_ID
    758 	{
    759 		npfvar_t *vp = npfvar_lookup($1);
    760 		const int type = npfvar_get_type(vp, 0);
    761 
    762 		switch (type) {
    763 		case NPFVAR_STRING:
    764 		case NPFVAR_IDENTIFIER:
    765 			$$ = npfvar_expand_string(vp);
    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 string",
    772 			    $1, npfvar_type(type));
    773 			break;
    774 		}
    775 	}
    776 	;
    777 
    778 ifnet
    779 	: IFNET PAR_OPEN string PAR_CLOSE
    780 	{
    781 		$$ = npfctl_parse_ifnet($3, AF_UNSPEC);
    782 	}
    783 	| afamily PAR_OPEN string PAR_CLOSE
    784 	{
    785 		$$ = npfctl_parse_ifnet($3, $1);
    786 	}
    787 	;
    788 
    789 ifindex
    790 	: some_name
    791 	{
    792 		$$ = npfctl_find_ifindex($1);
    793 	}
    794 	| ifnet
    795 	{
    796 		ifnet_addr_t *ifna = npfvar_get_data($1, NPFVAR_INTERFACE, 0);
    797 		$$ = ifna->ifna_index;
    798 	}
    799 	| VAR_ID
    800 	{
    801 		npfvar_t *vp = npfvar_lookup($1);
    802 		const int type = npfvar_get_type(vp, 0);
    803 		ifnet_addr_t *ifna;
    804 
    805 		switch (type) {
    806 		case NPFVAR_STRING:
    807 		case NPFVAR_IDENTIFIER:
    808 			$$ = npfctl_find_ifindex(npfvar_expand_string(vp));
    809 			break;
    810 		case NPFVAR_INTERFACE:
    811 			ifna = npfvar_get_data(vp, type, 0);
    812 			$$ = ifna->ifna_index;
    813 			break;
    814 		case -1:
    815 			yyerror("undefined variable '%s' for interface", $1);
    816 			break;
    817 		default:
    818 			yyerror("wrong variable '%s' type '%s' for interface",
    819 			    $1, npfvar_type(type));
    820 			break;
    821 		}
    822 	}
    823 	;
    824 
    825 some_name
    826 	: IDENTIFIER	{ $$ = $1; }
    827 	| STRING	{ $$ = $1; }
    828 	;
    829 
    830 %%
    831