1/*- 2 * Copyright (c) 2011-2020 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Martin Husemann, Christos Zoulas and Mindaugas Rasiukevicius. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30%{ 31 32#include <err.h> 33#include <netdb.h> 34#include <stdio.h> 35#include <stdlib.h> 36#include <string.h> 37#ifdef __NetBSD__ 38#include <vis.h> 39#endif 40 41#include "npfctl.h" 42 43#define YYSTACKSIZE 4096 44 45int yystarttoken; 46const char * yyfilename; 47 48extern int yylineno, yycolumn; 49extern int yylex(int); 50 51void 52yyerror(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#ifdef __NetBSD__ 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 context = dst; 74#endif 75 fprintf(stderr, " near '%s'", context); 76 } 77 fprintf(stderr, "\n"); 78 exit(EXIT_FAILURE); 79} 80 81%} 82 83/* 84 * No conflicts allowed. Keep it this way. 85 */ 86%expect 0 87%expect-rr 0 88 89/* 90 * Depending on the mode of operation, set a different start symbol. 91 * Workaround yacc limitation by passing the start token. 92 */ 93%start input 94%token RULE_ENTRY_TOKEN MAP_ENTRY_TOKEN 95%lex-param { int yystarttoken } 96 97/* 98 * General tokens. 99 */ 100%token ALG 101%token ALGO 102%token ALL 103%token ANY 104%token APPLY 105%token ARROWBOTH 106%token ARROWLEFT 107%token ARROWRIGHT 108%token BLOCK 109%token CDB 110%token CONST 111%token CURLY_CLOSE 112%token CURLY_OPEN 113%token CODE 114%token COLON 115%token COMMA 116%token DEFAULT 117%token TDYNAMIC 118%token TSTATIC 119%token EQ 120%token EXCL_MARK 121%token TFILE 122%token FLAGS 123%token FROM 124%token GROUP 125%token HASH 126%token ICMPTYPE 127%token ID 128%token IFADDRS 129%token IN 130%token INET4 131%token INET6 132%token INTERFACE 133%token INVALID 134%token IPHASH 135%token IPSET 136%token LPM 137%token MAP 138%token NO_PORTS 139%token MINUS 140%token NAME 141%token NETMAP 142%token NPT66 143%token ON 144%token OFF 145%token OUT 146%token PAR_CLOSE 147%token PAR_OPEN 148%token PASS 149%token PCAP_FILTER 150%token PORT 151%token PROCEDURE 152%token PROTO 153%token FAMILY 154%token FINAL 155%token FORW 156%token RETURN 157%token RETURNICMP 158%token RETURNRST 159%token ROUNDROBIN 160%token RULESET 161%token SEPLINE 162%token SET 163%token SLASH 164%token STATEFUL 165%token STATEFUL_ALL 166%token TABLE 167%token TCP 168%token TO 169%token TREE 170%token TYPE 171%token <num> ICMP 172%token <num> ICMP6 173 174%token <num> HEX 175%token <str> IDENTIFIER 176%token <str> IPV4ADDR 177%token <str> IPV6ADDR 178%token <num> NUM 179%token <fpnum> FPNUM 180%token <str> STRING 181%token <str> PARAM 182%token <str> TABLE_ID 183%token <str> VAR_ID 184 185%type <str> addr some_name table_store dynamic_ifaddrs 186%type <str> proc_param_val opt_apply ifname on_ifname ifref 187%type <num> port opt_final number afamily opt_family 188%type <num> block_or_pass rule_dir group_dir block_opts 189%type <num> maybe_not opt_stateful icmp_type table_type 190%type <num> map_sd map_algo map_flags map_type 191%type <num> param_val 192%type <var> static_ifaddrs filt_addr_element 193%type <var> filt_port filt_port_list port_range icmp_type_and_code 194%type <var> filt_addr addr_and_mask tcp_flags tcp_flags_and_mask 195%type <var> procs proc_call proc_param_list proc_param 196%type <var> element list_elems list value filt_addr_list 197%type <var> opt_proto proto proto_elems 198%type <addrport> mapseg 199%type <filtopts> filt_opts all_or_filt_opts 200%type <optproto> rawproto 201%type <rulegroup> group_opts 202 203%union { 204 char * str; 205 unsigned long num; 206 double fpnum; 207 npfvar_t * var; 208 addr_port_t addrport; 209 filt_opts_t filtopts; 210 opt_proto_t optproto; 211 rule_group_t rulegroup; 212} 213 214%% 215 216input 217 : lines 218 | RULE_ENTRY_TOKEN rule 219 | MAP_ENTRY_TOKEN map 220 ; 221 222lines 223 : lines SEPLINE line 224 | line 225 ; 226 227line 228 : vardef 229 | table 230 | map 231 | group 232 | rproc 233 | alg 234 | set 235 | 236 ; 237 238alg 239 : ALG STRING 240 { 241 npfctl_build_alg($2); 242 } 243 ; 244 245param_val 246 : number { $$ = $1; } 247 | ON { $$ = true; } 248 | OFF { $$ = false; } 249 ; 250 251set 252 : SET PARAM param_val { 253 npfctl_setparam($2, $3); 254 } 255 ; 256 257/* 258 * A value - an element or a list of elements. 259 * Can be assigned to a variable or used inline. 260 */ 261 262vardef 263 : VAR_ID EQ value 264 { 265 npfvar_add($3, $1); 266 } 267 ; 268 269value 270 : element 271 | list 272 ; 273 274list 275 : CURLY_OPEN list_elems CURLY_CLOSE 276 { 277 $$ = $2; 278 } 279 ; 280 281list_elems 282 : list_elems COMMA element 283 { 284 npfvar_add_elements($1, $3); 285 } 286 | element 287 ; 288 289element 290 : IDENTIFIER 291 { 292 $$ = npfvar_create_from_string(NPFVAR_IDENTIFIER, $1); 293 } 294 | STRING 295 { 296 $$ = npfvar_create_from_string(NPFVAR_STRING, $1); 297 } 298 | number MINUS number 299 { 300 $$ = npfctl_parse_port_range($1, $3); 301 } 302 | number 303 { 304 $$ = npfvar_create_element(NPFVAR_NUM, &$1, sizeof($1)); 305 } 306 | VAR_ID 307 { 308 $$ = npfvar_create_from_string(NPFVAR_VAR_ID, $1); 309 } 310 | TABLE_ID { $$ = npfctl_parse_table_id($1); } 311 | dynamic_ifaddrs { $$ = npfctl_ifnet_table($1); } 312 | static_ifaddrs { $$ = $1; } 313 | addr_and_mask { $$ = $1; } 314 ; 315 316/* 317 * Table definition. 318 */ 319 320table 321 : TABLE TABLE_ID TYPE table_type table_store 322 { 323 npfctl_build_table($2, $4, $5); 324 } 325 ; 326 327table_type 328 : IPSET { $$ = NPF_TABLE_IPSET; } 329 | HASH 330 { 331 warnx("warning - table type \"hash\" is deprecated and may be " 332 "deleted in\nthe future; please use the \"ipset\" type " 333 "instead."); 334 $$ = NPF_TABLE_IPSET; 335 } 336 | LPM { $$ = NPF_TABLE_LPM; } 337 | TREE 338 { 339 warnx("warning - table type \"tree\" is deprecated and may be " 340 "deleted in\nthe future; please use the \"lpm\" type " 341 "instead."); 342 $$ = NPF_TABLE_LPM; 343 } 344 | CONST { $$ = NPF_TABLE_CONST; } 345 | CDB 346 { 347 warnx("warning -- table type \"cdb\" is deprecated and may be " 348 "deleted in\nthe future; please use the \"const\" type " 349 "instead."); 350 $$ = NPF_TABLE_CONST; 351 } 352 ; 353 354table_store 355 : TFILE STRING { $$ = $2; } 356 | TDYNAMIC 357 { 358 warnx("warning - the \"dynamic\" keyword for tables is obsolete"); 359 $$ = NULL; 360 } 361 | { $$ = NULL; } 362 ; 363 364/* 365 * Map definition. 366 */ 367 368map_sd 369 : TSTATIC { $$ = NPFCTL_NAT_STATIC; } 370 | TDYNAMIC { $$ = NPFCTL_NAT_DYNAMIC; } 371 | { $$ = NPFCTL_NAT_DYNAMIC; } 372 ; 373 374map_algo 375 : ALGO NETMAP { $$ = NPF_ALGO_NETMAP; } 376 | ALGO IPHASH { $$ = NPF_ALGO_IPHASH; } 377 | ALGO ROUNDROBIN { $$ = NPF_ALGO_RR; } 378 | ALGO NPT66 { $$ = NPF_ALGO_NPT66; } 379 | { $$ = 0; } 380 ; 381 382map_flags 383 : NO_PORTS { $$ = NPF_NAT_PORTS; } 384 | { $$ = 0; } 385 ; 386 387map_type 388 : ARROWBOTH { $$ = NPF_NATIN | NPF_NATOUT; } 389 | ARROWLEFT { $$ = NPF_NATIN; } 390 | ARROWRIGHT { $$ = NPF_NATOUT; } 391 ; 392 393mapseg 394 : filt_addr filt_port 395 { 396 $$.ap_netaddr = $1; 397 $$.ap_portrange = $2; 398 } 399 ; 400 401map 402 : MAP ifref map_sd map_algo map_flags mapseg map_type mapseg 403 PASS opt_family opt_proto all_or_filt_opts 404 { 405 npfctl_build_natseg($3, $7, $5, $2, &$6, &$8, $11, &$12, $4); 406 } 407 | MAP ifref map_sd map_algo map_flags mapseg map_type mapseg 408 { 409 npfctl_build_natseg($3, $7, $5, $2, &$6, &$8, NULL, NULL, $4); 410 } 411 | MAP ifref map_sd map_algo map_flags proto mapseg map_type mapseg 412 { 413 npfctl_build_natseg($3, $8, $5, $2, &$7, &$9, $6, NULL, $4); 414 } 415 | MAP RULESET group_opts 416 { 417 npfctl_build_maprset($3.rg_name, $3.rg_attr, $3.rg_ifname); 418 } 419 ; 420 421/* 422 * Rule procedure definition and its parameters. 423 */ 424 425rproc 426 : PROCEDURE STRING CURLY_OPEN procs CURLY_CLOSE 427 { 428 npfctl_build_rproc($2, $4); 429 } 430 ; 431 432procs 433 : procs SEPLINE proc_call 434 { 435 $$ = npfvar_add_elements($1, $3); 436 } 437 | proc_call { $$ = $1; } 438 ; 439 440proc_call 441 : IDENTIFIER COLON proc_param_list 442 { 443 proc_call_t pc; 444 445 pc.pc_name = estrdup($1); 446 pc.pc_opts = $3; 447 448 $$ = npfvar_create_element(NPFVAR_PROC, &pc, sizeof(pc)); 449 } 450 | { $$ = NULL; } 451 ; 452 453proc_param_list 454 : proc_param_list COMMA proc_param 455 { 456 $$ = npfvar_add_elements($1, $3); 457 } 458 | proc_param { $$ = $1; } 459 | { $$ = NULL; } 460 ; 461 462proc_param 463 : some_name proc_param_val 464 { 465 proc_param_t pp; 466 467 pp.pp_param = estrdup($1); 468 pp.pp_value = $2 ? estrdup($2) : NULL; 469 470 $$ = npfvar_create_element(NPFVAR_PROC_PARAM, &pp, sizeof(pp)); 471 } 472 ; 473 474proc_param_val 475 : some_name { $$ = $1; } 476 | number { (void)asprintf(&$$, "%ld", $1); } 477 | FPNUM { (void)asprintf(&$$, "%lf", $1); } 478 | { $$ = NULL; } 479 ; 480 481/* 482 * Group and dynamic ruleset definition. 483 */ 484 485group 486 : GROUP group_opts 487 { 488 /* Build a group. Increase the nesting level. */ 489 npfctl_build_group($2.rg_name, $2.rg_attr, 490 $2.rg_ifname, $2.rg_default); 491 } 492 ruleset_block 493 { 494 /* Decrease the nesting level. */ 495 npfctl_build_group_end(); 496 } 497 ; 498 499ruleset 500 : RULESET group_opts 501 { 502 /* Ruleset is a dynamic group. */ 503 npfctl_build_group($2.rg_name, $2.rg_attr | NPF_RULE_DYNAMIC, 504 $2.rg_ifname, $2.rg_default); 505 npfctl_build_group_end(); 506 } 507 ; 508 509group_dir 510 : FORW { $$ = NPF_RULE_FORW; } 511 | rule_dir 512 ; 513 514group_opts 515 : DEFAULT 516 { 517 memset(&$$, 0, sizeof(rule_group_t)); 518 $$.rg_default = true; 519 } 520 | STRING group_dir on_ifname 521 { 522 memset(&$$, 0, sizeof(rule_group_t)); 523 $$.rg_name = $1; 524 $$.rg_attr = $2; 525 $$.rg_ifname = $3; 526 } 527 ; 528 529ruleset_block 530 : CURLY_OPEN ruleset_def CURLY_CLOSE 531 ; 532 533ruleset_def 534 : ruleset_def SEPLINE rule_group 535 | rule_group 536 ; 537 538rule_group 539 : rule 540 | group 541 | ruleset 542 | 543 ; 544 545/* 546 * Rule and misc. 547 */ 548 549rule 550 : block_or_pass opt_stateful rule_dir opt_final on_ifname 551 opt_family opt_proto all_or_filt_opts opt_apply 552 { 553 npfctl_build_rule($1 | $2 | $3 | $4, $5, 554 $6, $7, &$8, NULL, $9); 555 } 556 | block_or_pass opt_stateful rule_dir opt_final on_ifname 557 PCAP_FILTER STRING opt_apply 558 { 559 npfctl_build_rule($1 | $2 | $3 | $4, $5, 560 AF_UNSPEC, NULL, NULL, $7, $8); 561 } 562 ; 563 564block_or_pass 565 : BLOCK block_opts { $$ = $2; } 566 | PASS { $$ = NPF_RULE_PASS; } 567 ; 568 569rule_dir 570 : IN { $$ = NPF_RULE_IN; } 571 | OUT { $$ = NPF_RULE_OUT; } 572 | { $$ = NPF_RULE_IN | NPF_RULE_OUT; } 573 ; 574 575opt_final 576 : FINAL { $$ = NPF_RULE_FINAL; } 577 | { $$ = 0; } 578 ; 579 580on_ifname 581 : ON ifref { $$ = $2; } 582 | { $$ = NULL; } 583 ; 584 585afamily 586 : INET4 { $$ = AF_INET; } 587 | INET6 { $$ = AF_INET6; } 588 ; 589 590maybe_not 591 : EXCL_MARK { $$ = true; } 592 | { $$ = false; } 593 ; 594 595opt_family 596 : FAMILY afamily { $$ = $2; } 597 | { $$ = AF_UNSPEC; } 598 ; 599 600rawproto 601 : TCP tcp_flags_and_mask 602 { 603 $$.op_proto = IPPROTO_TCP; 604 $$.op_opts = $2; 605 } 606 | ICMP icmp_type_and_code 607 { 608 $$.op_proto = IPPROTO_ICMP; 609 $$.op_opts = $2; 610 } 611 | ICMP6 icmp_type_and_code 612 { 613 $$.op_proto = IPPROTO_ICMPV6; 614 $$.op_opts = $2; 615 } 616 | some_name 617 { 618 $$.op_proto = npfctl_protono($1); 619 $$.op_opts = NULL; 620 } 621 | number 622 { 623 $$.op_proto = $1; 624 $$.op_opts = NULL; 625 } 626 ; 627 628proto_elems 629 : proto_elems COMMA rawproto 630 { 631 npfvar_t *pvar = npfvar_create_element( 632 NPFVAR_PROTO, &$3, sizeof($3)); 633 $$ = npfvar_add_elements($1, pvar); 634 } 635 | rawproto 636 { 637 $$ = npfvar_create_element(NPFVAR_PROTO, &$1, sizeof($1)); 638 } 639 ; 640 641proto 642 : PROTO rawproto 643 { 644 $$ = npfvar_create_element(NPFVAR_PROTO, &$2, sizeof($2)); 645 } 646 | PROTO CURLY_OPEN proto_elems CURLY_CLOSE 647 { 648 $$ = $3; 649 } 650 ; 651 652opt_proto 653 : proto { $$ = $1; } 654 | { $$ = NULL; } 655 ; 656 657all_or_filt_opts 658 : ALL 659 { 660 $$.fo_finvert = false; 661 $$.fo_from.ap_netaddr = NULL; 662 $$.fo_from.ap_portrange = NULL; 663 $$.fo_tinvert = false; 664 $$.fo_to.ap_netaddr = NULL; 665 $$.fo_to.ap_portrange = NULL; 666 } 667 | filt_opts { $$ = $1; } 668 ; 669 670opt_stateful 671 : STATEFUL { $$ = NPF_RULE_STATEFUL; } 672 | STATEFUL_ALL { $$ = NPF_RULE_STATEFUL | NPF_RULE_GSTATEFUL; } 673 | { $$ = 0; } 674 ; 675 676opt_apply 677 : APPLY STRING { $$ = $2; } 678 | { $$ = NULL; } 679 ; 680 681block_opts 682 : RETURNRST { $$ = NPF_RULE_RETRST; } 683 | RETURNICMP { $$ = NPF_RULE_RETICMP; } 684 | RETURN { $$ = NPF_RULE_RETRST | NPF_RULE_RETICMP; } 685 | { $$ = 0; } 686 ; 687 688filt_opts 689 : FROM maybe_not filt_addr filt_port TO maybe_not filt_addr filt_port 690 { 691 $$.fo_finvert = $2; 692 $$.fo_from.ap_netaddr = $3; 693 $$.fo_from.ap_portrange = $4; 694 $$.fo_tinvert = $6; 695 $$.fo_to.ap_netaddr = $7; 696 $$.fo_to.ap_portrange = $8; 697 } 698 | FROM maybe_not filt_addr filt_port 699 { 700 $$.fo_finvert = $2; 701 $$.fo_from.ap_netaddr = $3; 702 $$.fo_from.ap_portrange = $4; 703 $$.fo_tinvert = false; 704 $$.fo_to.ap_netaddr = NULL; 705 $$.fo_to.ap_portrange = NULL; 706 } 707 | TO maybe_not filt_addr filt_port 708 { 709 $$.fo_finvert = false; 710 $$.fo_from.ap_netaddr = NULL; 711 $$.fo_from.ap_portrange = NULL; 712 $$.fo_tinvert = $2; 713 $$.fo_to.ap_netaddr = $3; 714 $$.fo_to.ap_portrange = $4; 715 } 716 ; 717 718filt_addr_list 719 : filt_addr_list COMMA filt_addr_element 720 { 721 npfvar_add_elements($1, $3); 722 } 723 | filt_addr_element 724 ; 725 726filt_addr 727 : CURLY_OPEN filt_addr_list CURLY_CLOSE 728 { 729 $$ = $2; 730 } 731 | filt_addr_element { $$ = $1; } 732 | ANY { $$ = NULL; } 733 ; 734 735addr_and_mask 736 : addr SLASH number 737 { 738 $$ = npfctl_parse_fam_addr_mask($1, NULL, &$3); 739 } 740 | addr SLASH addr 741 { 742 $$ = npfctl_parse_fam_addr_mask($1, $3, NULL); 743 } 744 | addr 745 { 746 $$ = npfctl_parse_fam_addr_mask($1, NULL, NULL); 747 } 748 ; 749 750filt_addr_element 751 : addr_and_mask { assert($1 != NULL); $$ = $1; } 752 | static_ifaddrs 753 { 754 if (npfvar_get_count($1) != 1) 755 yyerror("multiple interfaces are not supported"); 756 ifnet_addr_t *ifna = npfvar_get_data($1, NPFVAR_INTERFACE, 0); 757 $$ = ifna->ifna_addrs; 758 } 759 | dynamic_ifaddrs { $$ = npfctl_ifnet_table($1); } 760 | TABLE_ID { $$ = npfctl_parse_table_id($1); } 761 | VAR_ID 762 { 763 npfvar_t *vp = npfvar_lookup($1); 764 int type = npfvar_get_type(vp, 0); 765 ifnet_addr_t *ifna; 766again: 767 switch (type) { 768 case NPFVAR_IDENTIFIER: 769 case NPFVAR_STRING: 770 vp = npfctl_parse_ifnet(npfvar_expand_string(vp), 771 AF_UNSPEC); 772 type = npfvar_get_type(vp, 0); 773 goto again; 774 case NPFVAR_FAM: 775 case NPFVAR_TABLE: 776 $$ = vp; 777 break; 778 case NPFVAR_INTERFACE: 779 $$ = NULL; 780 for (u_int i = 0; i < npfvar_get_count(vp); i++) { 781 ifna = npfvar_get_data(vp, type, i); 782 $$ = npfvar_add_elements($$, ifna->ifna_addrs); 783 } 784 break; 785 case -1: 786 yyerror("undefined variable '%s'", $1); 787 break; 788 default: 789 yyerror("wrong variable '%s' type '%s' for address " 790 "or interface", $1, npfvar_type(type)); 791 break; 792 } 793 } 794 ; 795 796addr 797 : IPV4ADDR { $$ = $1; } 798 | IPV6ADDR { $$ = $1; } 799 ; 800 801filt_port 802 : PORT CURLY_OPEN filt_port_list CURLY_CLOSE 803 { 804 $$ = npfctl_parse_port_range_variable(NULL, $3); 805 } 806 | PORT port_range { $$ = $2; } 807 | { $$ = NULL; } 808 ; 809 810filt_port_list 811 : filt_port_list COMMA port_range 812 { 813 npfvar_add_elements($1, $3); 814 } 815 | port_range 816 ; 817 818port_range 819 : port /* just port */ 820 { 821 $$ = npfctl_parse_port_range($1, $1); 822 } 823 | port MINUS port /* port from-to */ 824 { 825 $$ = npfctl_parse_port_range($1, $3); 826 } 827 | VAR_ID 828 { 829 npfvar_t *vp = npfvar_lookup($1); 830 $$ = npfctl_parse_port_range_variable($1, vp); 831 } 832 ; 833 834port 835 : number { $$ = $1; } 836 | IDENTIFIER { $$ = npfctl_portno($1); } 837 | STRING { $$ = npfctl_portno($1); } 838 ; 839 840icmp_type_and_code 841 : ICMPTYPE icmp_type 842 { 843 $$ = npfctl_parse_icmp($<num>0, $2, -1); 844 } 845 | ICMPTYPE icmp_type CODE number 846 { 847 $$ = npfctl_parse_icmp($<num>0, $2, $4); 848 } 849 | ICMPTYPE icmp_type CODE IDENTIFIER 850 { 851 $$ = npfctl_parse_icmp($<num>0, $2, 852 npfctl_icmpcode($<num>0, $2, $4)); 853 } 854 | ICMPTYPE icmp_type CODE VAR_ID 855 { 856 char *s = npfvar_expand_string(npfvar_lookup($4)); 857 $$ = npfctl_parse_icmp($<num>0, $2, 858 npfctl_icmpcode($<num>0, $2, s)); 859 } 860 | { $$ = NULL; } 861 ; 862 863tcp_flags_and_mask 864 : FLAGS tcp_flags SLASH tcp_flags 865 { 866 npfvar_add_elements($2, $4); 867 $$ = $2; 868 } 869 | FLAGS tcp_flags 870 { 871 if (npfvar_get_count($2) != 1) 872 yyerror("multiple tcpflags are not supported"); 873 char *s = npfvar_get_data($2, NPFVAR_TCPFLAG, 0); 874 npfvar_add_elements($2, npfctl_parse_tcpflag(s)); 875 $$ = $2; 876 } 877 | { $$ = NULL; } 878 ; 879 880tcp_flags 881 : IDENTIFIER { $$ = npfctl_parse_tcpflag($1); } 882 ; 883 884icmp_type 885 : number { $$ = $1; } 886 | IDENTIFIER { $$ = npfctl_icmptype($<num>-1, $1); } 887 | VAR_ID 888 { 889 char *s = npfvar_expand_string(npfvar_lookup($1)); 890 $$ = npfctl_icmptype($<num>-1, s); 891 } 892 ; 893 894ifname 895 : some_name 896 { 897 npfctl_note_interface($1); 898 $$ = $1; 899 } 900 | VAR_ID 901 { 902 npfvar_t *vp = npfvar_lookup($1); 903 const int type = npfvar_get_type(vp, 0); 904 ifnet_addr_t *ifna; 905 const char *name; 906 unsigned *tid; 907 bool ifaddr; 908 909 switch (type) { 910 case NPFVAR_STRING: 911 case NPFVAR_IDENTIFIER: 912 $$ = npfvar_expand_string(vp); 913 break; 914 case NPFVAR_INTERFACE: 915 if (npfvar_get_count(vp) != 1) 916 yyerror( 917 "multiple interfaces are not supported"); 918 ifna = npfvar_get_data(vp, type, 0); 919 $$ = ifna->ifna_name; 920 break; 921 case NPFVAR_TABLE: 922 tid = npfvar_get_data(vp, type, 0); 923 name = npfctl_table_getname(npfctl_config_ref(), 924 *tid, &ifaddr); 925 if (!ifaddr) { 926 yyerror("variable '%s' references a table " 927 "%s instead of an interface", $1, name); 928 } 929 $$ = estrdup(name); 930 break; 931 case -1: 932 yyerror("undefined variable '%s' for interface", $1); 933 break; 934 default: 935 yyerror("wrong variable '%s' type '%s' for interface", 936 $1, npfvar_type(type)); 937 break; 938 } 939 npfctl_note_interface($$); 940 } 941 ; 942 943static_ifaddrs 944 : afamily PAR_OPEN ifname PAR_CLOSE 945 { 946 $$ = npfctl_parse_ifnet($3, $1); 947 } 948 ; 949 950dynamic_ifaddrs 951 : IFADDRS PAR_OPEN ifname PAR_CLOSE 952 { 953 $$ = $3; 954 } 955 ; 956 957ifref 958 : ifname 959 | dynamic_ifaddrs 960 | static_ifaddrs 961 { 962 ifnet_addr_t *ifna; 963 964 if (npfvar_get_count($1) != 1) { 965 yyerror("multiple interfaces are not supported"); 966 } 967 ifna = npfvar_get_data($1, NPFVAR_INTERFACE, 0); 968 npfctl_note_interface(ifna->ifna_name); 969 $$ = ifna->ifna_name; 970 } 971 ; 972 973number 974 : HEX { $$ = $1; } 975 | NUM { $$ = $1; } 976 ; 977 978some_name 979 : IDENTIFIER { $$ = $1; } 980 | STRING { $$ = $1; } 981 ; 982 983%% 984