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