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