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