2 /* $NetBSD: cfparse.y,v 1.15 2003/08/18 05:39:53 itojun Exp $ */
5 * Configuration file parser for mrouted.
7 * Written by Bill Fenner, NRL, 1994
9 * Naval Research Laboratory (NRL/CCS)
11 * Defense Advanced Research Projects Agency (DARPA)
13 * All Rights Reserved.
15 * Permission to use, copy, modify and distribute this software and its
16 * documentation is hereby granted, provided that both the copyright notice and
17 * this permission notice appear in all copies of the software, derivative
18 * works or modified versions, and any portions thereof, and that both notices
19 * appear in supporting documentation.
21 * NRL AND DARPA ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND
22 * DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM
23 * THE USE OF THIS SOFTWARE.
32 * Local function declarations
34 static void fatal
(const char *fmt
, ...
)
35 __attribute__
((__format__
(__printf__
, 1, 2)));
36 static void warn
(const char *fmt
, ...
)
37 __attribute__
((__format__
(__printf__
, 1, 2)));
38 static void yyerror(const char *s
);
39 static char * next_word
(void);
40 static int yylex(void);
41 static u_int32_t valid_if
(char *s
);
42 static const char * ifconfaddr
(u_int32_t a
);
45 static FILE *f __attribute__
((__unused__
)); /* XXX egcs */
46 extern
int udp_socket
;
47 const char *configfilename
= _PATH_MROUTED_CONF
;
49 extern
int cache_lifetime
;
50 extern
int max_prune_lifetime
;
54 static struct uvif
*v
;
65 struct addrmask bound
;
70 struct boundnam boundlist
[MAXBOUNDS
]; /* Max. of 20 named boundaries */
71 int numbounds
= 0; /* Number of named boundaries */
79 struct addrmask addrmask
;
83 %token CACHE_LIFETIME PRUNING
84 %token PHYINT TUNNEL NAME
85 %token DISABLE IGMPV1 SRCRT
86 %token METRIC THRESHOLD RATE_LIMIT BOUNDARY NETMASK ALTNET
87 %token SYSNAM SYSCONTACT SYSVERSION SYSLOCATION
91 %token
<addrmask
> ADDRMASK
94 %type
<addr
> interface addrname
95 %type
<addrmask
> bound boundary addrmask
114 fatal
("phyints must appear before tunnels");
116 for
(vifi
= 0, v
= uvifs
;
119 if
(!(v
->uv_flags
& VIFF_TUNNEL
) &&
120 $2 == v
->uv_lcl_addr
)
124 fatal
("%s is not a configured interface",
129 | TUNNEL interface addrname
{
136 ifname
= ifconfaddr
($2);
138 fatal
("Tunnel local address %s is not mine",
141 strncpy
(ffr.ifr_name
, ifname
, sizeof
(ffr.ifr_name
));
142 if
(ioctl
(udp_socket
, SIOCGIFFLAGS
, (char *)&ffr
)<0)
143 fatal
("ioctl SIOCGIFFLAGS on %s",ffr.ifr_name
);
144 if
(ffr.ifr_flags
& IFF_LOOPBACK
)
145 fatal
("Tunnel local address %s is a loopback interface",
148 if
(ifconfaddr
($3) != 0)
149 fatal
("Tunnel remote address %s is one of mine",
152 for
(vifi
= 0, v
= uvifs
;
155 if
(v
->uv_flags
& VIFF_TUNNEL
) {
156 if
($3 == v
->uv_rmt_addr
)
157 fatal
("Duplicate tunnel to %s",
159 } else if
(!(v
->uv_flags
& VIFF_DISABLED
)) {
160 if
(($3 & v
->uv_subnetmask
) == v
->uv_subnet
)
161 fatal
("Unnecessary tunnel to %s",
165 if
(numvifs
== MAXVIFS
)
166 fatal
("too many vifs");
169 v
->uv_flags
= VIFF_TUNNEL
;
170 v
->uv_metric
= DEFAULT_METRIC
;
171 v
->uv_rate_limit
= DEFAULT_TUN_RATE_LIMIT
;
172 v
->uv_threshold
= DEFAULT_THRESHOLD
;
177 v
->uv_subnetbcast
= 0;
178 strncpy
(v
->uv_name
, ffr.ifr_name
, IFNAMSIZ
);
180 v
->uv_neighbors
= NULL
;
184 if
(!(ffr.ifr_flags
& IFF_UP
)) {
185 v
->uv_flags |
= VIFF_DOWN
;
192 "installing tunnel from %s to %s as vif #%u - rate=%d",
195 numvifs
, v
->uv_rate_limit
);
199 | PRUNING BOOLEAN
{ pruning
= $2; }
200 | CACHE_LIFETIME NUMBER
{ cache_lifetime
= $2;
201 max_prune_lifetime
= cache_lifetime
* 2;
203 | NAME STRING boundary
{ if
(numbounds
>= MAXBOUNDS
) {
204 fatal
("Too many named boundaries (max %d)", MAXBOUNDS
);
207 boundlist
[numbounds
].name
= strdup
($2);
208 boundlist
[numbounds
++].bound
= $3;
215 | SYSCONTACT STRING
{
220 | SYSVERSION STRING
{
225 | SYSLOCATION STRING
{
232 tunnelmods
: /* empty */
233 | tunnelmods tunnelmod
237 | SRCRT
{ fatal
("Source-route tunnels not supported"); }
245 | DISABLE
{ v
->uv_flags |
= VIFF_DISABLED
; }
246 | IGMPV1
{ v
->uv_flags |
= VIFF_IGMPV1
; }
248 u_int32_t subnet
, mask
;
251 subnet
= v
->uv_lcl_addr
& mask
;
252 if
(!inet_valid_subnet
(subnet
, mask
))
253 fatal
("Invalid netmask");
254 v
->uv_subnet
= subnet
;
255 v
->uv_subnetmask
= mask
;
256 v
->uv_subnetbcast
= subnet | ~mask
;
260 warn
("Expected address after netmask keyword, ignored");
267 ph
= (struct phaddr
*)malloc
(sizeof
(struct phaddr
));
269 fatal
("out of memory");
271 VAL_TO_MASK
(ph
->pa_subnetmask
, $2.mask
);
273 ph
->pa_subnetmask
= v
->uv_subnetmask
;
274 ph
->pa_subnet
= $2.addr
& ph
->pa_subnetmask
;
275 ph
->pa_subnetbcast
= ph
->pa_subnet | ~ph
->pa_subnetmask
;
276 if
($2.addr
& ~ph
->pa_subnetmask
)
277 warn
("Extra subnet %s/%d has host bits set",
278 inet_fmt
($2.addr
), $2.mask
);
279 ph
->pa_next
= v
->uv_addrs
;
285 warn
("Expected address after altnet keyword, ignored");
290 mod
: THRESHOLD NUMBER
{ if
($2 < 1 ||
$2 > 255)
291 fatal
("Invalid threshold %d",$2);
292 v
->uv_threshold
= $2;
296 warn
("Expected number after threshold keyword, ignored");
299 | METRIC NUMBER
{ if
($2 < 1 ||
$2 > UNREACHABLE
)
300 fatal
("Invalid metric %d",$2);
305 warn
("Expected number after metric keyword, ignored");
308 | RATE_LIMIT NUMBER
{ if
($2 > MAX_RATE_LIMIT
)
309 fatal
("Invalid rate_limit %d",$2);
310 v
->uv_rate_limit
= $2;
314 warn
("Expected number after rate_limit keyword, ignored");
319 struct vif_acl
*v_acl
;
321 v_acl
= (struct vif_acl
*)malloc
(sizeof
(struct vif_acl
));
323 fatal
("out of memory");
324 VAL_TO_MASK
(v_acl
->acl_mask
, $2.mask
);
325 v_acl
->acl_addr
= $2.addr
& v_acl
->acl_mask
;
326 if
($2.addr
& ~v_acl
->acl_mask
)
327 warn
("Boundary spec %s/%d has host bits set",
328 inet_fmt
($2.addr
),$2.mask
);
329 v_acl
->acl_next
= v
->uv_acl
;
335 warn
("Expected boundary spec after boundary keyword, ignored");
340 interface
: ADDR
{ $$
= $1; }
344 fatal
("Invalid interface name %s",$1);
348 addrname
: ADDR
{ $$
= $1; }
349 | STRING
{ struct hostent
*hp
;
351 if
((hp
= gethostbyname
($1)) == NULL
)
352 fatal
("No such host %s", $1);
354 if
(hp
->h_addr_list
[1])
355 fatal
("Hostname %s does not %s",
356 $1, "map to a unique address");
358 bcopy
(hp
->h_addr_list
[0], &$$
,
362 bound
: boundary
{ $$
= $1; }
365 for
(i
=0; i
< numbounds
; i
++) {
366 if
(!strcmp
(boundlist
[i
].name
, $1)) {
367 $$
= boundlist
[i
].bound
;
371 if
(i
== numbounds
) {
372 fatal
("Invalid boundary name %s",$1);
377 boundary
: ADDRMASK
{
379 if
((ntohl
($1.addr
) & 0xff000000) != 0xef000000) {
380 fatal
("Boundaries must be 239.x.x.x, not %s/%d",
381 inet_fmt
($1.addr
), $1.mask
);
388 addrmask
: ADDRMASK
{ $$
= $1; }
389 | ADDR
{ $$.addr
= $1; $$.mask
= 0; }
393 fatal
(const char *fmt
, ...
)
399 vsnprintf
(buf
, sizeof
(buf
), fmt
, ap
);
402 logit
(LOG_ERR
,0,"%s: %s near line %d", configfilename
, buf
, lineno
);
406 warn
(const char *fmt
, ...
)
412 vsnprintf
(buf
, sizeof
(buf
), fmt
, ap
);
415 logit
(LOG_WARNING
,0,"%s: %s near line %d", configfilename
, buf
, lineno
);
422 logit
(LOG_ERR
, 0, "%s: %s near line %d", configfilename
, s
, lineno
);
428 static char buf
[1024];
436 if
(fgets
(buf
, sizeof
(buf
), f
) == NULL
)
440 while
(*p
&& (*p
== ' ' ||
*p
== '\t')) /* skip whitespace */
443 p
= NULL
; /* skip comments */
450 while
(*p
&& *p
!= '"' && *p
!= '\n')
451 p
++; /* find next whitespace */
456 while
(*p
&& *p
!= ' ' && *p
!= '\t' && *p
!= '\n')
457 p
++; /* find next whitespace */
458 *p
++ = '\0'; /* null-terminate string */
462 continue
; /* if 0-length string, read another line */
477 if
((q
= next_word
()) == NULL
) {
481 if
(!strcmp
(q
,"cache_lifetime"))
482 return CACHE_LIFETIME
;
483 if
(!strcmp
(q
,"pruning"))
485 if
(!strcmp
(q
,"phyint"))
487 if
(!strcmp
(q
,"tunnel"))
489 if
(!strcmp
(q
,"disable"))
491 if
(!strcmp
(q
,"metric"))
493 if
(!strcmp
(q
,"threshold"))
495 if
(!strcmp
(q
,"rate_limit"))
497 if
(!strcmp
(q
,"srcrt") ||
!strcmp
(q
,"sourceroute"))
499 if
(!strcmp
(q
,"boundary"))
501 if
(!strcmp
(q
,"netmask"))
503 if
(!strcmp
(q
,"igmpv1"))
505 if
(!strcmp
(q
,"altnet"))
507 if
(!strcmp
(q
,"name"))
509 if
(!strcmp
(q
,"on") ||
!strcmp
(q
,"yes")) {
513 if
(!strcmp
(q
,"off") ||
!strcmp
(q
,"no")) {
517 if
((addr
= inet_parse
(q
, &n
)) != 0xffffffff) {
518 yylval.addrmask.mask
= n
;
519 yylval.addrmask.addr
= addr
;
522 if
((addr
= inet_parse
(q
,0)) != 0xffffffff &&
523 inet_valid_host
(addr
)) {
527 if
(sscanf
(q
,"0x%8x%c",&n
,&c
) == 1) {
531 if
(sscanf
(q
,"%d%c",&n
,&c
) == 1) {
536 if
(!strcmp
(q
,"sysName"))
538 if
(!strcmp
(q
,"sysContact"))
540 if
(!strcmp
(q
,"sysVersion"))
542 if
(!strcmp
(q
,"sysLocation"))
545 if
(q
[ strlen
(q
)-1 ]=='"')
546 q
[ strlen
(q
)-1 ]='\0'; /* trash trailing quote */
556 config_vifs_from_file
()
564 if
((f
= fopen
(configfilename
, "r")) == NULL
) {
566 logit
(LOG_ERR
, errno
, "can't open %s", configfilename
);
582 for
(vifi
=0, uv
=uvifs
; vifi
<numvifs
; vifi
++, uv
++)
583 if
(!strcmp
(uv
->uv_name
, s
))
584 return uv
->uv_lcl_addr
;
593 static char ifname
[IFNAMSIZ
];
594 struct ifaddrs
*ifap
, *ifa
;
596 if
(getifaddrs
(&ifap
) != 0)
599 for
(ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
600 if
(ifa
->ifa_addr
->sa_family
== AF_INET
&&
601 ((struct sockaddr_in
*)ifa
->ifa_addr
)->sin_addr.s_addr
== a
) {
602 strlcpy
(ifname
, ifa
->ifa_name
, sizeof
(ifname
));