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