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