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(char *s) 402 { 403 logit(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno); 404 } 405 406 static char * 407 next_word(void) 408 { 409 static char buf[1024]; 410 static char *p=NULL; 411 extern FILE *f; 412 char *q; 413 414 while (1) { 415 if (!p || !*p) { 416 lineno++; 417 if (fgets(buf, sizeof(buf), f) == NULL) 418 return NULL; 419 p = buf; 420 } 421 while (*p && (*p == ' ' || *p == '\t')) /* skip whitespace */ 422 p++; 423 if (*p == '#') { 424 p = NULL; /* skip comments */ 425 continue; 426 } 427 q = p; 428 while (*p && *p != ' ' && *p != '\t' && *p != '\n') 429 p++; /* find next whitespace */ 430 *p++ = '\0'; /* null-terminate string */ 431 432 if (!*q) { 433 p = NULL; 434 continue; /* if 0-length string, read another line */ 435 } 436 437 return q; 438 } 439 } 440 441 static int 442 yylex(void) 443 { 444 int n; 445 u_int32_t addr; 446 char *q; 447 448 if ((q = next_word()) == NULL) { 449 return 0; 450 } 451 452 if (!strcmp(q,"cache_lifetime")) 453 return CACHE_LIFETIME; 454 if (!strcmp(q,"pruning")) 455 return PRUNING; 456 if (!strcmp(q,"phyint")) 457 return PHYINT; 458 if (!strcmp(q,"tunnel")) 459 return TUNNEL; 460 if (!strcmp(q,"disable")) 461 return DISABLE; 462 if (!strcmp(q,"metric")) 463 return METRIC; 464 if (!strcmp(q,"threshold")) 465 return THRESHOLD; 466 if (!strcmp(q,"rate_limit")) 467 return RATE_LIMIT; 468 if (!strcmp(q,"srcrt") || !strcmp(q,"sourceroute")) 469 return SRCRT; 470 if (!strcmp(q,"boundary")) 471 return BOUNDARY; 472 if (!strcmp(q,"netmask")) 473 return NETMASK; 474 if (!strcmp(q,"igmpv1")) 475 return IGMPV1; 476 if (!strcmp(q,"altnet")) 477 return ALTNET; 478 if (!strcmp(q,"name")) 479 return NAME; 480 if (!strcmp(q,"on") || !strcmp(q,"yes")) { 481 yylval.num = 1; 482 return BOOLEAN; 483 } 484 if (!strcmp(q,"off") || !strcmp(q,"no")) { 485 yylval.num = 0; 486 return BOOLEAN; 487 } 488 if (sscanf(q,"%[.0-9]/%d%c",s1,&n,s2) == 2) { 489 if ((addr = inet_parse(s1)) != 0xffffffff) { 490 yylval.addrmask.mask = n; 491 yylval.addrmask.addr = addr; 492 return ADDRMASK; 493 } 494 /* fall through to returning STRING */ 495 } 496 if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) { 497 if ((addr = inet_parse(s1)) != 0xffffffff && 498 inet_valid_host(addr)) { 499 yylval.addr = addr; 500 return ADDR; 501 } 502 } 503 if (sscanf(q,"0x%8x%c",&n,s1) == 1) { 504 yylval.addr = n; 505 return ADDR; 506 } 507 if (sscanf(q,"%d%c",&n,s1) == 1) { 508 yylval.num = n; 509 return NUMBER; 510 } 511 yylval.ptr = q; 512 return STRING; 513 } 514 515 void 516 config_vifs_from_file(void) 517 { 518 extern FILE *f; 519 520 order = 0; 521 numbounds = 0; 522 lineno = 0; 523 524 if ((f = fopen(configfilename, "r")) == NULL) { 525 if (errno != ENOENT) 526 logit(LOG_ERR, errno, "can't open %s", configfilename); 527 return; 528 } 529 530 yyparse(); 531 532 fclose(f); 533 } 534 535 static u_int32_t 536 valid_if(char *s) 537 { 538 register vifi_t vifi; 539 register struct uvif *v; 540 541 for (vifi=0, v=uvifs; vifi<numvifs; vifi++, v++) 542 if (!strcmp(v->uv_name, s)) 543 return v->uv_lcl_addr; 544 545 return 0; 546 } 547 548 static const char * 549 ifconfaddr(u_int32_t a) 550 { 551 static char ifname[IFNAMSIZ]; 552 struct ifaddrs *ifap, *ifa; 553 554 if (getifaddrs(&ifap) != 0) 555 return (NULL); 556 557 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 558 if (ifa->ifa_addr != NULL && 559 ifa->ifa_addr->sa_family == AF_INET && 560 ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == a) { 561 strlcpy(ifname, ifa->ifa_name, sizeof(ifname)); 562 freeifaddrs(ifap); 563 return (ifname); 564 } 565 } 566 freeifaddrs(ifap); 567 return (0); 568 } 569