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