1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #if !defined(lint) && !defined(sgi) && !defined(__NetBSD__) 35 static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93"; 36 #elif defined(__NetBSD__) 37 static char rcsid[] = "$NetBSD$"; 38 #endif 39 #ident "$Revision: 1.9 $" 40 41 #include "defs.h" 42 #include "pathnames.h" 43 44 45 struct parm *parms; 46 struct intnet *intnets; 47 48 49 /* use configured parameters 50 */ 51 void 52 get_parms(struct interface *ifp) 53 { 54 struct parm *parmp; 55 56 /* get all relevant parameters 57 */ 58 for (parmp = parms; parmp != 0; parmp = parmp->parm_next) { 59 if ((parmp->parm_name[0] == '\0' 60 && on_net(ifp->int_addr, 61 parmp->parm_addr_h, parmp->parm_mask)) 62 || (parmp->parm_name[0] != '\0' 63 && !strcmp(ifp->int_name, parmp->parm_name))) { 64 /* this group of parameters is relevant, 65 * so get its settings 66 */ 67 ifp->int_state |= parmp->parm_int_state; 68 if (parmp->parm_passwd[0] != '\0') 69 bcopy(parmp->parm_passwd, ifp->int_passwd, 70 sizeof(ifp->int_passwd)); 71 if (parmp->parm_rdisc_pref != 0) 72 ifp->int_rdisc_pref = parmp->parm_rdisc_pref; 73 if (parmp->parm_rdisc_int != 0) 74 ifp->int_rdisc_int = parmp->parm_rdisc_int; 75 if (parmp->parm_d_metric != 0) 76 ifp->int_d_metric = parmp->parm_d_metric; 77 } 78 } 79 /* default poor-man's router discovery to a metric that will 80 * be heard by old versions of routed. 81 */ 82 if ((ifp->int_state & IS_PM_RDISC) 83 && ifp->int_d_metric == 0) 84 ifp->int_d_metric = HOPCNT_INFINITY-2; 85 86 if (IS_RIP_IN_OFF(ifp->int_state)) 87 ifp->int_state |= IS_NO_RIP_OUT; 88 89 if (ifp->int_rdisc_int == 0) 90 ifp->int_rdisc_int = DefMaxAdvertiseInterval; 91 92 if (!(ifp->int_if_flags & IFF_MULTICAST) 93 && !(ifp->int_if_flags & IFF_POINTOPOINT)) 94 ifp->int_state |= IS_NO_RIPV2_OUT; 95 96 if (!(ifp->int_if_flags & IFF_MULTICAST)) 97 ifp->int_state |= IS_BCAST_RDISC; 98 99 if (ifp->int_if_flags & IFF_POINTOPOINT) { 100 ifp->int_state |= IS_BCAST_RDISC; 101 /* By default, point-to-point links should be passive 102 * about router-discovery for the sake of demand-dialing. 103 */ 104 if (0 == (ifp->int_state & GROUP_IS_SOL)) 105 ifp->int_state |= IS_NO_SOL_OUT; 106 if (0 == (ifp->int_state & GROUP_IS_ADV)) 107 ifp->int_state |= IS_NO_ADV_OUT; 108 } 109 110 if (0 != (ifp->int_state & (IS_PASSIVE | IS_REMOTE))) 111 ifp->int_state |= IS_NO_RDISC; 112 if (ifp->int_state & IS_PASSIVE) 113 ifp->int_state |= (IS_NO_RIP | IS_NO_RDISC); 114 if ((ifp->int_state & (IS_NO_RIP | IS_NO_RDISC)) 115 == (IS_NO_RIP|IS_NO_RDISC)) 116 ifp->int_state |= IS_PASSIVE; 117 } 118 119 120 /* Read a list of gateways from /etc/gateways and add them to our tables. 121 * 122 * This file contains a list of "remote" gateways. That is usually 123 * a gateway which we cannot immediately determine if it is present or 124 * not as we can do for those provided by directly connected hardware. 125 * 126 * If a gateway is marked "passive" in the file, then we assume it 127 * does not understand RIP and assume it is always present. Those 128 * not marked passive are treated as if they were directly connected 129 * and assumed to be broken if they do not send us advertisements. 130 * All remote interfaces are added to our list, and those not marked 131 * passive are sent routing updates. 132 * 133 * A passive interface can also be local, hardware interface exempt 134 * from RIP. 135 */ 136 void 137 gwkludge(void) 138 { 139 FILE *fp; 140 char *p, *lptr; 141 char lbuf[200], net_host[5], dname[64+1+64+1], gname[64+1], qual[9]; 142 struct interface *ifp; 143 naddr dst, netmask, gate; 144 int metric, n; 145 u_int state; 146 char *type; 147 struct parm *parmp; 148 149 150 fp = fopen(_PATH_GATEWAYS, "r"); 151 if (fp == 0) 152 return; 153 154 for (;;) { 155 if (0 == fgets(lbuf, sizeof(lbuf)-1, fp)) 156 break; 157 lptr = lbuf; 158 while (*lptr == ' ') 159 lptr++; 160 if (*lptr == '\n' /* ignore null and comment lines */ 161 || *lptr == '#') 162 continue; 163 p = lptr+strlen(lptr)-1; 164 while (*p == '\n' 165 || *p == ' ') 166 *p-- = '\0'; 167 168 /* notice newfangled parameter lines 169 */ 170 if (strncasecmp("net", lptr, 3) 171 && strncasecmp("host", lptr, 4)) { 172 p = parse_parms(lptr); 173 if (p != 0) { 174 if (strcmp(p,lptr)) 175 msglog("bad \"%s\" in "_PATH_GATEWAYS 176 " entry \"%s\"", lptr, p); 177 else 178 msglog("bad \"%s\" in "_PATH_GATEWAYS, 179 lptr); 180 } 181 continue; 182 } 183 184 /* {net | host} XX[/M] XX gateway XX metric DD [passive | external]\n */ 185 n = sscanf(lptr, "%4s %129[^ \t] gateway" 186 " %64[^ / \t] metric %d %8s\n", 187 net_host, dname, gname, &metric, qual); 188 if (n != 5) { 189 msglog("bad "_PATH_GATEWAYS" entry \"%s\"", lptr); 190 continue; 191 } 192 if (metric < 0 || metric >= HOPCNT_INFINITY) { 193 msglog("bad metric in "_PATH_GATEWAYS" entry \"%s\"", 194 lptr); 195 continue; 196 } 197 if (!strcmp(net_host, "host")) { 198 if (!gethost(dname, &dst)) { 199 msglog("bad host \"%s\" in "_PATH_GATEWAYS 200 " entry \"%s\"", dname, lptr); 201 continue; 202 } 203 netmask = HOST_MASK; 204 } else if (!strcmp(net_host, "net")) { 205 if (!getnet(dname, &dst, &netmask)) { 206 msglog("bad net \"%s\" in "_PATH_GATEWAYS 207 " entry \"%s\"", dname, lptr); 208 continue; 209 } 210 } else { 211 msglog("bad \"%s\" in "_PATH_GATEWAYS 212 " entry \"%s\"", lptr); 213 continue; 214 } 215 216 if (!gethost(gname, &gate)) { 217 msglog("bad gateway \"%s\" in "_PATH_GATEWAYS 218 " entry \"%s\"", gname, lptr); 219 continue; 220 } 221 222 if (strcmp(qual, type = "passive") == 0) { 223 /* Passive entries are not placed in our tables, 224 * only the kernel's, so we don't copy all of the 225 * external routing information within a net. 226 * Internal machines should use the default 227 * route to a suitable gateway (like us). 228 */ 229 state = IS_REMOTE | IS_PASSIVE; 230 if (metric == 0) 231 metric = 1; 232 233 } else if (strcmp(qual, type = "external") == 0) { 234 /* External entries are handled by other means 235 * such as EGP, and are placed only in the daemon 236 * tables to prevent overriding them with something 237 * else. 238 */ 239 state = IS_REMOTE | IS_PASSIVE | IS_EXTERNAL; 240 if (metric == 0) 241 metric = 1; 242 243 } else if (qual[0] == '\0') { 244 if (metric != 0) { 245 /* Entries that are neither "passive" nor 246 * "external" are "remote" and must behave 247 * like physical interfaces. If they are not 248 * heard from regularly, they are deleted. 249 */ 250 state = IS_REMOTE; 251 type = "remote"; 252 } else { 253 /* "remote" entries with a metric of 0 254 * are aliases for our own interfaces 255 */ 256 state = IS_REMOTE | IS_PASSIVE; 257 type = "alias"; 258 } 259 260 } else { 261 msglog("bad "_PATH_GATEWAYS" entry \"%s\"", lptr); 262 continue; 263 } 264 265 /* Remember to advertise the corresponding logical network. 266 */ 267 if (!(state & IS_EXTERNAL) 268 && netmask != std_mask(dst)) 269 state |= IS_SUBNET; 270 271 if (0 != (state & (IS_PASSIVE | IS_REMOTE))) 272 state |= IS_NO_RDISC; 273 if (state & IS_PASSIVE) 274 state |= (IS_NO_RIP | IS_NO_RDISC); 275 if ((state & (IS_NO_RIP | IS_NO_RDISC)) 276 == (IS_NO_RIP|IS_NO_RDISC)) 277 state |= IS_PASSIVE; 278 279 parmp = (struct parm*)malloc(sizeof(*parmp)); 280 bzero(parmp, sizeof(*parmp)); 281 parmp->parm_next = parms; 282 parms = parmp; 283 parmp->parm_addr_h = ntohl(dst); 284 parmp->parm_mask = -1; 285 parmp->parm_d_metric = 0; 286 parmp->parm_int_state = state; 287 288 /* See if this new interface duplicates an existing 289 * interface. 290 */ 291 for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { 292 if (ifp->int_mask == netmask 293 && ((ifp->int_addr == dst 294 && netmask != HOST_MASK) 295 || (ifp->int_dstaddr == dst 296 && netmask == HOST_MASK))) 297 break; 298 } 299 if (ifp != 0) { 300 /* Let one of our real interfaces be marked passive. 301 */ 302 if ((state & IS_PASSIVE) && !(state & IS_EXTERNAL)) { 303 ifp->int_state |= state; 304 } else { 305 msglog("%s is duplicated in "_PATH_GATEWAYS 306 " by %s", 307 ifp->int_name, lptr); 308 } 309 continue; 310 } 311 312 tot_interfaces++; 313 314 ifp = (struct interface *)malloc(sizeof(*ifp)); 315 bzero(ifp, sizeof(*ifp)); 316 if (ifnet != 0) { 317 ifp->int_next = ifnet; 318 ifnet->int_prev = ifp; 319 } 320 ifnet = ifp; 321 322 ifp->int_state = state; 323 ifp->int_net = ntohl(dst) & netmask; 324 ifp->int_mask = netmask; 325 if (netmask == HOST_MASK) 326 ifp->int_if_flags |= IFF_POINTOPOINT; 327 ifp->int_dstaddr = dst; 328 ifp->int_addr = gate; 329 ifp->int_metric = metric; 330 (void)sprintf(ifp->int_name, "%s-%s", type, naddr_ntoa(dst)); 331 ifp->int_index = -1; 332 333 get_parms(ifp); 334 335 trace_if("Add", ifp); 336 } 337 } 338 339 340 /* parse a set of parameters for an interface 341 */ 342 char * /* 0 or error message */ 343 parse_parms(char *line) 344 { 345 #define PARS(str) (0 == (tgt = str, strcasecmp(tok, tgt))) 346 #define PARSE(str) (0 == (tgt = str, strncasecmp(tok, str "=", sizeof(str)))) 347 #define CKF(g,b) {if (0 != (parm.parm_int_state & ((g) & ~(b)))) break; \ 348 parm.parm_int_state |= (b);} 349 #define DELIMS " ,\t\n" 350 struct parm parm; 351 struct intnet *intnetp; 352 char *tok, *tgt, *p; 353 354 355 /* "subnet=x.y.z.u/mask" must be alone on the line */ 356 if (!strncasecmp("subnet=",line,7)) { 357 intnetp = (struct intnet*)malloc(sizeof(*intnetp)); 358 intnetp->intnet_metric = 1; 359 if ((p = strrchr(line,','))) { 360 *p++ = '\0'; 361 intnetp->intnet_metric = (int)strtol(p,&p,0); 362 if (*p != '\0' 363 || intnetp->intnet_metric <= 0 364 || intnetp->intnet_metric >= HOPCNT_INFINITY) 365 return line; 366 } 367 if (!getnet(&line[7], &intnetp->intnet_addr, 368 &intnetp->intnet_mask) 369 || intnetp->intnet_mask == HOST_MASK 370 || intnetp->intnet_addr == RIP_DEFAULT) { 371 free(intnetp); 372 return line; 373 } 374 intnetp->intnet_next = intnets; 375 intnets = intnetp; 376 return 0; 377 } 378 379 bzero(&parm, sizeof(parm)); 380 381 tgt = "null"; 382 for (tok = strtok(line, DELIMS); 383 tok != 0 && tok[0] != '\0'; 384 tgt = 0, tok = strtok(0,DELIMS)) { 385 if (PARSE("if")) { 386 if (parm.parm_name[0] != '\0' 387 || tok[3] == '\0' 388 || strlen(tok) > IFNAMSIZ+3) 389 break; 390 strcpy(parm.parm_name, tok+3); 391 392 } else if (PARSE("passwd")) { 393 if (tok[7] == '\0' 394 || strlen(tok) > RIP_AUTH_PW_LEN+7) 395 break; 396 strcpy(parm.parm_passwd, tok+7); 397 398 } else if (PARS("no_ag")) { 399 parm.parm_int_state |= (IS_NO_AG | IS_NO_SUPER_AG); 400 401 } else if (PARS("no_super_ag")) { 402 parm.parm_int_state |= IS_NO_SUPER_AG; 403 404 } else if (PARS("no_ripv1_in")) { 405 parm.parm_int_state |= IS_NO_RIPV1_IN; 406 407 } else if (PARS("no_ripv2_in")) { 408 parm.parm_int_state |= IS_NO_RIPV2_IN; 409 410 } else if (PARS("ripv2_out")) { 411 if (parm.parm_int_state & IS_NO_RIPV2_OUT) 412 break; 413 parm.parm_int_state |= IS_NO_RIPV1_OUT; 414 415 } else if (PARS("no_rip")) { 416 parm.parm_int_state |= IS_NO_RIP; 417 418 } else if (PARS("no_rdisc")) { 419 CKF((GROUP_IS_SOL|GROUP_IS_ADV), IS_NO_RDISC); 420 421 } else if (PARS("no_solicit")) { 422 CKF(GROUP_IS_SOL, IS_NO_SOL_OUT); 423 424 } else if (PARS("send_solicit")) { 425 CKF(GROUP_IS_SOL, IS_SOL_OUT); 426 427 } else if (PARS("no_rdisc_adv")) { 428 CKF(GROUP_IS_ADV, IS_NO_ADV_OUT); 429 430 } else if (PARS("rdisc_adv")) { 431 CKF(GROUP_IS_ADV, IS_ADV_OUT); 432 433 } else if (PARS("bcast_rdisc")) { 434 parm.parm_int_state |= IS_BCAST_RDISC; 435 436 } else if (PARS("passive")) { 437 CKF((GROUP_IS_SOL|GROUP_IS_ADV), IS_NO_RDISC); 438 parm.parm_int_state |= IS_NO_RIP; 439 440 } else if (PARSE("rdisc_pref")) { 441 if (parm.parm_rdisc_pref != 0 442 || tok[11] == '\0' 443 || (parm.parm_rdisc_pref = (int)strtol(&tok[11], 444 &p,0), 445 *p != '\0')) 446 break; 447 448 } else if (PARS("pm_rdisc")) { 449 parm.parm_int_state |= IS_PM_RDISC; 450 451 } else if (PARSE("rdisc_interval")) { 452 if (parm.parm_rdisc_int != 0 453 || tok[15] == '\0' 454 || (parm.parm_rdisc_int = (int)strtol(&tok[15], 455 &p,0), 456 *p != '\0') 457 || parm.parm_rdisc_int < MinMaxAdvertiseInterval 458 || parm.parm_rdisc_int > MaxMaxAdvertiseInterval) 459 break; 460 461 } else if (PARSE("fake_default")) { 462 if (parm.parm_d_metric != 0 463 || tok[13] == '\0' 464 || (parm.parm_d_metric=(int)strtol(&tok[13],&p,0), 465 *p != '\0') 466 || parm.parm_d_metric > HOPCNT_INFINITY-1) 467 break; 468 469 } else { 470 tgt = tok; 471 break; 472 } 473 } 474 if (tgt != 0) 475 return tgt; 476 477 return check_parms(&parm); 478 #undef DELIMS 479 #undef PARS 480 #undef PARSE 481 } 482 483 484 /* check for duplicate parameter specifications */ 485 char * /* 0 or error message */ 486 check_parms(struct parm *new) 487 { 488 struct parm *parmp; 489 490 491 /* set implicit values 492 */ 493 if (!supplier && supplier_set) 494 new->parm_int_state |= (IS_NO_RIPV1_OUT 495 | IS_NO_RIPV2_OUT 496 | IS_NO_ADV_OUT); 497 if (new->parm_int_state & IS_NO_ADV_IN) 498 new->parm_int_state |= IS_NO_SOL_OUT; 499 500 if ((new->parm_int_state & (IS_NO_RIP | IS_NO_RDISC)) 501 == (IS_NO_RIP | IS_NO_RDISC)) 502 new->parm_int_state |= IS_PASSIVE; 503 504 /* compare with existing sets of parameters 505 */ 506 for (parmp = parms; parmp != 0; parmp = parmp->parm_next) { 507 if (strcmp(new->parm_name, parmp->parm_name)) 508 continue; 509 if (!on_net(htonl(parmp->parm_addr_h), 510 new->parm_addr_h, new->parm_mask) 511 && !on_net(htonl(new->parm_addr_h), 512 parmp->parm_addr_h, parmp->parm_mask)) 513 continue; 514 515 if (strcmp(parmp->parm_passwd, new->parm_passwd) 516 || (0 != (new->parm_int_state & GROUP_IS_SOL) 517 && 0 != (parmp->parm_int_state & GROUP_IS_SOL) 518 && 0 != ((new->parm_int_state ^ parmp->parm_int_state) 519 && GROUP_IS_SOL)) 520 || (0 != (new->parm_int_state & GROUP_IS_ADV) 521 && 0 != (parmp->parm_int_state & GROUP_IS_ADV) 522 && 0 != ((new->parm_int_state ^ parmp->parm_int_state) 523 && GROUP_IS_ADV)) 524 || (new->parm_rdisc_pref != 0 525 && parmp->parm_rdisc_pref != 0 526 && new->parm_rdisc_pref != parmp->parm_rdisc_pref) 527 || (new->parm_rdisc_int != 0 528 && parmp->parm_rdisc_int != 0 529 && new->parm_rdisc_int != parmp->parm_rdisc_int) 530 || (new->parm_d_metric != 0 531 && parmp->parm_d_metric != 0 532 && new->parm_d_metric != parmp->parm_d_metric)) 533 return "duplicate"; 534 } 535 536 parmp = (struct parm*)malloc(sizeof(*parmp)); 537 bcopy(new, parmp, sizeof(*parmp)); 538 parmp->parm_next = parms; 539 parms = parmp; 540 541 return 0; 542 } 543 544 545 /* get a network number as a name or a number, with an optional "/xx" 546 * netmask. 547 */ 548 int /* 0=bad */ 549 getnet(char *name, 550 naddr *addrp, /* host byte order */ 551 naddr *maskp) 552 { 553 int i; 554 struct netent *np; 555 naddr mask; 556 struct in_addr in; 557 char hname[MAXHOSTNAMELEN+1]; 558 char *mname, *p; 559 560 561 /* Detect and separate "1.2.3.4/24" 562 */ 563 if (0 != (mname = rindex(name,'/'))) { 564 i = (int)(mname - name); 565 if (i > sizeof(hname)-1) /* name too long */ 566 return 0; 567 bcopy(name, hname, i); 568 hname[i] = '\0'; 569 mname++; 570 name = hname; 571 } 572 573 np = getnetbyname(name); 574 if (np != 0) { 575 in.s_addr = (naddr)np->n_net; 576 } else if (inet_aton(name, &in) == 1) { 577 HTONL(in.s_addr); 578 } else { 579 return 0; 580 } 581 582 if (mname == 0) { 583 /* we cannot use the interfaces here because we have not 584 * looked at them yet. 585 */ 586 mask = std_mask(in.s_addr); 587 if ((~mask & ntohl(in.s_addr)) != 0) 588 mask = HOST_MASK; 589 } else { 590 mask = (naddr)strtoul(mname, &p, 0); 591 if (*p != '\0' || mask > 32) 592 return 0; 593 mask = HOST_MASK << (32-mask); 594 } 595 if (mask != 0 && in.s_addr == RIP_DEFAULT) 596 return 0; 597 if ((~mask & ntohl(in.s_addr)) != 0) 598 return 0; 599 600 *addrp = in.s_addr; 601 *maskp = mask; 602 return 1; 603 } 604 605 606 int /* 0=bad */ 607 gethost(char *name, 608 naddr *addrp) 609 { 610 struct hostent *hp; 611 struct in_addr in; 612 613 614 /* Try for a number first, even in IRIX where gethostbyname() 615 * is smart. This avoids hitting the name server which 616 * might be sick because routing is. 617 */ 618 if (inet_aton(name, &in) == 1) { 619 *addrp = in.s_addr; 620 return 1; 621 } 622 623 hp = gethostbyname(name); 624 if (hp) { 625 bcopy(hp->h_addr, addrp, sizeof(*addrp)); 626 return 1; 627 } 628 629 return 0; 630 } 631