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