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