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