1 /* 2 * The mrouted program is covered by the license in the accompanying file 3 * named "LICENSE". Use of the mrouted program represents acceptance of 4 * the terms and conditions listed in that file. 5 * 6 * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of 7 * Leland Stanford Junior University. 8 * 9 * 10 * from: Id: config.c,v 1.3 1993/05/30 01:36:38 deering Exp 11 * $Id: config.c,v 1.3 1994/06/09 16:04:00 brezak Exp $ 12 */ 13 14 #ifndef lint 15 static char rcsid[] = "$Id: config.c,v 1.3 1994/06/09 16:04:00 brezak Exp $"; 16 #endif 17 18 #include "defs.h" 19 20 21 char *configfilename = _PATH_MROUTED_CONF; 22 23 24 /* 25 * Forward declarations. 26 */ 27 static char *next_word(); 28 29 30 /* 31 * Query the kernel to find network interfaces that are multicast-capable 32 * and install them in the uvifs array. 33 */ 34 void config_vifs_from_kernel() 35 { 36 struct ifreq ifbuf[32]; 37 struct ifreq *ifrp, *ifend, *mp; 38 struct ifconf ifc; 39 register struct uvif *v; 40 register vifi_t vifi; 41 int i, n; 42 u_long addr, mask, subnet; 43 short flags; 44 45 ifc.ifc_buf = (char *)ifbuf; 46 ifc.ifc_len = sizeof(ifbuf); 47 if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0) 48 log(LOG_ERR, errno, "ioctl SIOCGIFCONF"); 49 50 ifrp = (struct ifreq *)ifbuf; 51 ifend = (struct ifreq *)((char *)ifbuf + ifc.ifc_len); 52 /* 53 * Loop through all of the interfaces. 54 */ 55 for (; ifrp < ifend; ifrp = (struct ifreq *)((char *)ifrp + n)) { 56 struct ifreq ifr; 57 #if BSD >= 199006 58 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); 59 if (n < sizeof(*ifrp)) 60 n = sizeof(*ifrp); 61 #else 62 n = sizeof(*ifrp); 63 #endif 64 /* 65 * Ignore any interface for an address family other than IP. 66 */ 67 addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr; 68 if (ifrp->ifr_addr.sa_family != AF_INET) 69 continue; 70 71 /* 72 * Need a template to preserve address info that is 73 * used below to locate the next entry. (Otherwise, 74 * SIOCGIFFLAGS stomps over it because the requests 75 * are returned in a union.) 76 */ 77 bcopy(ifrp->ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name)); 78 79 /* 80 * Ignore loopback interfaces and interfaces that do not support 81 * multicast. 82 */ 83 if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0) 84 log(LOG_ERR, errno, "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name); 85 flags = ifr.ifr_flags; 86 if ((flags & (IFF_LOOPBACK|IFF_MULTICAST)) != IFF_MULTICAST) continue; 87 88 /* 89 * Ignore any interface whose address and mask do not define a 90 * valid subnet number, or whose address is of the form {subnet,0} 91 * or {subnet,-1}. 92 */ 93 if (ioctl(udp_socket, SIOCGIFNETMASK, (char *)&ifr) < 0) 94 log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", ifr.ifr_name); 95 mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; 96 subnet = addr & mask; 97 if (!inet_valid_subnet(subnet, mask) || 98 addr == subnet || 99 addr == (subnet | ~mask)) { 100 log(LOG_WARNING, 0, 101 "ignoring %s, has invalid address (%s) and/or mask (%08x)", 102 ifr.ifr_name, inet_fmt(addr, s1), ntohl(mask)); 103 continue; 104 } 105 106 /* 107 * Ignore any interface that is connected to the same subnet as 108 * one already installed in the uvifs array. 109 */ 110 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { 111 if ((addr & v->uv_subnetmask) == v->uv_subnet || 112 (v->uv_subnet & mask) == subnet) { 113 log(LOG_WARNING, 0, "ignoring %s, same subnet as %s", 114 ifr.ifr_name, v->uv_name); 115 break; 116 } 117 } 118 if (vifi != numvifs) continue; 119 120 /* 121 * If there is room in the uvifs array, install this interface. 122 */ 123 if (numvifs == MAXVIFS) { 124 log(LOG_WARNING, 0, "too many vifs, ignoring %s", ifr.ifr_name); 125 continue; 126 } 127 v = &uvifs[numvifs]; 128 v->uv_flags = 0; 129 v->uv_metric = DEFAULT_METRIC; 130 v->uv_threshold = DEFAULT_THRESHOLD; 131 v->uv_lcl_addr = addr; 132 v->uv_rmt_addr = 0; 133 v->uv_subnet = subnet; 134 v->uv_subnetmask = mask; 135 v->uv_subnetbcast = subnet | ~mask; 136 strncpy(v->uv_name, ifr.ifr_name, IFNAMSIZ); 137 v->uv_groups = NULL; 138 v->uv_neighbors = NULL; 139 140 log(LOG_INFO, 0, "installing %s (%s on subnet %s) as vif #%u", 141 v->uv_name, inet_fmt(addr, s1), inet_fmts(subnet, mask, s2), 142 numvifs); 143 144 ++numvifs; 145 146 /* 147 * If the interface is not yet up, set the vifs_down flag to 148 * remind us to check again later. 149 */ 150 if (!(flags & IFF_UP)) { 151 v->uv_flags |= VIFF_DOWN; 152 vifs_down = TRUE; 153 } 154 } 155 } 156 157 static struct ifreq * 158 ifconfaddr(ifcp, a) 159 struct ifconf *ifcp; 160 u_long a; 161 { 162 int n; 163 struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf; 164 struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len); 165 166 while (ifrp < ifend) { 167 if (ifrp->ifr_addr.sa_family == AF_INET && 168 ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a) 169 return (ifrp); 170 #if BSD >= 199006 171 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); 172 if (n < sizeof(*ifrp)) 173 ++ifrp; 174 else 175 ifrp = (struct ifreq *)((char *)ifrp + n); 176 #else 177 ++ifrp; 178 #endif 179 } 180 return (0); 181 } 182 /* 183 * Read the config file to learn about tunnel vifs and 184 * non-default phyint parameters. 185 */ 186 void config_vifs_from_file() 187 { 188 FILE *f; 189 char linebuf[100]; 190 char *w, *s, c; 191 u_long lcl_addr, rmt_addr; 192 struct ifconf ifc; 193 struct ifreq *ifr; 194 struct ifreq ffr; 195 int i; 196 u_int n; 197 struct ifreq ifbuf[32]; 198 vifi_t vifi; 199 struct uvif *v; 200 201 f = fopen(configfilename, "r"); 202 if (f == NULL) { 203 if (errno != ENOENT) 204 log(LOG_WARNING, errno, "can't open %s", configfilename); 205 return; 206 } 207 208 ifc.ifc_buf = (char *)ifbuf; 209 ifc.ifc_len = sizeof(ifbuf); 210 if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0) 211 log(LOG_ERR, errno, "ioctl SIOCGIFCONF"); 212 213 while (fgets(linebuf, sizeof(linebuf), f) != NULL) { 214 215 s = linebuf; 216 if (EQUAL((w = next_word(&s)), "")) { 217 /* 218 * blank or comment line; ignore 219 */ 220 } 221 222 else if (EQUAL(w, "phyint")) { 223 /* 224 * phyint <local-addr> [disable] [metric <m>] [threshold <t>] 225 */ 226 227 /* 228 * Parse the local address. 229 */ 230 if (EQUAL((w = next_word(&s)), "")) { 231 log(LOG_WARNING, 0, 232 "missing phyint address in %s", 233 configfilename); 234 continue; 235 } 236 if ((lcl_addr = inet_parse(w)) == 0xffffffff || 237 !inet_valid_host(lcl_addr)) { 238 log(LOG_WARNING, 0, 239 "invalid phyint address '%s' in %s", 240 w, configfilename); 241 continue; 242 } 243 244 /* 245 * Look up the vif with the specified local address. 246 */ 247 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { 248 if (!(v->uv_flags & VIFF_TUNNEL) && 249 lcl_addr == v->uv_lcl_addr) { 250 break; 251 } 252 } 253 if (vifi == numvifs) { 254 log(LOG_WARNING, 0, 255 "phyint %s in %s is not a configured interface", 256 inet_fmt(lcl_addr, s1), configfilename); 257 continue; 258 } 259 260 /* 261 * Look for "disable", "metric" and "threshold" options. 262 */ 263 while (!EQUAL((w = next_word(&s)), "")) { 264 if (EQUAL(w, "disable")) { 265 v->uv_flags |= VIFF_DISABLED; 266 } 267 else if (EQUAL(w, "metric")) { 268 if(EQUAL((w = next_word(&s)), "")) { 269 log(LOG_WARNING, 0, 270 "missing metric for phyint %s in %s", 271 inet_fmt(lcl_addr, s1), configfilename); 272 w = "garbage"; 273 break; 274 } 275 if(sscanf(w, "%u%c", &n, &c) != 1 || 276 n < 1 || n >= UNREACHABLE ) { 277 log(LOG_WARNING, 0, 278 "invalid metric '%s' for phyint %s in %s", 279 w, inet_fmt(lcl_addr, s1), configfilename); 280 break; 281 } 282 v->uv_metric = n; 283 } 284 else if (EQUAL(w, "threshold")) { 285 if(EQUAL((w = next_word(&s)), "")) { 286 log(LOG_WARNING, 0, 287 "missing threshold for phyint %s in %s", 288 inet_fmt(lcl_addr, s1), configfilename); 289 w = "garbage"; 290 break; 291 } 292 if(sscanf(w, "%u%c", &n, &c) != 1 || 293 n < 1 || n > 255 ) { 294 log(LOG_WARNING, 0, 295 "invalid threshold '%s' for phyint %s in %s", 296 w, inet_fmt(lcl_addr, s1), configfilename); 297 break; 298 } 299 v->uv_threshold = n; 300 } 301 else break; 302 } 303 if (!EQUAL(w, "")) continue; 304 } 305 306 else if (EQUAL(w, "tunnel")) { 307 /* 308 * tunnel <local-addr> <remote-addr> [srcrt] [metric <m>] [threshold <t>] 309 */ 310 311 /* 312 * Parse the local address. 313 */ 314 if (EQUAL((w = next_word(&s)), "")) { 315 log(LOG_WARNING, 0, 316 "missing tunnel local address in %s", 317 configfilename); 318 continue; 319 } 320 if ((lcl_addr = inet_parse(w)) == 0xffffffff || 321 !inet_valid_host(lcl_addr)) { 322 log(LOG_WARNING, 0, 323 "invalid tunnel local address '%s' in %s", 324 w, configfilename); 325 continue; 326 } 327 328 /* 329 * Make sure the local address is one of ours. 330 */ 331 ifr = ifconfaddr(&ifc, lcl_addr); 332 if (ifr == 0) { 333 log(LOG_WARNING, 0, 334 "tunnel local address %s in %s is not one of ours", 335 inet_fmt(lcl_addr, s1), configfilename); 336 continue; 337 } 338 339 /* 340 * Make sure the local address doesn't name a loopback interface.. 341 */ 342 strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ); 343 if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr) < 0) { 344 log(LOG_ERR, errno, 345 "ioctl SIOCGIFFLAGS for %s", ffr.ifr_name); 346 } 347 if (ffr.ifr_flags & IFF_LOOPBACK) { 348 log(LOG_WARNING, 0, 349 "tunnel local address %s in %s is a loopback interface", 350 inet_fmt(lcl_addr, s1), configfilename); 351 continue; 352 } 353 354 /* 355 * Parse the remote address. 356 */ 357 if (EQUAL((w = next_word(&s)), "")) { 358 log(LOG_WARNING, 0, 359 "missing tunnel remote address in %s", 360 configfilename); 361 continue; 362 } 363 if ((rmt_addr = inet_parse(w)) == 0xffffffff || 364 !inet_valid_host(rmt_addr)) { 365 log(LOG_WARNING, 0, 366 "invalid tunnel remote address %s in %s", 367 w, configfilename); 368 continue; 369 } 370 371 /* 372 * Make sure the remote address is not one of ours. 373 */ 374 if (ifconfaddr(&ifc, rmt_addr) != 0) { 375 log(LOG_WARNING, 0, 376 "tunnel remote address %s in %s is one of ours", 377 inet_fmt(rmt_addr, s1), configfilename); 378 continue; 379 } 380 381 /* 382 * Make sure the remote address has not been used for another 383 * tunnel and does not belong to a subnet to which we have direct 384 * access on an enabled phyint. 385 */ 386 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { 387 if (v->uv_flags & VIFF_TUNNEL) { 388 if (rmt_addr == v->uv_rmt_addr) { 389 log(LOG_WARNING, 0, 390 "duplicate tunnel remote address %s in %s", 391 inet_fmt(rmt_addr, s1), configfilename); 392 break; 393 } 394 } 395 else if (!(v->uv_flags & VIFF_DISABLED)) { 396 if ((rmt_addr & v->uv_subnetmask) == v->uv_subnet) { 397 log(LOG_WARNING, 0, 398 "unnecessary tunnel remote address %s in %s", 399 inet_fmt(rmt_addr, s1), configfilename); 400 break; 401 } 402 } 403 } 404 if (vifi != numvifs) continue; 405 406 /* 407 * OK, let's initialize a uvif structure for the tunnel. 408 */ 409 if (numvifs == MAXVIFS) { 410 log(LOG_WARNING, 0, "too many vifs, ignoring tunnel to %s", 411 inet_fmt(rmt_addr, s1)); 412 continue; 413 } 414 v = &uvifs[numvifs]; 415 v->uv_flags = VIFF_TUNNEL; 416 v->uv_metric = DEFAULT_METRIC; 417 v->uv_threshold = DEFAULT_THRESHOLD; 418 v->uv_lcl_addr = lcl_addr; 419 v->uv_rmt_addr = rmt_addr; 420 v->uv_subnet = 0; 421 v->uv_subnetmask = 0; 422 v->uv_subnetbcast = 0; 423 strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ); 424 v->uv_groups = NULL; 425 v->uv_neighbors = NULL; 426 427 /* 428 * Look for "metric" and "threshold" options. 429 */ 430 while (!EQUAL((w = next_word(&s)), "")) { 431 if (EQUAL(w, "metric")) { 432 if(EQUAL((w = next_word(&s)), "")) { 433 log(LOG_WARNING, 0, 434 "missing metric for tunnel to %s in %s", 435 inet_fmt(rmt_addr, s1), configfilename); 436 w = "garbage"; 437 break; 438 } 439 if(sscanf(w, "%u%c", &n, &c) != 1 || 440 n < 1 || n >= UNREACHABLE ) { 441 log(LOG_WARNING, 0, 442 "invalid metric '%s' for tunnel to %s in %s", 443 w, inet_fmt(rmt_addr, s1), configfilename); 444 break; 445 } 446 v->uv_metric = n; 447 } 448 else if (EQUAL(w, "threshold")) { 449 if(EQUAL((w = next_word(&s)), "")) { 450 log(LOG_WARNING, 0, 451 "missing threshold for tunnel to %s in %s", 452 inet_fmt(rmt_addr, s1), configfilename); 453 w = "garbage"; 454 break; 455 } 456 if(sscanf(w, "%u%c", &n, &c) != 1 || 457 n < 1 || n > 255 ) { 458 log(LOG_WARNING, 0, 459 "invalid threshold '%s' for tunnel to %s in %s", 460 w, inet_fmt(rmt_addr, s1), configfilename); 461 break; 462 } 463 v->uv_threshold = n; 464 } 465 else if (EQUAL(w, "srcrt") || EQUAL(w, "sourceroute")) { 466 v->uv_flags |= VIFF_SRCRT; 467 } 468 else break; 469 } 470 if (!EQUAL(w, "")) continue; 471 472 log(LOG_INFO, 0, 473 "installing %stunnel from %s to %s as vif #%u", 474 v->uv_flags & VIFF_SRCRT? "srcrt " : "", 475 inet_fmt(lcl_addr, s1), inet_fmt(rmt_addr, s2), numvifs); 476 477 ++numvifs; 478 479 if (!(ffr.ifr_flags & IFF_UP)) { 480 v->uv_flags |= VIFF_DOWN; 481 vifs_down = TRUE; 482 } 483 } 484 485 else { 486 log(LOG_WARNING, 0, 487 "unknown command '%s' in %s", w, configfilename); 488 } 489 } 490 491 close(f); 492 } 493 494 495 /* 496 * Return a pointer to the next "word" in the string to which '*s' points, 497 * lower-cased and null terminated, and advance '*s' to point beyond the word. 498 * Words are separated by blanks and/or tabs, and the input string is 499 * considered to terminate at a newline, '#' (comment), or null character. 500 * If no words remain, a pointer to a null string ("") is returned. 501 * Warning: This function clobbers the input string. 502 */ 503 static char *next_word(s) 504 char **s; 505 { 506 char *w; 507 508 w = *s; 509 while (*w == ' ' || *w == '\t') 510 ++w; 511 512 *s = w; 513 for(;;) { 514 switch (**s) { 515 516 case ' ' : 517 case '\t' : **s = '\0'; 518 ++*s; 519 return (w); 520 521 case '\n' : 522 case '#' : **s = '\0'; 523 return (w); 524 525 case '\0' : return (w); 526 527 default : if (isascii(**s) && isupper(**s)) 528 **s = tolower(**s); 529 ++*s; 530 } 531 } 532 } 533