1 %{ 2 /* $NetBSD: cfparse.y,v 1.3 1995/10/09 03:51:35 thorpej Exp $ */ 3 4 /* 5 * Configuration file parser for mrouted. 6 * 7 * Written by Bill Fenner, NRL, 1994 8 */ 9 #include <stdio.h> 10 #include <string.h> 11 #include <varargs.h> 12 #include "defs.h" 13 14 static FILE *f; 15 16 extern int udp_socket; 17 char *configfilename = _PATH_MROUTED_CONF; 18 19 extern int cache_lifetime; 20 extern int max_prune_lifetime; 21 22 static int lineno; 23 static struct ifreq ifbuf[32]; 24 static struct ifconf ifc; 25 26 static struct uvif *v; 27 28 static int order; 29 30 struct addrmask { 31 u_int32_t addr; 32 int mask; 33 }; 34 35 struct boundnam { 36 char *name; 37 struct addrmask bound; 38 }; 39 40 #define MAXBOUNDS 20 41 42 struct boundnam boundlist[MAXBOUNDS]; /* Max. of 20 named boundaries */ 43 int numbounds = 0; /* Number of named boundaries */ 44 45 %} 46 47 %union 48 { 49 int num; 50 char *ptr; 51 struct addrmask addrmask; 52 u_int32_t addr; 53 }; 54 55 %token CACHE_LIFETIME PRUNING 56 %token PHYINT TUNNEL NAME 57 %token DISABLE METRIC THRESHOLD RATE_LIMIT SRCRT BOUNDARY NETMASK ALTNET 58 %token <num> BOOLEAN 59 %token <num> NUMBER 60 %token <ptr> STRING 61 %token <addrmask> ADDRMASK 62 %token <addr> ADDR 63 64 %type <addr> interface 65 %type <addrmask> bound boundary addrmask 66 67 %start conf 68 69 %% 70 71 conf : stmts 72 ; 73 74 stmts : /* Empty */ 75 | stmts stmt 76 ; 77 78 stmt : error 79 | PHYINT interface { 80 81 vifi_t vifi; 82 83 if (order) 84 fatal("phyints must appear before tunnels"); 85 86 for (vifi = 0, v = uvifs; 87 vifi < numvifs; 88 ++vifi, ++v) 89 if (!(v->uv_flags & VIFF_TUNNEL) && 90 $2 == v->uv_lcl_addr) 91 break; 92 93 if (vifi == numvifs) 94 fatal("%s is not a configured interface", 95 inet_fmt($2,s1)); 96 97 /*log(LOG_INFO, 0, "phyint: %x\n", v);*/ 98 } 99 ifmods 100 | TUNNEL interface ADDR { 101 102 struct ifreq *ifr; 103 struct ifreq ffr; 104 vifi_t vifi; 105 106 order++; 107 108 ifr = ifconfaddr(&ifc, $2); 109 if (ifr == 0) 110 fatal("Tunnel local address %s is not mine", 111 inet_fmt($2, s1)); 112 113 strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ); 114 if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr)<0) 115 fatal("ioctl SIOCGIFFLAGS on %s",ffr.ifr_name); 116 if (ffr.ifr_flags & IFF_LOOPBACK) 117 fatal("Tunnel local address %s is a loopback interface", 118 inet_fmt($2, s1)); 119 120 if (ifconfaddr(&ifc, $3) != 0) 121 fatal("Tunnel remote address %s is one of mine", 122 inet_fmt($3, s1)); 123 124 for (vifi = 0, v = uvifs; 125 vifi < numvifs; 126 ++vifi, ++v) 127 if (v->uv_flags & VIFF_TUNNEL) { 128 if ($3 == v->uv_rmt_addr) 129 fatal("Duplicate tunnel to %s", 130 inet_fmt($3, s1)); 131 } else if (!(v->uv_flags & VIFF_DISABLED)) { 132 if (($3 & v->uv_subnetmask) == v->uv_subnet) 133 fatal("Unnecessary tunnel to %s", 134 inet_fmt($3,s1)); 135 } 136 137 if (numvifs == MAXVIFS) 138 fatal("too many vifs"); 139 140 v = &uvifs[numvifs]; 141 v->uv_flags = VIFF_TUNNEL; 142 v->uv_metric = DEFAULT_METRIC; 143 v->uv_rate_limit= DEFAULT_TUN_RATE_LIMIT; 144 v->uv_threshold = DEFAULT_THRESHOLD; 145 v->uv_lcl_addr = $2; 146 v->uv_rmt_addr = $3; 147 v->uv_subnet = 0; 148 v->uv_subnetmask= 0; 149 v->uv_subnetbcast= 0; 150 strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ); 151 v->uv_groups = NULL; 152 v->uv_neighbors = NULL; 153 v->uv_acl = NULL; 154 v->uv_addrs = NULL; 155 156 if (!(ffr.ifr_flags & IFF_UP)) { 157 v->uv_flags |= VIFF_DOWN; 158 vifs_down = TRUE; 159 } 160 /*log(LOG_INFO, 0, "tunnel: %x\n", v);*/ 161 } 162 tunnelmods 163 { 164 log(LOG_INFO, 0, 165 "installing tunnel from %s to %s as vif #%u - rate=%d", 166 inet_fmt($2, s1), inet_fmt($3, s2), 167 numvifs, v->uv_rate_limit); 168 169 ++numvifs; 170 } 171 | PRUNING BOOLEAN { pruning = $2; } 172 | CACHE_LIFETIME NUMBER { cache_lifetime = $2; 173 max_prune_lifetime = cache_lifetime * 2; 174 } 175 | NAME STRING boundary { if (numbounds >= MAXBOUNDS) { 176 fatal("Too many named boundaries (max %d)", MAXBOUNDS); 177 } 178 179 boundlist[numbounds].name = malloc(strlen($2) + 1); 180 strcpy(boundlist[numbounds].name, $2); 181 boundlist[numbounds++].bound = $3; 182 } 183 ; 184 185 tunnelmods : /* empty */ 186 | tunnelmods /*{ log(LOG_INFO, 0, "tunnelmod: %x", v); }*/ tunnelmod 187 ; 188 189 tunnelmod : mod 190 | SRCRT { fatal("Source-route tunnels not supported"); } 191 ; 192 193 ifmods : /* empty */ 194 | ifmods /*{ log(LOG_INFO, 0, "ifmod: %x", v); }*/ ifmod 195 ; 196 197 ifmod : mod 198 | DISABLE { v->uv_flags |= VIFF_DISABLED; } 199 | NETMASK ADDR { v->uv_subnetmask = $2; } 200 | ALTNET addrmask { 201 202 struct phaddr *ph; 203 204 ph = (struct phaddr *)malloc(sizeof(struct phaddr)); 205 if (ph == NULL) 206 fatal("out of memory"); 207 if ($2.mask) { 208 VAL_TO_MASK(ph->pa_mask, $2.mask); 209 } else 210 ph->pa_mask = v->uv_subnetmask; 211 ph->pa_addr = $2.addr & ph->pa_mask; 212 if ($2.addr & ~ph->pa_mask) 213 warn("Extra addr %s/%d has host bits set", 214 inet_fmt($2.addr,s1), $2.mask); 215 ph->pa_next = v->uv_addrs; 216 v->uv_addrs = ph; 217 218 } 219 ; 220 221 mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255) 222 fatal("Invalid threshold %d",$2); 223 v->uv_threshold = $2; 224 } 225 | THRESHOLD { 226 227 warn("Expected number after threshold keyword"); 228 229 } 230 | METRIC NUMBER { if ($2 < 1 || $2 > UNREACHABLE) 231 fatal("Invalid metric %d",$2); 232 v->uv_metric = $2; 233 } 234 | METRIC { 235 236 warn("Expected number after metric keyword"); 237 238 } 239 | RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT) 240 fatal("Invalid rate_limit %d",$2); 241 v->uv_rate_limit = $2; 242 } 243 | RATE_LIMIT { 244 245 warn("Expected number after rate_limit keyword"); 246 247 } 248 | BOUNDARY bound { 249 250 struct vif_acl *v_acl; 251 252 v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl)); 253 if (v_acl == NULL) 254 fatal("out of memory"); 255 VAL_TO_MASK(v_acl->acl_mask, $2.mask); 256 v_acl->acl_addr = $2.addr & v_acl->acl_mask; 257 if ($2.addr & ~v_acl->acl_mask) 258 warn("Boundary spec %s/%d has host bits set", 259 inet_fmt($2.addr,s1),$2.mask); 260 v_acl->acl_next = v->uv_acl; 261 v->uv_acl = v_acl; 262 263 } 264 | BOUNDARY { 265 266 warn("Expected boundary spec after boundary keyword"); 267 268 } 269 ; 270 271 interface : ADDR { $$ = $1; } 272 | STRING { 273 $$ = valid_if($1); 274 if ($$ == 0) 275 fatal("Invalid interface name %s",$1); 276 } 277 ; 278 279 bound : boundary { $$ = $1; } 280 | STRING { int i; 281 282 for (i=0; i < numbounds; i++) { 283 if (!strcmp(boundlist[i].name, $1)) { 284 $$ = boundlist[i].bound; 285 break; 286 } 287 } 288 if (i == numbounds) { 289 fatal("Invalid boundary name %s",$1); 290 } 291 } 292 ; 293 294 boundary : ADDRMASK { 295 296 if ((ntohl($1.addr) & 0xff000000) != 0xef000000) { 297 fatal("Boundaries must be 239.x.x.x, not %s/%d", 298 inet_fmt($1.addr, s1), $1.mask); 299 } 300 $$ = $1; 301 302 } 303 ; 304 305 addrmask : ADDRMASK { $$ = $1; } 306 | ADDR { $$.addr = $1; $$.mask = 0; } 307 ; 308 %% 309 /*VARARGS1*/ 310 static void fatal(fmt, va_alist) 311 char *fmt; 312 va_dcl 313 { 314 va_list ap; 315 char buf[200]; 316 317 va_start(ap); 318 vsprintf(buf, fmt, ap); 319 va_end(ap); 320 321 log(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno); 322 } 323 324 /*VARARGS1*/ 325 static void warn(fmt, va_alist) 326 char *fmt; 327 va_dcl 328 { 329 va_list ap; 330 char buf[200]; 331 332 va_start(ap); 333 vsprintf(buf, fmt, ap); 334 va_end(ap); 335 336 log(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno); 337 } 338 339 void yyerror(s) 340 char *s; 341 { 342 log(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno); 343 } 344 345 char *next_word() 346 { 347 static char buf[1024]; 348 static char *p=NULL; 349 extern FILE *f; 350 char *q; 351 352 while (1) { 353 if (!p || !*p) { 354 lineno++; 355 if (fgets(buf, sizeof(buf), f) == NULL) 356 return NULL; 357 p = buf; 358 } 359 while (*p && (*p == ' ' || *p == '\t')) /* skip whitespace */ 360 p++; 361 if (*p == '#') { 362 p = NULL; /* skip comments */ 363 continue; 364 } 365 q = p; 366 while (*p && *p != ' ' && *p != '\t' && *p != '\n') 367 p++; /* find next whitespace */ 368 *p++ = '\0'; /* null-terminate string */ 369 370 if (!*q) { 371 p = NULL; 372 continue; /* if 0-length string, read another line */ 373 } 374 375 return q; 376 } 377 } 378 379 int yylex() 380 { 381 int n; 382 u_int32_t addr; 383 char *q; 384 385 if ((q = next_word()) == NULL) { 386 return 0; 387 } 388 389 if (!strcmp(q,"cache_lifetime")) 390 return CACHE_LIFETIME; 391 if (!strcmp(q,"pruning")) 392 return PRUNING; 393 if (!strcmp(q,"phyint")) 394 return PHYINT; 395 if (!strcmp(q,"tunnel")) 396 return TUNNEL; 397 if (!strcmp(q,"disable")) 398 return DISABLE; 399 if (!strcmp(q,"metric")) 400 return METRIC; 401 if (!strcmp(q,"threshold")) 402 return THRESHOLD; 403 if (!strcmp(q,"rate_limit")) 404 return RATE_LIMIT; 405 if (!strcmp(q,"srcrt") || !strcmp(q,"sourceroute")) 406 return SRCRT; 407 if (!strcmp(q,"boundary")) 408 return BOUNDARY; 409 if (!strcmp(q,"netmask")) 410 return NETMASK; 411 if (!strcmp(q,"name")) 412 return NAME; 413 if (!strcmp(q,"altnet")) 414 return ALTNET; 415 if (!strcmp(q,"on") || !strcmp(q,"yes")) { 416 yylval.num = 1; 417 return BOOLEAN; 418 } 419 if (!strcmp(q,"off") || !strcmp(q,"no")) { 420 yylval.num = 0; 421 return BOOLEAN; 422 } 423 if (sscanf(q,"%[.0-9]/%d%c",s1,&n,s2) == 2) { 424 if ((addr = inet_parse(s1)) != 0xffffffff) { 425 yylval.addrmask.mask = n; 426 yylval.addrmask.addr = addr; 427 return ADDRMASK; 428 } 429 /* fall through to returning STRING */ 430 } 431 if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) { 432 if ((addr = inet_parse(s1)) != 0xffffffff && 433 inet_valid_host(addr)) { 434 yylval.addr = addr; 435 return ADDR; 436 } 437 } 438 if (sscanf(q,"0x%8x%c",&n,s1) == 1) { 439 yylval.addr = n; 440 return ADDR; 441 } 442 if (sscanf(q,"%d%c",&n,s1) == 1) { 443 yylval.num = n; 444 return NUMBER; 445 } 446 yylval.ptr = q; 447 return STRING; 448 } 449 450 void config_vifs_from_file() 451 { 452 extern FILE *f; 453 454 order = 0; 455 numbounds = 0; 456 lineno = 0; 457 458 if ((f = fopen(configfilename, "r")) == NULL) { 459 if (errno != ENOENT) 460 log(LOG_ERR, errno, "can't open %s", configfilename); 461 return; 462 } 463 464 ifc.ifc_buf = (char *)ifbuf; 465 ifc.ifc_len = sizeof(ifbuf); 466 if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0) 467 log(LOG_ERR, errno, "ioctl SIOCGIFCONF"); 468 469 yyparse(); 470 471 close(f); 472 } 473 474 static u_int32_t 475 valid_if(s) 476 char *s; 477 { 478 register vifi_t vifi; 479 register struct uvif *v; 480 481 for (vifi=0, v=uvifs; vifi<numvifs; vifi++, v++) 482 if (!strcmp(v->uv_name, s)) 483 return v->uv_lcl_addr; 484 485 return 0; 486 } 487 488 static struct ifreq * 489 ifconfaddr(ifcp, a) 490 struct ifconf *ifcp; 491 u_int32_t a; 492 { 493 int n; 494 struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf; 495 struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len); 496 497 while (ifrp < ifend) { 498 if (ifrp->ifr_addr.sa_family == AF_INET && 499 ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a) 500 return (ifrp); 501 #if (defined(BSD) && (BSD >= 199006)) 502 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); 503 if (n < sizeof(*ifrp)) 504 ++ifrp; 505 else 506 ifrp = (struct ifreq *)((char *)ifrp + n); 507 #else 508 ++ifrp; 509 #endif 510 } 511 return (0); 512 } 513