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