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