3 * Configuration file parser for mrouted.
5 * Written by Bill Fenner, NRL, 1994
7 * $FreeBSD: src/usr.sbin/mrouted/cfparse.y,v 1.10.2.2 2001/07/19 01:41:11 kris Exp $
8 * $DragonFly: src/usr.sbin/mrouted/cfparse.y,v 1.5 2006/08/03 16:40:48 swildner Exp $
9 * cfparse.y,v 3.8.4.30 1998/03/01 01:48:58 fenner Exp
17 * Local function declarations
19 static void fatal
(char *fmt
, ...
) __printflike
(1, 2);
20 static void warn
(char *fmt
, ...
) __printflike
(1, 2);
21 static void yyerror(char *s
);
22 static char * next_word
(void);
23 static int yylex(void);
24 static u_int32 valid_if
(char *s
);
25 static struct ifreq
* ifconfaddr
(struct ifconf
*ifcp
, u_int32 a
);
29 char *configfilename
= _PATH_MROUTED_CONF
;
31 extern
int cache_lifetime
;
32 extern
int prune_lifetime
;
34 /* imported from config.c, with slight memory leak */
35 extern
struct ifconf ifc
;
37 int allow_black_holes
= 0;
41 static struct uvif
*v
;
43 static int order
, state
;
44 static int noflood
= 0;
45 static int rexmit
= VIFF_REXMIT_PRUNES
;
54 struct addrmask bound
;
59 struct boundnam boundlist
[MAXBOUNDS
]; /* Max. of 20 named boundaries */
60 int numbounds
= 0; /* Number of named boundaries */
68 struct addrmask addrmask
;
70 struct vf_element
*filterelem
;
73 %token CACHE_LIFETIME PRUNE_LIFETIME PRUNING BLACK_HOLE NOFLOOD
74 %token PHYINT TUNNEL NAME
75 %token DISABLE IGMPV1 SRCRT BESIDE
76 %token METRIC THRESHOLD RATE_LIMIT BOUNDARY NETMASK ALTNET ADVERT_METRIC
77 %token FILTER ACCEPT DENY EXACT BIDIR REXMIT_PRUNES REXMIT_PRUNES2
78 %token PASSIVE ALLOW_NONPRUNERS
79 %token NOTRANSIT BLASTER FORCE_LEAF
80 %token PRUNE_LIFETIME2 NOFLOOD2
81 %token SYSNAM SYSCONTACT SYSVERSION SYSLOCATION
85 %token
<addrmask
> ADDRMASK
88 %type
<addr
> interface addrname
89 %type
<addrmask
> bound boundary addrmask
90 %type
<filterelem
> filter filtlist filtelement filtelem
111 fatal
("phyints must appear before tunnels");
113 for
(vifi
= 0, v
= uvifs
;
116 if
(!(v
->uv_flags
& VIFF_TUNNEL
) &&
117 $2 == v
->uv_lcl_addr
)
121 fatal
("%s is not a configured interface",
126 | TUNNEL interface addrname
{
134 ifr
= ifconfaddr
(&ifc
, $2);
136 fatal
("Tunnel local address %s is not mine",
139 if
(((ntohl
($2) & IN_CLASSA_NET
) >> IN_CLASSA_NSHIFT
) ==
141 fatal
("Tunnel local address %s is a loopback address",
144 if
(ifconfaddr
(&ifc
, $3) != 0)
145 fatal
("Tunnel remote address %s is one of mine",
148 for
(vifi
= 0, v
= uvifs
;
151 if
(v
->uv_flags
& VIFF_TUNNEL
) {
152 if
($3 == v
->uv_rmt_addr
)
153 fatal
("Duplicate tunnel to %s",
155 } else if
(!(v
->uv_flags
& VIFF_DISABLED
)) {
156 if
(($3 & v
->uv_subnetmask
) == v
->uv_subnet
)
157 fatal
("Unnecessary tunnel to %s, same subnet as vif %d (%s)",
158 inet_fmt
($3,s1
), vifi
, v
->uv_name
);
161 if
(numvifs
== MAXVIFS
)
162 fatal
("too many vifs");
164 strncpy
(ffr.ifr_name
, ifr
->ifr_name
, IFNAMSIZ
);
165 if
(ioctl
(udp_socket
, SIOCGIFFLAGS
, (char *)&ffr
)<0)
166 fatal
("ioctl SIOCGIFFLAGS on %s", ffr.ifr_name
);
170 v
->uv_flags
= VIFF_TUNNEL | rexmit | noflood
;
171 v
->uv_flags |
= VIFF_OTUNNEL
; /*XXX*/
175 strncpy
(v
->uv_name
, ffr.ifr_name
, IFNAMSIZ
);
176 v
->uv_name
[IFNAMSIZ
-1]='\0';
178 if
(!(ffr.ifr_flags
& IFF_UP
)) {
179 v
->uv_flags |
= VIFF_DOWN
;
186 if
(!(v
->uv_flags
& VIFF_OTUNNEL
)) {
191 "installing tunnel from %s to %s as vif #%u - rate=%d",
192 inet_fmt
($2, s1
), inet_fmt
($3, s2
),
193 numvifs
, v
->uv_rate_limit
);
198 | CACHE_LIFETIME NUMBER
{
200 if
($2 < MIN_CACHE_LIFETIME
) {
201 warn
("cache_lifetime %d must be at least %d",
202 $2, MIN_CACHE_LIFETIME
);
208 | PRUNE_LIFETIME NUMBER
{
210 if
($2 < MIN_PRUNE_LIFETIME
) {
211 warn
("prune_lifetime %d must be at least %d",
212 $2, MIN_PRUNE_LIFETIME
);
221 warn
("Disabling pruning is no longer supported");
226 #ifdef ALLOW_BLACK_HOLES
227 allow_black_holes
= 1;
231 * Turn off initial flooding (until subordinateness is learned
232 * via route exchange) on all phyints and set the default for
233 * all further tunnels.
239 noflood
= VIFF_NOFLOOD
;
240 for
(vifi
= 0, v
= uvifs
;
243 v
->uv_flags |
= VIFF_NOFLOOD
;
247 * Turn on prune retransmission on all interfaces.
248 * Tunnels default to retransmitting, so this just
249 * needs to turn on phyints.
255 for
(vifi
= 0, v
= uvifs
;
258 v
->uv_flags |
= VIFF_REXMIT_PRUNES
;
262 * If true, do as above. If false, no need to turn
263 * it off for phyints since they default to not
264 * rexmit; need to set flag to not rexmit on tunnels.
266 | REXMIT_PRUNES BOOLEAN
{
271 for
(vifi
= 0, v
= uvifs
;
274 v
->uv_flags |
= VIFF_REXMIT_PRUNES
;
280 | NAME STRING boundary
{ if
(numbounds
>= MAXBOUNDS
) {
281 fatal
("Too many named boundaries (max %d)", MAXBOUNDS
);
284 boundlist
[numbounds
].name
= malloc
(strlen
($2) + 1);
285 strcpy
(boundlist
[numbounds
].name
, $2);
286 boundlist
[numbounds
++].bound
= $3;
293 | SYSCONTACT STRING
{
298 | SYSVERSION STRING
{
303 | SYSLOCATION STRING
{
310 tunnelmods
: /* empty */
311 | tunnelmods tunnelmod
315 | BESIDE
{ v
->uv_flags |
= VIFF_OTUNNEL
; }
319 v
->uv_flags |
= VIFF_OTUNNEL
;
321 v
->uv_flags
&= ~VIFF_OTUNNEL
;
325 | SRCRT
{ fatal
("Source-route tunnels not supported"); }
333 | DISABLE
{ v
->uv_flags |
= VIFF_DISABLED
; }
334 | IGMPV1
{ v
->uv_flags |
= VIFF_IGMPV1
; }
336 u_int32 subnet
, mask
;
339 subnet
= v
->uv_lcl_addr
& mask
;
340 if
(!inet_valid_subnet
(subnet
, mask
))
341 fatal
("Invalid netmask");
342 v
->uv_subnet
= subnet
;
343 v
->uv_subnetmask
= mask
;
344 v
->uv_subnetbcast
= subnet | ~mask
;
348 warn
("Expected address after netmask keyword, ignored");
355 ph
= (struct phaddr
*)malloc
(sizeof
(struct phaddr
));
357 fatal
("out of memory");
359 VAL_TO_MASK
(ph
->pa_subnetmask
, $2.mask
);
361 ph
->pa_subnetmask
= v
->uv_subnetmask
;
362 ph
->pa_subnet
= $2.addr
& ph
->pa_subnetmask
;
363 ph
->pa_subnetbcast
= ph
->pa_subnet | ~ph
->pa_subnetmask
;
364 if
($2.addr
& ~ph
->pa_subnetmask
)
365 warn
("Extra subnet %s/%d has host bits set",
366 inet_fmt
($2.addr
,s1
), $2.mask
);
367 ph
->pa_next
= v
->uv_addrs
;
373 warn
("Expected address after altnet keyword, ignored");
378 v
->uv_flags |
= VIFF_FORCE_LEAF
;
381 | FORCE_LEAF BOOLEAN
{
384 v
->uv_flags |
= VIFF_FORCE_LEAF
;
386 v
->uv_flags
&= ~VIFF_FORCE_LEAF
;
392 mod
: THRESHOLD NUMBER
{ if
($2 < 1 ||
$2 > 255)
393 fatal
("Invalid threshold %d",$2);
394 v
->uv_threshold
= $2;
398 warn
("Expected number after threshold keyword, ignored");
401 | METRIC NUMBER
{ if
($2 < 1 ||
$2 > UNREACHABLE
)
402 fatal
("Invalid metric %d",$2);
407 warn
("Expected number after metric keyword, ignored");
410 | ADVERT_METRIC NUMBER
{ if
($2 < 0 ||
$2 > UNREACHABLE
- 1)
411 fatal
("Invalid advert_metric %d", $2);
416 warn
("Expected number after advert_metric keyword, ignored");
419 | RATE_LIMIT NUMBER
{ if
($2 > MAX_RATE_LIMIT
)
420 fatal
("Invalid rate_limit %d",$2);
421 v
->uv_rate_limit
= $2;
425 warn
("Expected number after rate_limit keyword, ignored");
430 struct vif_acl
*v_acl
;
432 v_acl
= (struct vif_acl
*)malloc
(sizeof
(struct vif_acl
));
434 fatal
("out of memory");
435 VAL_TO_MASK
(v_acl
->acl_mask
, $2.mask
);
436 v_acl
->acl_addr
= $2.addr
& v_acl
->acl_mask
;
437 if
($2.addr
& ~v_acl
->acl_mask
)
438 warn
("Boundary spec %s/%d has host bits set",
439 inet_fmt
($2.addr
,s1
),$2.mask
);
440 v_acl
->acl_next
= v
->uv_acl
;
446 warn
("Expected boundary spec after boundary keyword, ignored");
451 v
->uv_flags |
= VIFF_REXMIT_PRUNES
;
454 | REXMIT_PRUNES2 BOOLEAN
{
457 v
->uv_flags |
= VIFF_REXMIT_PRUNES
;
459 v
->uv_flags
&= ~VIFF_REXMIT_PRUNES
;
465 v
->uv_flags |
= VIFF_PASSIVE
;
470 v
->uv_flags |
= VIFF_NOFLOOD
;
475 v
->uv_flags |
= VIFF_NOTRANSIT
;
480 v
->uv_flags |
= VIFF_BLASTER
;
481 blaster_alloc
(v
- uvifs
);
486 v
->uv_flags |
= VIFF_ALLOW_NONPRUNERS
;
489 | PRUNE_LIFETIME2 NUMBER
{
491 if
($2 < MIN_PRUNE_LIFETIME
) {
492 warn
("prune_lifetime %d must be at least %d",
493 $2, MIN_PRUNE_LIFETIME
);
495 v
->uv_prune_lifetime
= $2;
501 if
(v
->uv_filter
== NULL
) {
502 struct vif_filter
*v_filter
;
504 v_filter
= (struct vif_filter
*)malloc
(sizeof
(struct vif_filter
));
505 if
(v_filter
== NULL
)
506 fatal
("out of memory");
507 v_filter
->vf_flags
= 0;
508 v_filter
->vf_type
= VFT_ACCEPT
;
509 v_filter
->vf_filter
= $2;
510 v
->uv_filter
= v_filter
;
511 } else if
(v
->uv_filter
->vf_type
!= VFT_ACCEPT
) {
512 fatal
("can't accept and deny");
514 struct vf_element
*p
;
516 p
= v
->uv_filter
->vf_filter
;
525 warn
("Expected filter spec after accept keyword, ignored");
530 if
(v
->uv_filter
== NULL
) {
531 struct vif_filter
*v_filter
;
533 v_filter
= (struct vif_filter
*)malloc
(sizeof
(struct vif_filter
));
534 if
(v_filter
== NULL
)
535 fatal
("out of memory");
536 v_filter
->vf_flags
= 0;
537 v_filter
->vf_type
= VFT_DENY
;
538 v_filter
->vf_filter
= $2;
539 v
->uv_filter
= v_filter
;
540 } else if
(v
->uv_filter
->vf_type
!= VFT_DENY
) {
541 fatal
("can't accept and deny");
543 struct vf_element
*p
;
545 p
= v
->uv_filter
->vf_filter
;
554 warn
("Expected filter spec after deny keyword, ignored");
559 if
(v
->uv_filter
== NULL
) {
560 fatal
("bidir goes after filters");
562 v
->uv_filter
->vf_flags |
= VFF_BIDIR
;
567 interface
: ADDR
{ $$
= $1; }
571 fatal
("Invalid interface name %s",$1);
575 addrname
: ADDR
{ $$
= $1; }
576 | STRING
{ struct hostent
*hp
;
578 if
((hp
= gethostbyname
($1)) == NULL ||
579 hp
->h_length
!= sizeof
($$
))
580 fatal
("No such host %s", $1);
582 if
(hp
->h_addr_list
[1])
583 fatal
("Hostname %s does not %s",
584 $1, "map to a unique address");
586 bcopy
(hp
->h_addr_list
[0], &$$
,
590 bound
: boundary
{ $$
= $1; }
593 for
(i
=0; i
< numbounds
; i
++) {
594 if
(!strcmp
(boundlist
[i
].name
, $1)) {
595 $$
= boundlist
[i
].bound
;
599 if
(i
== numbounds
) {
600 fatal
("Invalid boundary name %s",$1);
605 boundary
: ADDRMASK
{
607 #ifdef ALLOW_BLACK_HOLES
608 if
(!allow_black_holes
)
610 if
((ntohl
($1.addr
) & 0xff000000) != 0xef000000) {
611 fatal
("Boundaries must be 239.x.x.x, not %s/%d",
612 inet_fmt
($1.addr
, s1
), $1.mask
);
619 addrmask
: ADDRMASK
{ $$
= $1; }
620 | ADDR
{ $$.addr
= $1; $$.mask
= 0; }
623 filter
: filtlist
{ $$
= $1; }
624 | STRING
{ fatal
("named filters no implemented yet"); }
627 filtlist
: filtelement
{ $$
= $1; }
628 | filtelement filtlist
{ $1->vfe_next
= $2; $$
= $1; }
631 filtelement
: filtelem
{ $$
= $1; }
632 | filtelem EXACT
{ $1->vfe_flags |
= VFEF_EXACT
; $$
= $1; }
635 filtelem
: ADDRMASK
{
637 struct vf_element
*vfe
;
639 vfe
= (struct vf_element
*)malloc
(sizeof
(struct vf_element
));
641 fatal
("out of memory");
643 vfe
->vfe_addr
= $1.addr
;
644 VAL_TO_MASK
(vfe
->vfe_mask
, $1.mask
);
646 vfe
->vfe_next
= NULL
;
653 fatal
(char *fmt
, ...
)
656 char buf
[MAXHOSTNAMELEN
+ 100];
659 vsnprintf
(buf
, sizeof
(buf
), fmt
, ap
);
662 dolog
(LOG_ERR
,0,"%s: %s near line %d", configfilename
, buf
, lineno
);
672 vsnprintf
(buf
, sizeof
(buf
), fmt
, ap
);
675 dolog
(LOG_WARNING
,0,"%s: %s near line %d", configfilename
, buf
, lineno
);
681 dolog
(LOG_ERR
, 0, "%s: %s near line %d", configfilename
, s
, lineno
);
687 static char buf
[1024];
694 if
(fgets
(buf
, sizeof
(buf
), f
) == NULL
)
698 while
(*p
&& (*p
== ' ' ||
*p
== '\t')) /* skip whitespace */
701 p
= NULL
; /* skip comments */
708 while
(*p
&& *p
!= '"' && *p
!= '\n')
709 p
++; /* find next whitespace */
714 while
(*p
&& *p
!= ' ' && *p
!= '\t' && *p
!= '\n')
715 p
++; /* find next whitespace */
716 *p
++ = '\0'; /* null-terminate string */
720 continue
; /* if 0-length string, read another line */
728 * List of keywords. Must have an empty record at the end to terminate
729 * list. If a second value is specified, the first is used at the beginning
730 * of the file and the second is used while parsing interfaces (e.g. after
731 * the first "phyint" or "tunnel" keyword).
733 static struct keyword
{
738 { "cache_lifetime", CACHE_LIFETIME
},
739 { "prune_lifetime", PRUNE_LIFETIME
, PRUNE_LIFETIME2
},
740 { "pruning", PRUNING
},
741 { "phyint", PHYINT
},
742 { "tunnel", TUNNEL
},
743 { "disable", DISABLE
},
744 { "metric", METRIC
},
745 { "advert_metric", ADVERT_METRIC
},
746 { "threshold", THRESHOLD
},
747 { "rate_limit", RATE_LIMIT
},
748 { "force_leaf", FORCE_LEAF
},
750 { "sourceroute", SRCRT
},
751 { "boundary", BOUNDARY
},
752 { "netmask", NETMASK
},
753 { "igmpv1", IGMPV1
},
754 { "altnet", ALTNET
},
756 { "accept", ACCEPT
},
760 { "allow_nonpruners", ALLOW_NONPRUNERS
},
761 #ifdef ALLOW_BLACK_HOLES
762 { "allow_black_holes", BLACK_HOLE
},
764 { "noflood", NOFLOOD
, NOFLOOD2
},
765 { "notransit", NOTRANSIT
},
766 { "blaster", BLASTER
},
767 { "rexmit_prunes", REXMIT_PRUNES
, REXMIT_PRUNES2
},
768 { "passive", PASSIVE
},
769 { "beside", BESIDE
},
771 { "sysName", SYSNAM
},
772 { "sysContact", SYSCONTACT
},
773 { "sysVersion", SYSVERSION
},
774 { "sysLocation", SYSLOCATION
},
788 if
((q
= next_word
()) == NULL
) {
792 for
(w
= words
; w
->word
; w
++)
793 if
(!strcmp
(q
, w
->word
))
794 return
(state
&& w
->val2
) ? w
->val2
: w
->val1
;
796 if
(!strcmp
(q
,"on") ||
!strcmp
(q
,"yes")) {
800 if
(!strcmp
(q
,"off") ||
!strcmp
(q
,"no")) {
804 if
(!strcmp
(q
,"default")) {
805 yylval.addrmask.mask
= 0;
806 yylval.addrmask.addr
= 0;
809 if
(sscanf
(q
,"%[.0-9]/%d%c",s1
,&n
,s2
) == 2) {
810 if
((addr
= inet_parse
(s1
,1)) != 0xffffffff) {
811 yylval.addrmask.mask
= n
;
812 yylval.addrmask.addr
= addr
;
815 /* fall through to returning STRING */
817 if
(sscanf
(q
,"%[.0-9]%c",s1
,s2
) == 1) {
818 if
((addr
= inet_parse
(s1
,4)) != 0xffffffff &&
819 inet_valid_host
(addr
)) {
824 if
(sscanf
(q
,"0x%8x%c",&n
,s1
) == 1) {
828 if
(sscanf
(q
,"%d%c",&n
,s1
) == 1) {
834 if
(q
[ strlen
(q
)-1 ]=='"')
835 q
[ strlen
(q
)-1 ]='\0'; /* trash trailing quote */
845 config_vifs_from_file
(void)
852 if
((f
= fopen
(configfilename
, "r")) == NULL
) {
854 dolog
(LOG_ERR
, errno
, "can't open %s", configfilename
);
869 for
(vifi
=0, v
=uvifs
; vifi
<numvifs
; vifi
++, v
++)
870 if
(!strcmp
(v
->uv_name
, s
))
871 return v
->uv_lcl_addr
;
876 static struct ifreq
*
877 ifconfaddr
(struct ifconf
*ifcp
, u_int32 a
)
880 struct ifreq
*ifrp
= (struct ifreq
*)ifcp
->ifc_buf
;
881 struct ifreq
*ifend
= (struct ifreq
*)((char *)ifrp
+ ifcp
->ifc_len
);
883 while
(ifrp
< ifend
) {
884 if
(ifrp
->ifr_addr.sa_family
== AF_INET
&&
885 ((struct sockaddr_in
*)&ifrp
->ifr_addr
)->sin_addr.s_addr
== a
)
888 n
= ifrp
->ifr_addr.sa_len
+ sizeof
(ifrp
->ifr_name
);
889 if
(n
< sizeof
(*ifrp
))
892 ifrp
= (struct ifreq
*)((char *)ifrp
+ n
);