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
);
30 char *configfilename
= _PATH_MROUTED_CONF
;
32 extern
int cache_lifetime
;
33 extern
int prune_lifetime
;
35 /* imported from config.c, with slight memory leak */
36 extern
struct ifconf ifc
;
38 int allow_black_holes
= 0;
42 static struct uvif
*v
;
44 static int order
, state
;
45 static int noflood
= 0;
46 static int rexmit
= VIFF_REXMIT_PRUNES
;
55 struct addrmask bound
;
60 struct boundnam boundlist
[MAXBOUNDS
]; /* Max. of 20 named boundaries */
61 int numbounds
= 0; /* Number of named boundaries */
69 struct addrmask addrmask
;
71 struct vf_element
*filterelem
;
74 %token CACHE_LIFETIME PRUNE_LIFETIME PRUNING BLACK_HOLE NOFLOOD
75 %token PHYINT TUNNEL NAME
76 %token DISABLE IGMPV1 SRCRT BESIDE
77 %token METRIC THRESHOLD RATE_LIMIT BOUNDARY NETMASK ALTNET ADVERT_METRIC
78 %token FILTER ACCEPT DENY EXACT BIDIR REXMIT_PRUNES REXMIT_PRUNES2
79 %token PASSIVE ALLOW_NONPRUNERS
80 %token NOTRANSIT BLASTER FORCE_LEAF
81 %token PRUNE_LIFETIME2 NOFLOOD2
82 %token SYSNAM SYSCONTACT SYSVERSION SYSLOCATION
86 %token
<addrmask
> ADDRMASK
89 %type
<addr
> interface addrname
90 %type
<addrmask
> bound boundary addrmask
91 %type
<filterelem
> filter filtlist filtelement filtelem
112 fatal
("phyints must appear before tunnels");
114 for
(vifi
= 0, v
= uvifs
;
117 if
(!(v
->uv_flags
& VIFF_TUNNEL
) &&
118 $2 == v
->uv_lcl_addr
)
122 fatal
("%s is not a configured interface",
127 | TUNNEL interface addrname
{
135 ifr
= ifconfaddr
(&ifc
, $2);
137 fatal
("Tunnel local address %s is not mine",
140 if
(((ntohl
($2) & IN_CLASSA_NET
) >> IN_CLASSA_NSHIFT
) ==
142 fatal
("Tunnel local address %s is a loopback address",
145 if
(ifconfaddr
(&ifc
, $3) != 0)
146 fatal
("Tunnel remote address %s is one of mine",
149 for
(vifi
= 0, v
= uvifs
;
152 if
(v
->uv_flags
& VIFF_TUNNEL
) {
153 if
($3 == v
->uv_rmt_addr
)
154 fatal
("Duplicate tunnel to %s",
156 } else if
(!(v
->uv_flags
& VIFF_DISABLED
)) {
157 if
(($3 & v
->uv_subnetmask
) == v
->uv_subnet
)
158 fatal
("Unnecessary tunnel to %s, same subnet as vif %d (%s)",
159 inet_fmt
($3,s1
), vifi
, v
->uv_name
);
162 if
(numvifs
== MAXVIFS
)
163 fatal
("too many vifs");
165 strncpy
(ffr.ifr_name
, ifr
->ifr_name
, IFNAMSIZ
);
166 if
(ioctl
(udp_socket
, SIOCGIFFLAGS
, (char *)&ffr
)<0)
167 fatal
("ioctl SIOCGIFFLAGS on %s", ffr.ifr_name
);
171 v
->uv_flags
= VIFF_TUNNEL | rexmit | noflood
;
172 v
->uv_flags |
= VIFF_OTUNNEL
; /*XXX*/
176 strncpy
(v
->uv_name
, ffr.ifr_name
, IFNAMSIZ
);
177 v
->uv_name
[IFNAMSIZ
-1]='\0';
179 if
(!(ffr.ifr_flags
& IFF_UP
)) {
180 v
->uv_flags |
= VIFF_DOWN
;
187 if
(!(v
->uv_flags
& VIFF_OTUNNEL
)) {
192 "installing tunnel from %s to %s as vif #%u - rate=%d",
193 inet_fmt
($2, s1
), inet_fmt
($3, s2
),
194 numvifs
, v
->uv_rate_limit
);
199 | CACHE_LIFETIME NUMBER
{
201 if
($2 < MIN_CACHE_LIFETIME
) {
202 warn
("cache_lifetime %d must be at least %d",
203 $2, MIN_CACHE_LIFETIME
);
209 | PRUNE_LIFETIME NUMBER
{
211 if
($2 < MIN_PRUNE_LIFETIME
) {
212 warn
("prune_lifetime %d must be at least %d",
213 $2, MIN_PRUNE_LIFETIME
);
222 warn
("Disabling pruning is no longer supported");
227 #ifdef ALLOW_BLACK_HOLES
228 allow_black_holes
= 1;
232 * Turn off initial flooding (until subordinateness is learned
233 * via route exchange) on all phyints and set the default for
234 * all further tunnels.
240 noflood
= VIFF_NOFLOOD
;
241 for
(vifi
= 0, v
= uvifs
;
244 v
->uv_flags |
= VIFF_NOFLOOD
;
248 * Turn on prune retransmission on all interfaces.
249 * Tunnels default to retransmitting, so this just
250 * needs to turn on phyints.
256 for
(vifi
= 0, v
= uvifs
;
259 v
->uv_flags |
= VIFF_REXMIT_PRUNES
;
263 * If true, do as above. If false, no need to turn
264 * it off for phyints since they default to not
265 * rexmit; need to set flag to not rexmit on tunnels.
267 | REXMIT_PRUNES BOOLEAN
{
272 for
(vifi
= 0, v
= uvifs
;
275 v
->uv_flags |
= VIFF_REXMIT_PRUNES
;
281 | NAME STRING boundary
{ if
(numbounds
>= MAXBOUNDS
) {
282 fatal
("Too many named boundaries (max %d)", MAXBOUNDS
);
285 boundlist
[numbounds
].name
= malloc
(strlen
($2) + 1);
286 strcpy
(boundlist
[numbounds
].name
, $2);
287 boundlist
[numbounds
++].bound
= $3;
294 | SYSCONTACT STRING
{
299 | SYSVERSION STRING
{
304 | SYSLOCATION STRING
{
311 tunnelmods
: /* empty */
312 | tunnelmods tunnelmod
316 | BESIDE
{ v
->uv_flags |
= VIFF_OTUNNEL
; }
320 v
->uv_flags |
= VIFF_OTUNNEL
;
322 v
->uv_flags
&= ~VIFF_OTUNNEL
;
326 | SRCRT
{ fatal
("Source-route tunnels not supported"); }
334 | DISABLE
{ v
->uv_flags |
= VIFF_DISABLED
; }
335 | IGMPV1
{ v
->uv_flags |
= VIFF_IGMPV1
; }
337 u_int32 subnet
, mask
;
340 subnet
= v
->uv_lcl_addr
& mask
;
341 if
(!inet_valid_subnet
(subnet
, mask
))
342 fatal
("Invalid netmask");
343 v
->uv_subnet
= subnet
;
344 v
->uv_subnetmask
= mask
;
345 v
->uv_subnetbcast
= subnet | ~mask
;
349 warn
("Expected address after netmask keyword, ignored");
356 ph
= (struct phaddr
*)malloc
(sizeof
(struct phaddr
));
358 fatal
("out of memory");
360 VAL_TO_MASK
(ph
->pa_subnetmask
, $2.mask
);
362 ph
->pa_subnetmask
= v
->uv_subnetmask
;
363 ph
->pa_subnet
= $2.addr
& ph
->pa_subnetmask
;
364 ph
->pa_subnetbcast
= ph
->pa_subnet | ~ph
->pa_subnetmask
;
365 if
($2.addr
& ~ph
->pa_subnetmask
)
366 warn
("Extra subnet %s/%d has host bits set",
367 inet_fmt
($2.addr
,s1
), $2.mask
);
368 ph
->pa_next
= v
->uv_addrs
;
374 warn
("Expected address after altnet keyword, ignored");
379 v
->uv_flags |
= VIFF_FORCE_LEAF
;
382 | FORCE_LEAF BOOLEAN
{
385 v
->uv_flags |
= VIFF_FORCE_LEAF
;
387 v
->uv_flags
&= ~VIFF_FORCE_LEAF
;
393 mod
: THRESHOLD NUMBER
{ if
($2 < 1 ||
$2 > 255)
394 fatal
("Invalid threshold %d",$2);
395 v
->uv_threshold
= $2;
399 warn
("Expected number after threshold keyword, ignored");
402 | METRIC NUMBER
{ if
($2 < 1 ||
$2 > UNREACHABLE
)
403 fatal
("Invalid metric %d",$2);
408 warn
("Expected number after metric keyword, ignored");
411 | ADVERT_METRIC NUMBER
{ if
($2 < 0 ||
$2 > UNREACHABLE
- 1)
412 fatal
("Invalid advert_metric %d", $2);
417 warn
("Expected number after advert_metric keyword, ignored");
420 | RATE_LIMIT NUMBER
{ if
($2 > MAX_RATE_LIMIT
)
421 fatal
("Invalid rate_limit %d",$2);
422 v
->uv_rate_limit
= $2;
426 warn
("Expected number after rate_limit keyword, ignored");
431 struct vif_acl
*v_acl
;
433 v_acl
= (struct vif_acl
*)malloc
(sizeof
(struct vif_acl
));
435 fatal
("out of memory");
436 VAL_TO_MASK
(v_acl
->acl_mask
, $2.mask
);
437 v_acl
->acl_addr
= $2.addr
& v_acl
->acl_mask
;
438 if
($2.addr
& ~v_acl
->acl_mask
)
439 warn
("Boundary spec %s/%d has host bits set",
440 inet_fmt
($2.addr
,s1
),$2.mask
);
441 v_acl
->acl_next
= v
->uv_acl
;
447 warn
("Expected boundary spec after boundary keyword, ignored");
452 v
->uv_flags |
= VIFF_REXMIT_PRUNES
;
455 | REXMIT_PRUNES2 BOOLEAN
{
458 v
->uv_flags |
= VIFF_REXMIT_PRUNES
;
460 v
->uv_flags
&= ~VIFF_REXMIT_PRUNES
;
466 v
->uv_flags |
= VIFF_PASSIVE
;
471 v
->uv_flags |
= VIFF_NOFLOOD
;
476 v
->uv_flags |
= VIFF_NOTRANSIT
;
481 v
->uv_flags |
= VIFF_BLASTER
;
482 blaster_alloc
(v
- uvifs
);
487 v
->uv_flags |
= VIFF_ALLOW_NONPRUNERS
;
490 | PRUNE_LIFETIME2 NUMBER
{
492 if
($2 < MIN_PRUNE_LIFETIME
) {
493 warn
("prune_lifetime %d must be at least %d",
494 $2, MIN_PRUNE_LIFETIME
);
496 v
->uv_prune_lifetime
= $2;
502 if
(v
->uv_filter
== NULL
) {
503 struct vif_filter
*v_filter
;
505 v_filter
= (struct vif_filter
*)malloc
(sizeof
(struct vif_filter
));
506 if
(v_filter
== NULL
)
507 fatal
("out of memory");
508 v_filter
->vf_flags
= 0;
509 v_filter
->vf_type
= VFT_ACCEPT
;
510 v_filter
->vf_filter
= $2;
511 v
->uv_filter
= v_filter
;
512 } else if
(v
->uv_filter
->vf_type
!= VFT_ACCEPT
) {
513 fatal
("can't accept and deny");
515 struct vf_element
*p
;
517 p
= v
->uv_filter
->vf_filter
;
526 warn
("Expected filter spec after accept keyword, ignored");
531 if
(v
->uv_filter
== NULL
) {
532 struct vif_filter
*v_filter
;
534 v_filter
= (struct vif_filter
*)malloc
(sizeof
(struct vif_filter
));
535 if
(v_filter
== NULL
)
536 fatal
("out of memory");
537 v_filter
->vf_flags
= 0;
538 v_filter
->vf_type
= VFT_DENY
;
539 v_filter
->vf_filter
= $2;
540 v
->uv_filter
= v_filter
;
541 } else if
(v
->uv_filter
->vf_type
!= VFT_DENY
) {
542 fatal
("can't accept and deny");
544 struct vf_element
*p
;
546 p
= v
->uv_filter
->vf_filter
;
555 warn
("Expected filter spec after deny keyword, ignored");
560 if
(v
->uv_filter
== NULL
) {
561 fatal
("bidir goes after filters");
563 v
->uv_filter
->vf_flags |
= VFF_BIDIR
;
568 interface
: ADDR
{ $$
= $1; }
572 fatal
("Invalid interface name %s",$1);
576 addrname
: ADDR
{ $$
= $1; }
577 | STRING
{ struct hostent
*hp
;
579 if
((hp
= gethostbyname
($1)) == NULL ||
580 hp
->h_length
!= sizeof
($$
))
581 fatal
("No such host %s", $1);
583 if
(hp
->h_addr_list
[1])
584 fatal
("Hostname %s does not %s",
585 $1, "map to a unique address");
587 bcopy
(hp
->h_addr_list
[0], &$$
,
591 bound
: boundary
{ $$
= $1; }
594 for
(i
=0; i
< numbounds
; i
++) {
595 if
(!strcmp
(boundlist
[i
].name
, $1)) {
596 $$
= boundlist
[i
].bound
;
600 if
(i
== numbounds
) {
601 fatal
("Invalid boundary name %s",$1);
606 boundary
: ADDRMASK
{
608 #ifdef ALLOW_BLACK_HOLES
609 if
(!allow_black_holes
)
611 if
((ntohl
($1.addr
) & 0xff000000) != 0xef000000) {
612 fatal
("Boundaries must be 239.x.x.x, not %s/%d",
613 inet_fmt
($1.addr
, s1
), $1.mask
);
620 addrmask
: ADDRMASK
{ $$
= $1; }
621 | ADDR
{ $$.addr
= $1; $$.mask
= 0; }
624 filter
: filtlist
{ $$
= $1; }
625 | STRING
{ fatal
("named filters no implemented yet"); }
628 filtlist
: filtelement
{ $$
= $1; }
629 | filtelement filtlist
{ $1->vfe_next
= $2; $$
= $1; }
632 filtelement
: filtelem
{ $$
= $1; }
633 | filtelem EXACT
{ $1->vfe_flags |
= VFEF_EXACT
; $$
= $1; }
636 filtelem
: ADDRMASK
{
638 struct vf_element
*vfe
;
640 vfe
= (struct vf_element
*)malloc
(sizeof
(struct vf_element
));
642 fatal
("out of memory");
644 vfe
->vfe_addr
= $1.addr
;
645 VAL_TO_MASK
(vfe
->vfe_mask
, $1.mask
);
647 vfe
->vfe_next
= NULL
;
654 fatal
(char *fmt
, ...
)
657 char buf
[MAXHOSTNAMELEN
+ 100];
660 vsnprintf
(buf
, sizeof
(buf
), fmt
, ap
);
663 log
(LOG_ERR
,0,"%s: %s near line %d", configfilename
, buf
, lineno
);
673 vsnprintf
(buf
, sizeof
(buf
), fmt
, ap
);
676 log
(LOG_WARNING
,0,"%s: %s near line %d", configfilename
, buf
, lineno
);
682 log
(LOG_ERR
, 0, "%s: %s near line %d", configfilename
, s
, lineno
);
688 static char buf
[1024];
695 if
(fgets
(buf
, sizeof
(buf
), f
) == NULL
)
699 while
(*p
&& (*p
== ' ' ||
*p
== '\t')) /* skip whitespace */
702 p
= NULL
; /* skip comments */
709 while
(*p
&& *p
!= '"' && *p
!= '\n')
710 p
++; /* find next whitespace */
715 while
(*p
&& *p
!= ' ' && *p
!= '\t' && *p
!= '\n')
716 p
++; /* find next whitespace */
717 *p
++ = '\0'; /* null-terminate string */
721 continue
; /* if 0-length string, read another line */
729 * List of keywords. Must have an empty record at the end to terminate
730 * list. If a second value is specified, the first is used at the beginning
731 * of the file and the second is used while parsing interfaces (e.g. after
732 * the first "phyint" or "tunnel" keyword).
734 static struct keyword
{
739 { "cache_lifetime", CACHE_LIFETIME
},
740 { "prune_lifetime", PRUNE_LIFETIME
, PRUNE_LIFETIME2
},
741 { "pruning", PRUNING
},
742 { "phyint", PHYINT
},
743 { "tunnel", TUNNEL
},
744 { "disable", DISABLE
},
745 { "metric", METRIC
},
746 { "advert_metric", ADVERT_METRIC
},
747 { "threshold", THRESHOLD
},
748 { "rate_limit", RATE_LIMIT
},
749 { "force_leaf", FORCE_LEAF
},
751 { "sourceroute", SRCRT
},
752 { "boundary", BOUNDARY
},
753 { "netmask", NETMASK
},
754 { "igmpv1", IGMPV1
},
755 { "altnet", ALTNET
},
757 { "accept", ACCEPT
},
761 { "allow_nonpruners", ALLOW_NONPRUNERS
},
762 #ifdef ALLOW_BLACK_HOLES
763 { "allow_black_holes", BLACK_HOLE
},
765 { "noflood", NOFLOOD
, NOFLOOD2
},
766 { "notransit", NOTRANSIT
},
767 { "blaster", BLASTER
},
768 { "rexmit_prunes", REXMIT_PRUNES
, REXMIT_PRUNES2
},
769 { "passive", PASSIVE
},
770 { "beside", BESIDE
},
772 { "sysName", SYSNAM
},
773 { "sysContact", SYSCONTACT
},
774 { "sysVersion", SYSVERSION
},
775 { "sysLocation", SYSLOCATION
},
789 if
((q
= next_word
()) == NULL
) {
793 for
(w
= words
; w
->word
; w
++)
794 if
(!strcmp
(q
, w
->word
))
795 return
(state
&& w
->val2
) ? w
->val2
: w
->val1
;
797 if
(!strcmp
(q
,"on") ||
!strcmp
(q
,"yes")) {
801 if
(!strcmp
(q
,"off") ||
!strcmp
(q
,"no")) {
805 if
(!strcmp
(q
,"default")) {
806 yylval.addrmask.mask
= 0;
807 yylval.addrmask.addr
= 0;
810 if
(sscanf
(q
,"%[.0-9]/%d%c",s1
,&n
,s2
) == 2) {
811 if
((addr
= inet_parse
(s1
,1)) != 0xffffffff) {
812 yylval.addrmask.mask
= n
;
813 yylval.addrmask.addr
= addr
;
816 /* fall through to returning STRING */
818 if
(sscanf
(q
,"%[.0-9]%c",s1
,s2
) == 1) {
819 if
((addr
= inet_parse
(s1
,4)) != 0xffffffff &&
820 inet_valid_host
(addr
)) {
825 if
(sscanf
(q
,"0x%8x%c",&n
,s1
) == 1) {
829 if
(sscanf
(q
,"%d%c",&n
,s1
) == 1) {
835 if
(q
[ strlen
(q
)-1 ]=='"')
836 q
[ strlen
(q
)-1 ]='\0'; /* trash trailing quote */
846 config_vifs_from_file
(void)
853 if
((f
= fopen
(configfilename
, "r")) == NULL
) {
855 log
(LOG_ERR
, errno
, "can't open %s", configfilename
);
870 for
(vifi
=0, v
=uvifs
; vifi
<numvifs
; vifi
++, v
++)
871 if
(!strcmp
(v
->uv_name
, s
))
872 return v
->uv_lcl_addr
;
877 static struct ifreq
*
878 ifconfaddr
(struct ifconf
*ifcp
, u_int32 a
)
881 struct ifreq
*ifrp
= (struct ifreq
*)ifcp
->ifc_buf
;
882 struct ifreq
*ifend
= (struct ifreq
*)((char *)ifrp
+ ifcp
->ifc_len
);
884 while
(ifrp
< ifend
) {
885 if
(ifrp
->ifr_addr.sa_family
== AF_INET
&&
886 ((struct sockaddr_in
*)&ifrp
->ifr_addr
)->sin_addr.s_addr
== a
)
889 n
= ifrp
->ifr_addr.sa_len
+ sizeof
(ifrp
->ifr_name
);
890 if
(n
< sizeof
(*ifrp
))
893 ifrp
= (struct ifreq
*)((char *)ifrp
+ n
);