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