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