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