1 %{ 2 /* $NetBSD: cfparse.y,v 1.14 2003/07/13 12:40:17 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 #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 = strdup($2); 210 boundlist[numbounds++].bound = $3; 211 } 212 | SYSNAM STRING { 213 #ifdef SNMP 214 set_sysName($2); 215 #endif /* SNMP */ 216 } 217 | SYSCONTACT STRING { 218 #ifdef SNMP 219 set_sysContact($2); 220 #endif /* SNMP */ 221 } 222 | SYSVERSION STRING { 223 #ifdef SNMP 224 set_sysVersion($2); 225 #endif /* SNMP */ 226 } 227 | SYSLOCATION STRING { 228 #ifdef SNMP 229 set_sysLocation($2); 230 #endif /* SNMP */ 231 } 232 ; 233 234 tunnelmods : /* empty */ 235 | tunnelmods tunnelmod 236 ; 237 238 tunnelmod : mod 239 | SRCRT { fatal("Source-route tunnels not supported"); } 240 ; 241 242 ifmods : /* empty */ 243 | ifmods ifmod 244 ; 245 246 ifmod : mod 247 | DISABLE { v->uv_flags |= VIFF_DISABLED; } 248 | IGMPV1 { v->uv_flags |= VIFF_IGMPV1; } 249 | NETMASK addrname { 250 u_int32_t subnet, mask; 251 252 mask = $2; 253 subnet = v->uv_lcl_addr & mask; 254 if (!inet_valid_subnet(subnet, mask)) 255 fatal("Invalid netmask"); 256 v->uv_subnet = subnet; 257 v->uv_subnetmask = mask; 258 v->uv_subnetbcast = subnet | ~mask; 259 } 260 | NETMASK { 261 262 warn("Expected address after netmask keyword, ignored"); 263 264 } 265 | ALTNET addrmask { 266 267 struct phaddr *ph; 268 269 ph = (struct phaddr *)malloc(sizeof(struct phaddr)); 270 if (ph == NULL) 271 fatal("out of memory"); 272 if ($2.mask) { 273 VAL_TO_MASK(ph->pa_subnetmask, $2.mask); 274 } else 275 ph->pa_subnetmask = v->uv_subnetmask; 276 ph->pa_subnet = $2.addr & ph->pa_subnetmask; 277 ph->pa_subnetbcast = ph->pa_subnet | ~ph->pa_subnetmask; 278 if ($2.addr & ~ph->pa_subnetmask) 279 warn("Extra subnet %s/%d has host bits set", 280 inet_fmt($2.addr), $2.mask); 281 ph->pa_next = v->uv_addrs; 282 v->uv_addrs = ph; 283 284 } 285 | ALTNET { 286 287 warn("Expected address after altnet keyword, ignored"); 288 289 } 290 ; 291 292 mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255) 293 fatal("Invalid threshold %d",$2); 294 v->uv_threshold = $2; 295 } 296 | THRESHOLD { 297 298 warn("Expected number after threshold keyword, ignored"); 299 300 } 301 | METRIC NUMBER { if ($2 < 1 || $2 > UNREACHABLE) 302 fatal("Invalid metric %d",$2); 303 v->uv_metric = $2; 304 } 305 | METRIC { 306 307 warn("Expected number after metric keyword, ignored"); 308 309 } 310 | RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT) 311 fatal("Invalid rate_limit %d",$2); 312 v->uv_rate_limit = $2; 313 } 314 | RATE_LIMIT { 315 316 warn("Expected number after rate_limit keyword, ignored"); 317 318 } 319 | BOUNDARY bound { 320 321 struct vif_acl *v_acl; 322 323 v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl)); 324 if (v_acl == NULL) 325 fatal("out of memory"); 326 VAL_TO_MASK(v_acl->acl_mask, $2.mask); 327 v_acl->acl_addr = $2.addr & v_acl->acl_mask; 328 if ($2.addr & ~v_acl->acl_mask) 329 warn("Boundary spec %s/%d has host bits set", 330 inet_fmt($2.addr),$2.mask); 331 v_acl->acl_next = v->uv_acl; 332 v->uv_acl = v_acl; 333 334 } 335 | BOUNDARY { 336 337 warn("Expected boundary spec after boundary keyword, ignored"); 338 339 } 340 ; 341 342 interface : ADDR { $$ = $1; } 343 | STRING { 344 $$ = valid_if($1); 345 if ($$ == 0) 346 fatal("Invalid interface name %s",$1); 347 } 348 ; 349 350 addrname : ADDR { $$ = $1; } 351 | STRING { struct hostent *hp; 352 353 if ((hp = gethostbyname($1)) == NULL) 354 fatal("No such host %s", $1); 355 356 if (hp->h_addr_list[1]) 357 fatal("Hostname %s does not %s", 358 $1, "map to a unique address"); 359 360 bcopy(hp->h_addr_list[0], &$$, 361 hp->h_length); 362 } 363 364 bound : boundary { $$ = $1; } 365 | STRING { int i; 366 367 for (i=0; i < numbounds; i++) { 368 if (!strcmp(boundlist[i].name, $1)) { 369 $$ = boundlist[i].bound; 370 break; 371 } 372 } 373 if (i == numbounds) { 374 fatal("Invalid boundary name %s",$1); 375 } 376 } 377 ; 378 379 boundary : ADDRMASK { 380 381 if ((ntohl($1.addr) & 0xff000000) != 0xef000000) { 382 fatal("Boundaries must be 239.x.x.x, not %s/%d", 383 inet_fmt($1.addr), $1.mask); 384 } 385 $$ = $1; 386 387 } 388 ; 389 390 addrmask : ADDRMASK { $$ = $1; } 391 | ADDR { $$.addr = $1; $$.mask = 0; } 392 ; 393 %% 394 static void 395 fatal(char *fmt, ...) 396 { 397 va_list ap; 398 char buf[200]; 399 400 va_start(ap, fmt); 401 vsnprintf(buf, sizeof(buf), fmt, ap); 402 va_end(ap); 403 404 logit(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno); 405 } 406 407 static void 408 warn(char *fmt, ...) 409 { 410 va_list ap; 411 char buf[200]; 412 413 va_start(ap, fmt); 414 vsnprintf(buf, sizeof(buf), fmt, ap); 415 va_end(ap); 416 417 logit(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno); 418 } 419 420 static void 421 yyerror(s) 422 char *s; 423 { 424 logit(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno); 425 } 426 427 static char * 428 next_word() 429 { 430 static char buf[1024]; 431 static char *p=NULL; 432 extern FILE *f; 433 char *q; 434 435 while (1) { 436 if (!p || !*p) { 437 lineno++; 438 if (fgets(buf, sizeof(buf), f) == NULL) 439 return NULL; 440 p = buf; 441 } 442 while (*p && (*p == ' ' || *p == '\t')) /* skip whitespace */ 443 p++; 444 if (*p == '#') { 445 p = NULL; /* skip comments */ 446 continue; 447 } 448 q = p; 449 #ifdef SNMP 450 if (*p == '"') { 451 p++; 452 while (*p && *p != '"' && *p != '\n') 453 p++; /* find next whitespace */ 454 if (*p == '"') 455 p++; 456 } else 457 #endif 458 while (*p && *p != ' ' && *p != '\t' && *p != '\n') 459 p++; /* find next whitespace */ 460 *p++ = '\0'; /* null-terminate string */ 461 462 if (!*q) { 463 p = NULL; 464 continue; /* if 0-length string, read another line */ 465 } 466 467 return q; 468 } 469 } 470 471 static int 472 yylex() 473 { 474 int n; 475 u_int32_t addr; 476 char *q; 477 char c; 478 479 if ((q = next_word()) == NULL) { 480 return 0; 481 } 482 483 if (!strcmp(q,"cache_lifetime")) 484 return CACHE_LIFETIME; 485 if (!strcmp(q,"pruning")) 486 return PRUNING; 487 if (!strcmp(q,"phyint")) 488 return PHYINT; 489 if (!strcmp(q,"tunnel")) 490 return TUNNEL; 491 if (!strcmp(q,"disable")) 492 return DISABLE; 493 if (!strcmp(q,"metric")) 494 return METRIC; 495 if (!strcmp(q,"threshold")) 496 return THRESHOLD; 497 if (!strcmp(q,"rate_limit")) 498 return RATE_LIMIT; 499 if (!strcmp(q,"srcrt") || !strcmp(q,"sourceroute")) 500 return SRCRT; 501 if (!strcmp(q,"boundary")) 502 return BOUNDARY; 503 if (!strcmp(q,"netmask")) 504 return NETMASK; 505 if (!strcmp(q,"igmpv1")) 506 return IGMPV1; 507 if (!strcmp(q,"altnet")) 508 return ALTNET; 509 if (!strcmp(q,"name")) 510 return NAME; 511 if (!strcmp(q,"on") || !strcmp(q,"yes")) { 512 yylval.num = 1; 513 return BOOLEAN; 514 } 515 if (!strcmp(q,"off") || !strcmp(q,"no")) { 516 yylval.num = 0; 517 return BOOLEAN; 518 } 519 if ((addr = inet_parse(q, &n)) != 0xffffffff) { 520 yylval.addrmask.mask = n; 521 yylval.addrmask.addr = addr; 522 return ADDRMASK; 523 } 524 if ((addr = inet_parse(q,0)) != 0xffffffff && 525 inet_valid_host(addr)) { 526 yylval.addr = addr; 527 return ADDR; 528 } 529 if (sscanf(q,"0x%8x%c",&n,&c) == 1) { 530 yylval.addr = n; 531 return ADDR; 532 } 533 if (sscanf(q,"%d%c",&n,&c) == 1) { 534 yylval.num = n; 535 return NUMBER; 536 } 537 #ifdef SNMP 538 if (!strcmp(q,"sysName")) 539 return SYSNAM; 540 if (!strcmp(q,"sysContact")) 541 return SYSCONTACT; 542 if (!strcmp(q,"sysVersion")) 543 return SYSVERSION; 544 if (!strcmp(q,"sysLocation")) 545 return SYSLOCATION; 546 if (*q=='"') { 547 if (q[ strlen(q)-1 ]=='"') 548 q[ strlen(q)-1 ]='\0'; /* trash trailing quote */ 549 yylval.ptr = q+1; 550 return STRING; 551 } 552 #endif 553 yylval.ptr = q; 554 return STRING; 555 } 556 557 void 558 config_vifs_from_file() 559 { 560 extern FILE *f; 561 562 order = 0; 563 numbounds = 0; 564 lineno = 0; 565 566 if ((f = fopen(configfilename, "r")) == NULL) { 567 if (errno != ENOENT) 568 logit(LOG_ERR, errno, "can't open %s", configfilename); 569 return; 570 } 571 572 ifc.ifc_buf = (char *)ifbuf; 573 ifc.ifc_len = sizeof(ifbuf); 574 if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0) 575 logit(LOG_ERR, errno, "ioctl SIOCGIFCONF"); 576 577 yyparse(); 578 579 fclose(f); 580 } 581 582 static u_int32_t 583 valid_if(s) 584 char *s; 585 { 586 vifi_t vifi; 587 struct uvif *v; 588 589 for (vifi=0, v=uvifs; vifi<numvifs; vifi++, v++) 590 if (!strcmp(v->uv_name, s)) 591 return v->uv_lcl_addr; 592 593 return 0; 594 } 595 596 static struct ifreq * 597 ifconfaddr(ifcp, a) 598 struct ifconf *ifcp; 599 u_int32_t a; 600 { 601 int n; 602 struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf; 603 struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len); 604 605 while (ifrp < ifend) { 606 if (ifrp->ifr_addr.sa_family == AF_INET && 607 ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a) 608 return (ifrp); 609 #if (defined(BSD) && (BSD >= 199006)) 610 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); 611 if (n < sizeof(*ifrp)) 612 ++ifrp; 613 else 614 ifrp = (struct ifreq *)((char *)ifrp + n); 615 #else 616 ++ifrp; 617 #endif 618 } 619 return (0); 620 } 621