Home | History | Annotate | Line # | Download | only in npfctl
npf_parse.y revision 1.7
      1 /*	$NetBSD: npf_parse.y,v 1.7 2012/05/30 21:30:07 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 #include <assert.h>
     39 
     40 #include "npfctl.h"
     41 
     42 const char *		yyfilename;
     43 
     44 extern int		yylineno, yycolumn;
     45 extern int		yylex(void);
     46 
     47 /* Variable under construction (bottom up). */
     48 static npfvar_t *	cvar;
     49 
     50 void
     51 yyerror(const char *fmt, ...)
     52 {
     53 	extern int yyleng;
     54 	extern char *yytext;
     55 
     56 	char *msg, *context = xstrndup(yytext, yyleng);
     57 	size_t len = strlen(context);
     58 	char *dst = zalloc(len * 4 + 1);
     59 	va_list ap;
     60 
     61 	va_start(ap, fmt);
     62 	vasprintf(&msg, fmt, ap);
     63 	va_end(ap);
     64 
     65 	strvisx(dst, context, len, VIS_WHITE|VIS_CSTYLE);
     66 	fprintf(stderr, "%s:%d:%d: %s near '%s'\n", yyfilename, yylineno,
     67 	    yycolumn, msg, dst);
     68 	exit(EXIT_FAILURE);
     69 }
     70 
     71 %}
     72 
     73 %token			ALL
     74 %token			ANY
     75 %token			APPLY
     76 %token			ARROW
     77 %token			BINAT
     78 %token			BLOCK
     79 %token			CURLY_CLOSE
     80 %token			CURLY_OPEN
     81 %token			CODE
     82 %token			COLON
     83 %token			COMMA
     84 %token			DEFAULT
     85 %token			TDYNAMIC
     86 %token			EQ
     87 %token			TFILE
     88 %token			FLAGS
     89 %token			FROM
     90 %token			GROUP
     91 %token			HASH
     92 %token			ICMPTYPE
     93 %token			ID
     94 %token			IN
     95 %token			INET
     96 %token			INET6
     97 %token			INTERFACE
     98 %token			MINUS
     99 %token			NAT
    100 %token			NAME
    101 %token			ON
    102 %token			OUT
    103 %token			PAR_CLOSE
    104 %token			PAR_OPEN
    105 %token			PASS
    106 %token			PORT
    107 %token			PROCEDURE
    108 %token			PROTO
    109 %token			FAMILY
    110 %token			FINAL
    111 %token			RDR
    112 %token			RETURN
    113 %token			RETURNICMP
    114 %token			RETURNRST
    115 %token			SEPLINE
    116 %token			SLASH
    117 %token			STATEFUL
    118 %token			TABLE
    119 %token			TCP
    120 %token			TO
    121 %token			TREE
    122 %token			TYPE
    123 %token			UDP
    124 %token			ICMP
    125 
    126 %token	<num>		HEX
    127 %token	<str>		IDENTIFIER
    128 %token	<str>		IPV4ADDR
    129 %token	<str>		IPV6ADDR
    130 %token	<num>		NUM
    131 %token	<str>		STRING
    132 %token	<str>		TABLE_ID
    133 %token	<str>		VAR_ID
    134 
    135 %type	<str>		addr, iface_name, moduleargname, list_elem, table_store
    136 %type	<str>		opt_apply
    137 %type	<num>		ifindex, port, opt_final, on_iface
    138 %type	<num>		block_or_pass, rule_dir, block_opts, family, opt_family
    139 %type	<num>		opt_stateful, icmp_type, table_type
    140 %type	<var>		addr_or_iface, port_range, icmp_type_and_code
    141 %type	<var>		filt_addr, addr_and_mask, tcp_flags, tcp_flags_and_mask
    142 %type	<var>		modulearg_opts, procs, proc_op, modulearg, moduleargs
    143 %type	<filtopts>	filt_opts, all_or_filt_opts
    144 %type	<optproto>	opt_proto
    145 %type	<rulegroup>	group_attr, group_opt
    146 
    147 %union {
    148 	char *		str;
    149 	unsigned long	num;
    150 	filt_opts_t	filtopts;
    151 	npfvar_t *	var;
    152 	opt_proto_t	optproto;
    153 	rule_group_t	rulegroup;
    154 }
    155 
    156 %%
    157 
    158 input
    159 	: lines
    160 	;
    161 
    162 lines
    163 	: line SEPLINE lines
    164 	| line
    165 	;
    166 
    167 line
    168 	: def
    169 	| table
    170 	| nat
    171 	| group
    172 	| rproc
    173 	|
    174 	;
    175 
    176 def
    177 	: VAR_ID
    178 	{
    179 		cvar = npfvar_create($1);
    180 		npfvar_add(cvar);
    181 	}
    182 	  EQ definition
    183 	{
    184 		cvar = NULL;
    185 	}
    186 	;
    187 
    188 definition
    189 	: list_elem
    190 	| listdef
    191 	;
    192 
    193 listdef
    194 	: CURLY_OPEN list_elems CURLY_CLOSE
    195 	;
    196 
    197 list_elems
    198 	: list_elem COMMA list_elems
    199 	| list_elem
    200 	;
    201 
    202 list_elem
    203 	: IDENTIFIER
    204 	{
    205 		npfvar_t *vp = npfvar_create(".identifier");
    206 		npfvar_add_element(vp, NPFVAR_IDENTIFIER, $1, strlen($1) + 1);
    207 		npfvar_add_elements(cvar, vp);
    208 	}
    209 	| STRING
    210 	{
    211 		npfvar_t *vp = npfvar_create(".string");
    212 		npfvar_add_element(vp, NPFVAR_STRING, $1, strlen($1) + 1);
    213 		npfvar_add_elements(cvar, vp);
    214 	}
    215 	| NUM MINUS NUM
    216 	{
    217 		npfvar_t *vp = npfctl_parse_port_range($1, $3);
    218 		npfvar_add_elements(cvar, vp);
    219 	}
    220 	| NUM
    221 	{
    222 		npfvar_t *vp = npfvar_create(".num");
    223 		npfvar_add_element(vp, NPFVAR_NUM, &$1, sizeof($1));
    224 		npfvar_add_elements(cvar, vp);
    225 	}
    226 	| VAR_ID
    227 	{
    228 		npfvar_t *vp = npfvar_create(".var_id");
    229 		npfvar_add_element(vp, NPFVAR_VAR_ID, $1, strlen($1) + 1);
    230 		npfvar_add_elements(cvar, vp);
    231 	}
    232 	| addr_and_mask
    233 	{
    234 		npfvar_add_elements(cvar, $1);
    235 	}
    236 	;
    237 
    238 table
    239 	: TABLE TABLE_ID TYPE table_type table_store
    240 	{
    241 		npfctl_build_table($2, $4, $5);
    242 	}
    243 	;
    244 
    245 table_type
    246 	: HASH		{ $$ = NPF_TABLE_HASH; }
    247 	| TREE		{ $$ = NPF_TABLE_TREE; }
    248 	;
    249 
    250 table_store
    251 	: TDYNAMIC	{ $$ = NULL; }
    252 	| TFILE STRING	{ $$ = $2; }
    253 	;
    254 
    255 nat
    256 	: natdef
    257 	| binatdef
    258 	| rdrdef
    259 	;
    260 
    261 natdef
    262 	: NAT ifindex filt_opts ARROW addr_or_iface
    263 	{
    264 		npfctl_build_nat(NPFCTL_NAT, $2, &$3, $5, NULL);
    265 	}
    266 	;
    267 
    268 binatdef
    269 	: BINAT ifindex filt_opts ARROW addr_or_iface
    270 	{
    271 		npfctl_build_nat(NPFCTL_BINAT, $2, &$3, $5, $3.fo_from);
    272 	}
    273 	;
    274 
    275 rdrdef
    276 	: RDR ifindex filt_opts ARROW addr_or_iface port_range
    277 	{
    278 		npfctl_build_nat(NPFCTL_RDR, $2, &$3, $5, $6);
    279 	}
    280 	;
    281 
    282 rproc
    283 	: PROCEDURE STRING CURLY_OPEN procs CURLY_CLOSE
    284 	{
    285 		npfctl_build_rproc($2, $4);
    286 	}
    287 	;
    288 
    289 procs
    290 	: proc_op SEPLINE procs	{ $$ = npfvar_add_elements($1, $3); }
    291 	| proc_op		{ $$ = $1; }
    292 	;
    293 
    294 proc_op
    295 	: IDENTIFIER COLON moduleargs
    296 	{
    297 		proc_op_t po;
    298 
    299 		po.po_name = xstrdup($1);
    300 		po.po_opts = $3;
    301 		$$ = npfvar_create(".proc_ops");
    302 		npfvar_add_element($$, NPFVAR_PROC_OP, &po, sizeof(po));
    303 	}
    304 	|	{ $$ = NULL; }
    305 	;
    306 
    307 moduleargs
    308 	: modulearg COMMA moduleargs
    309 	{
    310 		$$ = npfvar_add_elements($1, $3);
    311 	}
    312 	| modulearg	{ $$ = $1; }
    313 	|		{ $$ = NULL; }
    314 	;
    315 
    316 modulearg
    317 	: moduleargname modulearg_opts
    318 	{
    319 		module_arg_t ma;
    320 
    321 		ma.ma_name = xstrdup($1);
    322 		ma.ma_opts = $2;
    323 		$$ = npfvar_create(".module_arg");
    324 		npfvar_add_element($$, NPFVAR_MODULE_ARG, &ma, sizeof(ma));
    325 	}
    326 	;
    327 
    328 moduleargname
    329 	: STRING	{ $$ = $1; }
    330 	| IDENTIFIER	{ $$ = $1; }
    331 	;
    332 
    333 modulearg_opts
    334 	: STRING modulearg_opts
    335 	{
    336 		npfvar_t *vp = npfvar_create(".modstring");
    337 		npfvar_add_element(vp, NPFVAR_STRING, $1, strlen($1) + 1);
    338 		$$ = $2 ? npfvar_add_elements($2, vp) : vp;
    339 	}
    340 	| IDENTIFIER modulearg_opts
    341 	{
    342 		npfvar_t *vp = npfvar_create(".modident");
    343 		npfvar_add_element(vp, NPFVAR_IDENTIFIER, $1, strlen($1) + 1);
    344 		$$ = $2 ? npfvar_add_elements($2, vp) : vp;
    345 	}
    346 	| NUM modulearg_opts
    347 	{
    348 		npfvar_t *vp = npfvar_create(".modnum");
    349 		npfvar_add_element(vp, NPFVAR_NUM, &$1, sizeof($1));
    350 		$$ = $2 ? npfvar_add_elements($2, vp) : vp;
    351 	}
    352 	|	{ $$ = NULL; }
    353 	;
    354 
    355 group
    356 	: GROUP PAR_OPEN group_attr PAR_CLOSE
    357 	{
    358 		npfctl_build_group($3.rg_name, $3.rg_attr, $3.rg_ifnum);
    359 	}
    360 	  ruleset
    361 	;
    362 
    363 group_attr
    364 	: group_opt COMMA group_attr
    365 	{
    366 		$$ = $3;
    367 
    368 		if (($1.rg_name && $$.rg_name) ||
    369 		    ($1.rg_ifnum && $$.rg_ifnum) ||
    370 		    ($1.rg_attr & $$.rg_attr) != 0)
    371 			yyerror("duplicate group option");
    372 
    373 		if ($1.rg_name) {
    374 			$$.rg_name = $1.rg_name;
    375 		}
    376 		if ($1.rg_attr) {
    377 			$$.rg_attr |= $1.rg_attr;
    378 		}
    379 		if ($1.rg_ifnum) {
    380 			$$.rg_ifnum = $1.rg_ifnum;
    381 		}
    382 	}
    383 	| group_opt		{ $$ = $1; }
    384 	;
    385 
    386 group_opt
    387 	: DEFAULT
    388 	{
    389 		$$.rg_name = NULL;
    390 		$$.rg_ifnum = 0;
    391 		$$.rg_attr = NPF_RULE_DEFAULT;
    392 	}
    393 	| NAME STRING
    394 	{
    395 		$$.rg_name = $2;
    396 		$$.rg_ifnum = 0;
    397 		$$.rg_attr = 0;
    398 	}
    399 	| INTERFACE ifindex
    400 	{
    401 		$$.rg_name = NULL;
    402 		$$.rg_ifnum = $2;
    403 		$$.rg_attr = 0;
    404 	}
    405 	| rule_dir
    406 	{
    407 		$$.rg_name = NULL;
    408 		$$.rg_ifnum = 0;
    409 		$$.rg_attr = $1;
    410 	}
    411 	;
    412 
    413 ruleset
    414 	: CURLY_OPEN rules CURLY_CLOSE
    415 	;
    416 
    417 rules
    418 	: rule SEPLINE rules
    419 	| rule
    420 	;
    421 
    422 rule
    423 	: block_or_pass opt_stateful rule_dir opt_final on_iface opt_family
    424 	  opt_proto all_or_filt_opts opt_apply
    425 	{
    426 		/*
    427 		 * Arguments: attributes, interface index, address
    428 		 * family, protocol options, filter options.
    429 		 */
    430 		npfctl_build_rule($1 | $2 | $3 | $4, $5,
    431 		    $6, &$7, &$8, $9);
    432 	}
    433 	|
    434 	;
    435 
    436 block_or_pass
    437 	: BLOCK block_opts	{ $$ = $2; }
    438 	| PASS			{ $$ = NPF_RULE_PASS; }
    439 	;
    440 
    441 rule_dir
    442 	: IN			{ $$ = NPF_RULE_IN; }
    443 	| OUT			{ $$ = NPF_RULE_OUT; }
    444 	|			{ $$ = NPF_RULE_IN | NPF_RULE_OUT; }
    445 	;
    446 
    447 opt_final
    448 	: FINAL			{ $$ = NPF_RULE_FINAL; }
    449 	|			{ $$ = 0; }
    450 	;
    451 
    452 on_iface
    453 	: ON ifindex		{ $$ = $2; }
    454 	|			{ $$ = 0; }
    455 	;
    456 
    457 family
    458 	: INET			{ $$ = AF_INET; }
    459 	| INET6			{ $$ = AF_INET6; }
    460 	;
    461 
    462 opt_proto
    463 	: PROTO TCP tcp_flags_and_mask
    464 	{
    465 		$$.op_proto = IPPROTO_TCP;
    466 		$$.op_opts = $3;
    467 	}
    468 	| PROTO ICMP icmp_type_and_code
    469 	{
    470 		$$.op_proto = IPPROTO_ICMP;
    471 		$$.op_opts = $3;
    472 	}
    473 	| PROTO UDP
    474 	{
    475 		$$.op_proto = IPPROTO_UDP;
    476 		$$.op_opts = NULL;
    477 	}
    478 	|
    479 	{
    480 		$$.op_proto = -1;
    481 		$$.op_opts = NULL;
    482 	}
    483 	;
    484 
    485 opt_family
    486 	: FAMILY family		{ $$ = $2; }
    487 	|			{ $$ = AF_UNSPEC; }
    488 	;
    489 
    490 all_or_filt_opts
    491 	: ALL
    492 	{
    493 		$$.fo_from = NULL;
    494 		$$.fo_from_port_range = NULL;
    495 		$$.fo_to = NULL;
    496 		$$.fo_to_port_range = NULL;
    497 	}
    498 	| filt_opts	{ $$ = $1; }
    499 	;
    500 
    501 opt_stateful
    502 	: STATEFUL	{ $$ = NPF_RULE_KEEPSTATE; }
    503 	|		{ $$ = 0; }
    504 	;
    505 
    506 opt_apply
    507 	: APPLY STRING	{ $$ = $2; }
    508 	|		{ $$ = NULL; }
    509 	;
    510 
    511 block_opts
    512 	: RETURNRST	{ $$ = NPF_RULE_RETRST; }
    513 	| RETURNICMP	{ $$ = NPF_RULE_RETICMP; }
    514 	| RETURN	{ $$ = NPF_RULE_RETRST | NPF_RULE_RETICMP; }
    515 	|		{ $$ = 0; }
    516 	;
    517 
    518 filt_opts
    519 	: FROM filt_addr port_range TO filt_addr port_range
    520 	{
    521 		$$.fo_from = $2;
    522 		$$.fo_from_port_range = $3;
    523 		$$.fo_to = $5;
    524 		$$.fo_to_port_range = $6;
    525 	}
    526 	| FROM filt_addr port_range
    527 	{
    528 		$$.fo_from = $2;
    529 		$$.fo_from_port_range = $3;
    530 		$$.fo_to = NULL;
    531 		$$.fo_to_port_range = NULL;
    532 	}
    533 	| TO filt_addr port_range
    534 	{
    535 		$$.fo_from = NULL;
    536 		$$.fo_from_port_range = NULL;
    537 		$$.fo_to = $2;
    538 		$$.fo_to_port_range = $3;
    539 	}
    540 	;
    541 
    542 filt_addr
    543 	: addr_or_iface		{ $$ = $1; }
    544 	| TABLE_ID		{ $$ = npfctl_parse_table_id($1); }
    545 	| ANY			{ $$ = NULL; }
    546 	;
    547 
    548 addr_and_mask
    549 	: addr SLASH NUM
    550 	{
    551 		$$ = npfctl_parse_fam_addr_mask($1, NULL, &$3);
    552 	}
    553 	| addr SLASH HEX
    554 	{
    555 		$$ = npfctl_parse_fam_addr_mask($1, NULL, &$3);
    556 	}
    557 	| addr SLASH addr
    558 	{
    559 		$$ = npfctl_parse_fam_addr_mask($1, $3, NULL);
    560 	}
    561 	| addr
    562 	{
    563 		$$ = npfctl_parse_fam_addr_mask($1, NULL, NULL);
    564 	}
    565 	;
    566 
    567 addr_or_iface
    568 	: addr_and_mask	{ assert($1 != NULL); $$ = $1; }
    569 	| iface_name
    570 	{
    571 		$$ = npfctl_parse_iface($1);
    572 	}
    573 	| VAR_ID
    574 	{
    575 		npfvar_t *vp = npfvar_lookup($1);
    576 		const int type = npfvar_get_type(vp, 0);
    577 
    578 		switch (type) {
    579 		case NPFVAR_VAR_ID:
    580 		case NPFVAR_STRING:
    581 			$$ = npfctl_parse_iface(npfvar_expand_string(vp));
    582 			break;
    583 		case NPFVAR_FAM:
    584 			$$ = vp;
    585 			break;
    586 		case -1:
    587 			yyerror("undefined variable '%s' for interface", $1);
    588 			break;
    589 		default:
    590 			yyerror("wrong variable '%s' type '%s' or interface",
    591 			    $1, npfvar_type(type));
    592 			$$ = NULL;
    593 			break;
    594 		}
    595 	}
    596 	;
    597 
    598 addr
    599 	: IPV4ADDR	{ $$ = $1; }
    600 	| IPV6ADDR	{ $$ = $1; }
    601 	;
    602 
    603 
    604 port_range
    605 	: PORT port		/* just port */
    606 	{
    607 		$$ = npfctl_parse_port_range($2, $2);
    608 	}
    609 	| PORT port MINUS port	/* port from:to */
    610 	{
    611 		$$ = npfctl_parse_port_range($2, $4);
    612 	}
    613 	| PORT VAR_ID {
    614 		$$ = npfctl_parse_port_range_variable($2);
    615 	}
    616 	|
    617 	{
    618 		$$ = NULL;
    619 	}
    620 	;
    621 
    622 port
    623 	: NUM		{ $$ = $1; }
    624 	| IDENTIFIER	{ $$ = npfctl_portno($1); }
    625 	;
    626 
    627 icmp_type_and_code
    628 	: ICMPTYPE icmp_type
    629 	{
    630 		$$ = npfctl_parse_icmp($2, -1);
    631 	}
    632 	| ICMPTYPE icmp_type CODE NUM
    633 	{
    634 		$$ = npfctl_parse_icmp($2, $4);
    635 	}
    636 	| ICMPTYPE icmp_type CODE IDENTIFIER
    637 	{
    638 		$$ = npfctl_parse_icmp($2, npfctl_icmpcode($2, $4));
    639 	}
    640 	| ICMPTYPE icmp_type CODE VAR_ID
    641 	{
    642 		char *s = npfvar_expand_string(npfvar_lookup($4));
    643 		$$ = npfctl_parse_icmp($2, npfctl_icmpcode($2, s));
    644 	}
    645 	|
    646 	{
    647 		$$ = npfctl_parse_icmp(-1, -1);
    648 	}
    649 	;
    650 
    651 tcp_flags_and_mask
    652 	: FLAGS tcp_flags SLASH tcp_flags
    653 	{
    654 		npfvar_add_elements($2, $4);
    655 		$$ = $2;
    656 	}
    657 	| FLAGS tcp_flags
    658 	{
    659 		char *s = npfvar_get_data($2, NPFVAR_TCPFLAG, 0);
    660 		npfvar_add_elements($2, npfctl_parse_tcpflag(s));
    661 		$$ = $2;
    662 	}
    663 	|		{ $$ = NULL; }
    664 	;
    665 
    666 tcp_flags
    667 	: IDENTIFIER	{ $$ = npfctl_parse_tcpflag($1); }
    668 	;
    669 
    670 icmp_type
    671 	: NUM		{ $$ = $1; }
    672 	| IDENTIFIER	{ $$ = npfctl_icmptype($1); }
    673 	| VAR_ID
    674 	{
    675 		char *s = npfvar_expand_string(npfvar_lookup($1));
    676 		$$ = npfctl_icmptype(s);
    677 	}
    678 	;
    679 
    680 ifindex
    681 	: iface_name
    682 	{
    683 		$$ = npfctl_find_ifindex($1);
    684 	}
    685 	| VAR_ID
    686 	{
    687 		npfvar_t *vp = npfvar_lookup($1);
    688 		const int type = npfvar_get_type(vp, 0);
    689 
    690 		switch (type) {
    691 		case NPFVAR_VAR_ID:
    692 		case NPFVAR_STRING:
    693 			$$ = npfctl_find_ifindex(npfvar_expand_string(vp));
    694 			break;
    695 		case -1:
    696 			yyerror("undefined variable '%s' for interface", $1);
    697 			break;
    698 		default:
    699 			yyerror("wrong variable '%s' type '%s' for interface",
    700 			    $1, npfvar_type(type));
    701 			$$ = -1;
    702 			break;
    703 		}
    704 	}
    705 	;
    706 
    707 iface_name
    708 	: IDENTIFIER	{ $$ = $1; }
    709 	| STRING	{ $$ = $1; }
    710 	;
    711 
    712 %%
    713