Home | History | Annotate | Line # | Download | only in mrouted
cfparse.y revision 1.7
      1 %{
      2 /*	$NetBSD: cfparse.y,v 1.7 2001/08/02 03:41:42 itojun Exp $	*/
      3 
      4 /*
      5  * Configuration file parser for mrouted.
      6  *
      7  * Written by Bill Fenner, NRL, 1994
      8  * Copyright (c) 1994
      9  * Naval Research Laboratory (NRL/CCS)
     10  *                    and the
     11  * Defense Advanced Research Projects Agency (DARPA)
     12  *
     13  * All Rights Reserved.
     14  *
     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.
     20  *
     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.
     24  */
     25 #include <stdio.h>
     26 #ifdef __STDC__
     27 #include <stdarg.h>
     28 #else
     29 #include <string.h>
     30 #include <varargs.h>
     31 #endif
     32 #include "defs.h"
     33 #include <netdb.h>
     34 
     35 /*
     36  * Local function declarations
     37  */
     38 static void		fatal __P((char *fmt, ...))
     39     __attribute__((__format__(__printf__, 1, 2)));
     40 static void		warn __P((char *fmt, ...))
     41         __attribute__((__format__(__printf__, 1, 2)));
     42 static void		yyerror __P((char *s));
     43 static char *		next_word __P((void));
     44 static int		yylex __P((void));
     45 static u_int32_t	valid_if __P((char *s));
     46 static struct ifreq *	ifconfaddr __P((struct ifconf *ifcp, u_int32_t a));
     47 int			yyparse __P((void));
     48 
     49 static FILE *f __attribute__((__unused__));	/* XXX egcs */
     50 extern int udp_socket;
     51 char *configfilename = _PATH_MROUTED_CONF;
     52 
     53 extern int cache_lifetime;
     54 extern int max_prune_lifetime;
     55 
     56 static int lineno;
     57 static struct ifreq ifbuf[32];
     58 static struct ifconf ifc;
     59 
     60 static struct uvif *v;
     61 
     62 static int order;
     63 
     64 struct addrmask {
     65 	u_int32_t	addr;
     66 	int	mask;
     67 };
     68 
     69 struct boundnam {
     70 	char		*name;
     71 	struct addrmask	 bound;
     72 };
     73 
     74 #define MAXBOUNDS 20
     75 
     76 struct boundnam boundlist[MAXBOUNDS];	/* Max. of 20 named boundaries */
     77 int numbounds = 0;			/* Number of named boundaries */
     78 
     79 %}
     80 
     81 %union
     82 {
     83 	int num;
     84 	char *ptr;
     85 	struct addrmask addrmask;
     86 	u_int32_t addr;
     87 };
     88 
     89 %token CACHE_LIFETIME PRUNING
     90 %token PHYINT TUNNEL NAME
     91 %token DISABLE IGMPV1 SRCRT
     92 %token METRIC THRESHOLD RATE_LIMIT BOUNDARY NETMASK ALTNET
     93 %token SYSNAM SYSCONTACT SYSVERSION SYSLOCATION
     94 %token <num> BOOLEAN
     95 %token <num> NUMBER
     96 %token <ptr> STRING
     97 %token <addrmask> ADDRMASK
     98 %token <addr> ADDR
     99 
    100 %type <addr> interface addrname
    101 %type <addrmask> bound boundary addrmask
    102 
    103 %start conf
    104 
    105 %%
    106 
    107 conf	: stmts
    108 	;
    109 
    110 stmts	: /* Empty */
    111 	| stmts stmt
    112 	;
    113 
    114 stmt	: error
    115 	| PHYINT interface 		{
    116 
    117 			vifi_t vifi;
    118 
    119 			if (order)
    120 			    fatal("phyints must appear before tunnels");
    121 
    122 			for (vifi = 0, v = uvifs;
    123 			     vifi < numvifs;
    124 			     ++vifi, ++v)
    125 			    if (!(v->uv_flags & VIFF_TUNNEL) &&
    126 				$2 == v->uv_lcl_addr)
    127 				break;
    128 
    129 			if (vifi == numvifs)
    130 			    fatal("%s is not a configured interface",
    131 				inet_fmt($2,s1));
    132 
    133 					}
    134 		ifmods
    135 	| TUNNEL interface addrname	{
    136 
    137 			struct ifreq *ifr;
    138 			struct ifreq ffr;
    139 			vifi_t vifi;
    140 
    141 			order++;
    142 
    143 			ifr = ifconfaddr(&ifc, $2);
    144 			if (ifr == 0)
    145 			    fatal("Tunnel local address %s is not mine",
    146 				inet_fmt($2, s1));
    147 
    148 			strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ);
    149 			if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr)<0)
    150 			    fatal("ioctl SIOCGIFFLAGS on %s",ffr.ifr_name);
    151 			if (ffr.ifr_flags & IFF_LOOPBACK)
    152 			    fatal("Tunnel local address %s is a loopback interface",
    153 				inet_fmt($2, s1));
    154 
    155 			if (ifconfaddr(&ifc, $3) != 0)
    156 			    fatal("Tunnel remote address %s is one of mine",
    157 				inet_fmt($3, s1));
    158 
    159 			for (vifi = 0, v = uvifs;
    160 			     vifi < numvifs;
    161 			     ++vifi, ++v)
    162 			    if (v->uv_flags & VIFF_TUNNEL) {
    163 				if ($3 == v->uv_rmt_addr)
    164 				    fatal("Duplicate tunnel to %s",
    165 					inet_fmt($3, s1));
    166 			    } else if (!(v->uv_flags & VIFF_DISABLED)) {
    167 				if (($3 & v->uv_subnetmask) == v->uv_subnet)
    168 				    fatal("Unnecessary tunnel to %s",
    169 					inet_fmt($3,s1));
    170 			    }
    171 
    172 			if (numvifs == MAXVIFS)
    173 			    fatal("too many vifs");
    174 
    175 			v = &uvifs[numvifs];
    176 			v->uv_flags	= VIFF_TUNNEL;
    177 			v->uv_metric	= DEFAULT_METRIC;
    178 			v->uv_rate_limit= DEFAULT_TUN_RATE_LIMIT;
    179 			v->uv_threshold	= DEFAULT_THRESHOLD;
    180 			v->uv_lcl_addr	= $2;
    181 			v->uv_rmt_addr	= $3;
    182 			v->uv_subnet	= 0;
    183 			v->uv_subnetmask= 0;
    184 			v->uv_subnetbcast= 0;
    185 			strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ);
    186 			v->uv_groups	= NULL;
    187 			v->uv_neighbors	= NULL;
    188 			v->uv_acl	= NULL;
    189 			v->uv_addrs	= NULL;
    190 
    191 			if (!(ffr.ifr_flags & IFF_UP)) {
    192 			    v->uv_flags |= VIFF_DOWN;
    193 			    vifs_down = TRUE;
    194 			}
    195 					}
    196 		tunnelmods
    197 					{
    198 			log(LOG_INFO, 0,
    199 			    "installing tunnel from %s to %s as vif #%u - rate=%d",
    200 			    inet_fmt($2, s1), inet_fmt($3, s2),
    201 			    numvifs, v->uv_rate_limit);
    202 
    203 			++numvifs;
    204 					}
    205 	| PRUNING BOOLEAN	    { pruning = $2; }
    206 	| CACHE_LIFETIME NUMBER     { cache_lifetime = $2;
    207 				      max_prune_lifetime = cache_lifetime * 2;
    208 				    }
    209 	| NAME STRING boundary	    { if (numbounds >= MAXBOUNDS) {
    210 					fatal("Too many named boundaries (max %d)", MAXBOUNDS);
    211 				      }
    212 
    213 				      boundlist[numbounds].name = malloc(strlen($2) + 1);
    214 				      strcpy(boundlist[numbounds].name, $2);
    215 				      boundlist[numbounds++].bound = $3;
    216 				    }
    217 	| SYSNAM STRING    {
    218 #ifdef SNMP
    219 			    set_sysName($2);
    220 #endif /* SNMP */
    221 			    }
    222 	| SYSCONTACT STRING {
    223 #ifdef SNMP
    224 			    set_sysContact($2);
    225 #endif /* SNMP */
    226 			    }
    227         | SYSVERSION STRING {
    228 #ifdef SNMP
    229 			    set_sysVersion($2);
    230 #endif /* SNMP */
    231 			    }
    232 	| SYSLOCATION STRING {
    233 #ifdef SNMP
    234 			    set_sysLocation($2);
    235 #endif /* SNMP */
    236 			    }
    237 	;
    238 
    239 tunnelmods	: /* empty */
    240 	| tunnelmods tunnelmod
    241 	;
    242 
    243 tunnelmod	: mod
    244 	| SRCRT			{ fatal("Source-route tunnels not supported"); }
    245 	;
    246 
    247 ifmods	: /* empty */
    248 	| ifmods ifmod
    249 	;
    250 
    251 ifmod	: mod
    252 	| DISABLE		{ v->uv_flags |= VIFF_DISABLED; }
    253 	| IGMPV1		{ v->uv_flags |= VIFF_IGMPV1; }
    254 	| NETMASK addrname	{
    255 				  u_int32_t subnet, mask;
    256 
    257 				  mask = $2;
    258 				  subnet = v->uv_lcl_addr & mask;
    259 				  if (!inet_valid_subnet(subnet, mask))
    260 					fatal("Invalid netmask");
    261 				  v->uv_subnet = subnet;
    262 				  v->uv_subnetmask = mask;
    263 				  v->uv_subnetbcast = subnet | ~mask;
    264 				}
    265 	| NETMASK		{
    266 
    267 		    warn("Expected address after netmask keyword, ignored");
    268 
    269 				}
    270 	| ALTNET addrmask	{
    271 
    272 		    struct phaddr *ph;
    273 
    274 		    ph = (struct phaddr *)malloc(sizeof(struct phaddr));
    275 		    if (ph == NULL)
    276 			fatal("out of memory");
    277 		    if ($2.mask) {
    278 			VAL_TO_MASK(ph->pa_subnetmask, $2.mask);
    279 		    } else
    280 			ph->pa_subnetmask = v->uv_subnetmask;
    281 		    ph->pa_subnet = $2.addr & ph->pa_subnetmask;
    282 		    ph->pa_subnetbcast = ph->pa_subnet | ~ph->pa_subnetmask;
    283 		    if ($2.addr & ~ph->pa_subnetmask)
    284 			warn("Extra subnet %s/%d has host bits set",
    285 				inet_fmt($2.addr,s1), $2.mask);
    286 		    ph->pa_next = v->uv_addrs;
    287 		    v->uv_addrs = ph;
    288 
    289 				}
    290 	| ALTNET		{
    291 
    292 		    warn("Expected address after altnet keyword, ignored");
    293 
    294 				}
    295 	;
    296 
    297 mod	: THRESHOLD NUMBER	{ if ($2 < 1 || $2 > 255)
    298 				    fatal("Invalid threshold %d",$2);
    299 				  v->uv_threshold = $2;
    300 				}
    301 	| THRESHOLD		{
    302 
    303 		    warn("Expected number after threshold keyword, ignored");
    304 
    305 				}
    306 	| METRIC NUMBER		{ if ($2 < 1 || $2 > UNREACHABLE)
    307 				    fatal("Invalid metric %d",$2);
    308 				  v->uv_metric = $2;
    309 				}
    310 	| METRIC		{
    311 
    312 		    warn("Expected number after metric keyword, ignored");
    313 
    314 				}
    315 	| RATE_LIMIT NUMBER	{ if ($2 > MAX_RATE_LIMIT)
    316 				    fatal("Invalid rate_limit %d",$2);
    317 				  v->uv_rate_limit = $2;
    318 				}
    319 	| RATE_LIMIT		{
    320 
    321 		    warn("Expected number after rate_limit keyword, ignored");
    322 
    323 				}
    324 	| BOUNDARY bound	{
    325 
    326 		    struct vif_acl *v_acl;
    327 
    328 		    v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
    329 		    if (v_acl == NULL)
    330 			fatal("out of memory");
    331 		    VAL_TO_MASK(v_acl->acl_mask, $2.mask);
    332 		    v_acl->acl_addr = $2.addr & v_acl->acl_mask;
    333 		    if ($2.addr & ~v_acl->acl_mask)
    334 			warn("Boundary spec %s/%d has host bits set",
    335 				inet_fmt($2.addr,s1),$2.mask);
    336 		    v_acl->acl_next = v->uv_acl;
    337 		    v->uv_acl = v_acl;
    338 
    339 				}
    340 	| BOUNDARY		{
    341 
    342 		warn("Expected boundary spec after boundary keyword, ignored");
    343 
    344 				}
    345 	;
    346 
    347 interface	: ADDR		{ $$ = $1; }
    348 	| STRING		{
    349 				  $$ = valid_if($1);
    350 				  if ($$ == 0)
    351 					fatal("Invalid interface name %s",$1);
    352 				}
    353 	;
    354 
    355 addrname	: ADDR		{ $$ = $1; }
    356 	| STRING		{ struct hostent *hp;
    357 
    358 				  if ((hp = gethostbyname($1)) == NULL)
    359 				    fatal("No such host %s", $1);
    360 
    361 				  if (hp->h_addr_list[1])
    362 				    fatal("Hostname %s does not %s",
    363 					$1, "map to a unique address");
    364 
    365 				  bcopy(hp->h_addr_list[0], &$$,
    366 					    hp->h_length);
    367 				}
    368 
    369 bound	: boundary		{ $$ = $1; }
    370 	| STRING		{ int i;
    371 
    372 				  for (i=0; i < numbounds; i++) {
    373 				    if (!strcmp(boundlist[i].name, $1)) {
    374 					$$ = boundlist[i].bound;
    375 					break;
    376 				    }
    377 				  }
    378 				  if (i == numbounds) {
    379 				    fatal("Invalid boundary name %s",$1);
    380 				  }
    381 				}
    382 	;
    383 
    384 boundary	: ADDRMASK	{
    385 
    386 			if ((ntohl($1.addr) & 0xff000000) != 0xef000000) {
    387 			    fatal("Boundaries must be 239.x.x.x, not %s/%d",
    388 				inet_fmt($1.addr, s1), $1.mask);
    389 			}
    390 			$$ = $1;
    391 
    392 				}
    393 	;
    394 
    395 addrmask	: ADDRMASK	{ $$ = $1; }
    396 	| ADDR			{ $$.addr = $1; $$.mask = 0; }
    397 	;
    398 %%
    399 #ifdef __STDC__
    400 static void
    401 fatal(char *fmt, ...)
    402 {
    403 	va_list ap;
    404 	char buf[200];
    405 
    406 	va_start(ap, fmt);
    407 #else
    408 /*VARARGS1*/
    409 static void
    410 fatal(fmt, va_alist)
    411 char *fmt;
    412 va_dcl
    413 {
    414 	va_list ap;
    415 	char buf[200];
    416 
    417 	va_start(ap);
    418 #endif
    419 	vsprintf(buf, fmt, ap);
    420 	va_end(ap);
    421 
    422 	log(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno);
    423 }
    424 
    425 #ifdef __STDC__
    426 static void
    427 warn(char *fmt, ...)
    428 {
    429 	va_list ap;
    430 	char buf[200];
    431 
    432 	va_start(ap, fmt);
    433 #else
    434 /*VARARGS1*/
    435 static void
    436 warn(fmt, va_alist)
    437 char *fmt;
    438 va_dcl
    439 {
    440 	va_list ap;
    441 	char buf[200];
    442 
    443 	va_start(ap);
    444 #endif
    445 	vsprintf(buf, fmt, ap);
    446 	va_end(ap);
    447 
    448 	log(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno);
    449 }
    450 
    451 static void
    452 yyerror(s)
    453 char *s;
    454 {
    455 	log(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno);
    456 }
    457 
    458 static char *
    459 next_word()
    460 {
    461 	static char buf[1024];
    462 	static char *p=NULL;
    463 	extern FILE *f;
    464 	char *q;
    465 
    466 	while (1) {
    467 	    if (!p || !*p) {
    468 		lineno++;
    469 		if (fgets(buf, sizeof(buf), f) == NULL)
    470 		    return NULL;
    471 		p = buf;
    472 	    }
    473 	    while (*p && (*p == ' ' || *p == '\t'))	/* skip whitespace */
    474 		p++;
    475 	    if (*p == '#') {
    476 		p = NULL;		/* skip comments */
    477 		continue;
    478 	    }
    479 	    q = p;
    480 #ifdef SNMP
    481        if (*p == '"') {
    482           p++;
    483 	       while (*p && *p != '"' && *p != '\n')
    484 		      p++;		/* find next whitespace */
    485           if (*p == '"')
    486              p++;
    487        } else
    488 #endif
    489 	    while (*p && *p != ' ' && *p != '\t' && *p != '\n')
    490 		p++;		/* find next whitespace */
    491 	    *p++ = '\0';	/* null-terminate string */
    492 
    493 	    if (!*q) {
    494 		p = NULL;
    495 		continue;	/* if 0-length string, read another line */
    496 	    }
    497 
    498 	    return q;
    499 	}
    500 }
    501 
    502 static int
    503 yylex()
    504 {
    505 	int n;
    506 	u_int32_t addr;
    507 	char *q;
    508 
    509 	if ((q = next_word()) == NULL) {
    510 		return 0;
    511 	}
    512 
    513 	if (!strcmp(q,"cache_lifetime"))
    514 		return CACHE_LIFETIME;
    515 	if (!strcmp(q,"pruning"))
    516 		return PRUNING;
    517 	if (!strcmp(q,"phyint"))
    518 		return PHYINT;
    519 	if (!strcmp(q,"tunnel"))
    520 		return TUNNEL;
    521 	if (!strcmp(q,"disable"))
    522 		return DISABLE;
    523 	if (!strcmp(q,"metric"))
    524 		return METRIC;
    525 	if (!strcmp(q,"threshold"))
    526 		return THRESHOLD;
    527 	if (!strcmp(q,"rate_limit"))
    528 		return RATE_LIMIT;
    529 	if (!strcmp(q,"srcrt") || !strcmp(q,"sourceroute"))
    530 		return SRCRT;
    531 	if (!strcmp(q,"boundary"))
    532 		return BOUNDARY;
    533 	if (!strcmp(q,"netmask"))
    534 		return NETMASK;
    535 	if (!strcmp(q,"igmpv1"))
    536 		return IGMPV1;
    537 	if (!strcmp(q,"altnet"))
    538 		return ALTNET;
    539 	if (!strcmp(q,"name"))
    540 		return NAME;
    541 	if (!strcmp(q,"on") || !strcmp(q,"yes")) {
    542 		yylval.num = 1;
    543 		return BOOLEAN;
    544 	}
    545 	if (!strcmp(q,"off") || !strcmp(q,"no")) {
    546 		yylval.num = 0;
    547 		return BOOLEAN;
    548 	}
    549 	if (sscanf(q,"%[.0-9]/%d%c",s1,&n,s2) == 2) {
    550 		if ((addr = inet_parse(s1)) != 0xffffffff) {
    551 			yylval.addrmask.mask = n;
    552 			yylval.addrmask.addr = addr;
    553 			return ADDRMASK;
    554 		}
    555 		/* fall through to returning STRING */
    556 	}
    557 	if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) {
    558 		if ((addr = inet_parse(s1)) != 0xffffffff &&
    559 		    inet_valid_host(addr)) {
    560 			yylval.addr = addr;
    561 			return ADDR;
    562 		}
    563 	}
    564 	if (sscanf(q,"0x%8x%c",&n,s1) == 1) {
    565 		yylval.addr = n;
    566 		return ADDR;
    567 	}
    568 	if (sscanf(q,"%d%c",&n,s1) == 1) {
    569 		yylval.num = n;
    570 		return NUMBER;
    571 	}
    572 #ifdef SNMP
    573 	if (!strcmp(q,"sysName"))
    574 		return SYSNAM;
    575 	if (!strcmp(q,"sysContact"))
    576 		return SYSCONTACT;
    577 	if (!strcmp(q,"sysVersion"))
    578 		return SYSVERSION;
    579 	if (!strcmp(q,"sysLocation"))
    580 		return SYSLOCATION;
    581    if (*q=='"') {
    582       if (q[ strlen(q)-1 ]=='"')
    583          q[ strlen(q)-1 ]='\0'; /* trash trailing quote */
    584       yylval.ptr = q+1;
    585       return STRING;
    586    }
    587 #endif
    588 	yylval.ptr = q;
    589 	return STRING;
    590 }
    591 
    592 void
    593 config_vifs_from_file()
    594 {
    595 	extern FILE *f;
    596 
    597 	order = 0;
    598 	numbounds = 0;
    599 	lineno = 0;
    600 
    601 	if ((f = fopen(configfilename, "r")) == NULL) {
    602 	    if (errno != ENOENT)
    603 		log(LOG_ERR, errno, "can't open %s", configfilename);
    604 	    return;
    605 	}
    606 
    607 	ifc.ifc_buf = (char *)ifbuf;
    608 	ifc.ifc_len = sizeof(ifbuf);
    609 	if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
    610 	    log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
    611 
    612 	yyparse();
    613 
    614 	fclose(f);
    615 }
    616 
    617 static u_int32_t
    618 valid_if(s)
    619 char *s;
    620 {
    621 	register vifi_t vifi;
    622 	register struct uvif *v;
    623 
    624 	for (vifi=0, v=uvifs; vifi<numvifs; vifi++, v++)
    625 	    if (!strcmp(v->uv_name, s))
    626 		return v->uv_lcl_addr;
    627 
    628 	return 0;
    629 }
    630 
    631 static struct ifreq *
    632 ifconfaddr(ifcp, a)
    633     struct ifconf *ifcp;
    634     u_int32_t a;
    635 {
    636     int n;
    637     struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf;
    638     struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len);
    639 
    640     while (ifrp < ifend) {
    641 	    if (ifrp->ifr_addr.sa_family == AF_INET &&
    642 		((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a)
    643 		    return (ifrp);
    644 #if (defined(BSD) && (BSD >= 199006))
    645 		n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
    646 		if (n < sizeof(*ifrp))
    647 			++ifrp;
    648 		else
    649 			ifrp = (struct ifreq *)((char *)ifrp + n);
    650 #else
    651 		++ifrp;
    652 #endif
    653     }
    654     return (0);
    655 }
    656