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