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