1 /* 2 * Copyright (c) 1983, 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)startup.c 5.22 (Berkeley) 08/14/92"; 10 #endif /* not lint */ 11 12 /* 13 * Routing Table Management Daemon 14 */ 15 #include "defs.h" 16 #include <sys/ioctl.h> 17 #include <sys/kinfo.h> 18 #include <net/if.h> 19 #include <net/if_dl.h> 20 #include <syslog.h> 21 #include <stdlib.h> 22 #include "pathnames.h" 23 24 struct interface *ifnet; 25 struct interface **ifnext = &ifnet; 26 int lookforinterfaces = 1; 27 int externalinterfaces = 0; /* # of remote and local interfaces */ 28 int foundloopback; /* valid flag for loopaddr */ 29 struct sockaddr loopaddr; /* our address on loopback */ 30 31 32 void 33 quit(s) 34 char *s; 35 { 36 extern int errno; 37 int sverrno = errno; 38 39 (void) fprintf(stderr, "route: "); 40 if (s) 41 (void) fprintf(stderr, "%s: ", s); 42 (void) fprintf(stderr, "%s\n", strerror(sverrno)); 43 exit(1); 44 /* NOTREACHED */ 45 } 46 47 struct rt_addrinfo info; 48 /* Sleazy use of local variables throughout file, warning!!!! */ 49 #define netmask info.rti_info[RTAX_NETMASK] 50 #define ifaaddr info.rti_info[RTAX_IFA] 51 #define brdaddr info.rti_info[RTAX_BRD] 52 53 #define ROUNDUP(a) \ 54 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 55 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 56 57 void 58 rt_xaddrs(cp, cplim, rtinfo) 59 register caddr_t cp, cplim; 60 register struct rt_addrinfo *rtinfo; 61 { 62 register struct sockaddr *sa; 63 register int i; 64 65 bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 66 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 67 if ((rtinfo->rti_addrs & (1 << i)) == 0) 68 continue; 69 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 70 ADVANCE(cp, sa); 71 } 72 } 73 74 /* 75 * Find the network interfaces which have configured themselves. 76 * If the interface is present but not yet up (for example an 77 * ARPANET IMP), set the lookforinterfaces flag so we'll 78 * come back later and look again. 79 */ 80 ifinit() 81 { 82 struct interface ifs, *ifp; 83 int needed, rlen, no_ipaddr = 0, flags = 0; 84 char *buf, *cplim, *cp; 85 register struct if_msghdr *ifm; 86 register struct ifa_msghdr *ifam; 87 struct sockaddr_dl *sdl; 88 struct sockaddr_in *sin; 89 u_long i; 90 91 if ((needed = getkerninfo(KINFO_RT_IFLIST, 0, 0, 0)) < 0) 92 quit("route-getkerninfo-estimate"); 93 if ((buf = malloc(needed)) == NULL) 94 quit("malloc"); 95 if ((rlen = getkerninfo(KINFO_RT_IFLIST, buf, &needed, 0)) < 0) 96 quit("actual retrieval of interface table"); 97 lookforinterfaces = 0; 98 cplim = buf + rlen; 99 for (cp = buf; cp < cplim; cp += ifm->ifm_msglen) { 100 ifm = (struct if_msghdr *)cp; 101 if (ifm->ifm_type == RTM_IFINFO) { 102 bzero(&ifs, sizeof(ifs)); 103 ifs.int_flags = flags = (0xffff & ifm->ifm_flags) | IFF_INTERFACE; 104 if ((flags & IFF_UP) == 0 || no_ipaddr) 105 lookforinterfaces = 1; 106 sdl = (struct sockaddr_dl *) (ifm + 1); 107 sdl->sdl_data[sdl->sdl_nlen] = 0; 108 no_ipaddr = 1; 109 continue; 110 } 111 if (ifm->ifm_type != RTM_NEWADDR) 112 quit("ifinit: out of sync"); 113 if ((flags & IFF_UP) == 0) 114 continue; 115 ifam = (struct ifa_msghdr *)ifm; 116 info.rti_addrs = ifam->ifam_addrs; 117 rt_xaddrs((char *)(ifam + 1), cp + ifam->ifam_msglen, &info); 118 if (ifaaddr == 0) { 119 syslog(LOG_ERR, "%s: (get addr)", sdl->sdl_data); 120 continue; 121 } 122 ifs.int_addr = *ifaaddr; 123 if (ifs.int_addr.sa_family != AF_INET) 124 continue; 125 no_ipaddr = 0; 126 if (ifs.int_flags & IFF_POINTOPOINT) { 127 if (brdaddr == 0) { 128 syslog(LOG_ERR, "%s: (get dstaddr)", 129 sdl->sdl_data); 130 continue; 131 } 132 if (brdaddr->sa_family == AF_UNSPEC) { 133 lookforinterfaces = 1; 134 continue; 135 } 136 ifs.int_dstaddr = *brdaddr; 137 } 138 /* 139 * already known to us? 140 * This allows multiple point-to-point links 141 * to share a source address (possibly with one 142 * other link), but assumes that there will not be 143 * multiple links with the same destination address. 144 */ 145 if (ifs.int_flags & IFF_POINTOPOINT) { 146 if (if_ifwithdstaddr(&ifs.int_dstaddr)) 147 continue; 148 } else if (if_ifwithaddr(&ifs.int_addr)) 149 continue; 150 if (ifs.int_flags & IFF_LOOPBACK) { 151 ifs.int_flags |= IFF_PASSIVE; 152 foundloopback = 1; 153 loopaddr = ifs.int_addr; 154 for (ifp = ifnet; ifp; ifp = ifp->int_next) 155 if (ifp->int_flags & IFF_POINTOPOINT) 156 add_ptopt_localrt(ifp); 157 } 158 if (ifs.int_flags & IFF_BROADCAST) { 159 if (brdaddr == 0) { 160 syslog(LOG_ERR, "%s: (get broadaddr)", 161 sdl->sdl_data); 162 continue; 163 } 164 ifs.int_dstaddr = *brdaddr; 165 } 166 /* 167 * Use a minimum metric of one; 168 * treat the interface metric (default 0) 169 * as an increment to the hop count of one. 170 */ 171 ifs.int_metric = ifam->ifam_metric + 1; 172 if (netmask == 0) { 173 syslog(LOG_ERR, "%s: (get netmask)", 174 sdl->sdl_data); 175 continue; 176 } 177 sin = (struct sockaddr_in *)netmask; 178 ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr); 179 sin = (struct sockaddr_in *)&ifs.int_addr; 180 i = ntohl(sin->sin_addr.s_addr); 181 if (IN_CLASSA(i)) 182 ifs.int_netmask = IN_CLASSA_NET; 183 else if (IN_CLASSB(i)) 184 ifs.int_netmask = IN_CLASSB_NET; 185 else 186 ifs.int_netmask = IN_CLASSC_NET; 187 ifs.int_net = i & ifs.int_netmask; 188 ifs.int_subnet = i & ifs.int_subnetmask; 189 if (ifs.int_subnetmask != ifs.int_netmask) 190 ifs.int_flags |= IFF_SUBNET; 191 ifp = (struct interface *) 192 malloc(sdl->sdl_nlen + 1 + sizeof(ifs)); 193 if (ifp == 0) { 194 printf("routed: out of memory\n"); 195 lookforinterfaces = 1; 196 break; 197 } 198 *ifp = ifs; 199 /* 200 * Count the # of directly connected networks 201 * and point to point links which aren't looped 202 * back to ourself. This is used below to 203 * decide if we should be a routing ``supplier''. 204 */ 205 if ((ifs.int_flags & IFF_LOOPBACK) == 0 && 206 ((ifs.int_flags & IFF_POINTOPOINT) == 0 || 207 if_ifwithaddr(&ifs.int_dstaddr) == 0)) 208 externalinterfaces++; 209 /* 210 * If we have a point-to-point link, we want to act 211 * as a supplier even if it's our only interface, 212 * as that's the only way our peer on the other end 213 * can tell that the link is up. 214 */ 215 if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0) 216 supplier = 1; 217 ifp->int_name = (char *)(ifp + 1); 218 strcpy(ifp->int_name, sdl->sdl_data); 219 *ifnext = ifp; 220 ifnext = &ifp->int_next; 221 traceinit(ifp); 222 addrouteforif(ifp); 223 } 224 if (externalinterfaces > 1 && supplier < 0) 225 supplier = 1; 226 free(buf); 227 } 228 229 /* 230 * Add route for interface if not currently installed. 231 * Create route to other end if a point-to-point link, 232 * otherwise a route to this (sub)network. 233 * INTERNET SPECIFIC. 234 */ 235 addrouteforif(ifp) 236 register struct interface *ifp; 237 { 238 struct sockaddr_in net; 239 struct sockaddr *dst; 240 int state; 241 register struct rt_entry *rt; 242 243 if (ifp->int_flags & IFF_POINTOPOINT) 244 dst = &ifp->int_dstaddr; 245 else { 246 bzero((char *)&net, sizeof (net)); 247 net.sin_family = AF_INET; 248 net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY); 249 dst = (struct sockaddr *)&net; 250 } 251 rt = rtfind(dst); 252 if (rt && 253 (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE) 254 return; 255 if (rt) 256 rtdelete(rt); 257 /* 258 * If interface on subnetted network, 259 * install route to network as well. 260 * This is meant for external viewers. 261 */ 262 if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) { 263 struct in_addr subnet; 264 265 subnet = net.sin_addr; 266 net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); 267 rt = rtfind(dst); 268 if (rt == 0) 269 rtadd(dst, &ifp->int_addr, ifp->int_metric, 270 ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) | 271 RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET)); 272 else if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET)) == 273 (RTS_INTERNAL|RTS_SUBNET) && 274 ifp->int_metric < rt->rt_metric) 275 rtchange(rt, &rt->rt_router, ifp->int_metric); 276 net.sin_addr = subnet; 277 } 278 if (ifp->int_transitions++ > 0) 279 syslog(LOG_ERR, "re-installing interface %s", ifp->int_name); 280 state = ifp->int_flags & 281 (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET); 282 if (ifp->int_flags & IFF_POINTOPOINT && 283 (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr) & 284 ifp->int_netmask) != ifp->int_net) 285 state &= ~RTS_SUBNET; 286 if (ifp->int_flags & IFF_LOOPBACK) 287 state |= RTS_EXTERNAL; 288 rtadd(dst, &ifp->int_addr, ifp->int_metric, state); 289 if (ifp->int_flags & IFF_POINTOPOINT && foundloopback) 290 add_ptopt_localrt(ifp); 291 } 292 293 /* 294 * Add route to local end of point-to-point using loopback. 295 * If a route to this network is being sent to neighbors on other nets, 296 * mark this route as subnet so we don't have to propagate it too. 297 */ 298 add_ptopt_localrt(ifp) 299 register struct interface *ifp; 300 { 301 struct rt_entry *rt; 302 struct sockaddr *dst; 303 struct sockaddr_in net; 304 int state; 305 306 state = RTS_INTERFACE | RTS_PASSIVE; 307 308 /* look for route to logical network */ 309 bzero((char *)&net, sizeof (net)); 310 net.sin_family = AF_INET; 311 net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); 312 dst = (struct sockaddr *)&net; 313 rt = rtfind(dst); 314 if (rt && rt->rt_state & RTS_INTERNAL) 315 state |= RTS_SUBNET; 316 317 dst = &ifp->int_addr; 318 if (rt = rtfind(dst)) { 319 if (rt && rt->rt_state & RTS_INTERFACE) 320 return; 321 rtdelete(rt); 322 } 323 rtadd(dst, &loopaddr, 1, state); 324 } 325 326 /* 327 * As a concession to the ARPANET we read a list of gateways 328 * from /etc/gateways and add them to our tables. This file 329 * exists at each ARPANET gateway and indicates a set of ``remote'' 330 * gateways (i.e. a gateway which we can't immediately determine 331 * if it's present or not as we can do for those directly connected 332 * at the hardware level). If a gateway is marked ``passive'' 333 * in the file, then we assume it doesn't have a routing process 334 * of our design and simply assume it's always present. Those 335 * not marked passive are treated as if they were directly 336 * connected -- they're added into the interface list so we'll 337 * send them routing updates. 338 * 339 * PASSIVE ENTRIES AREN'T NEEDED OR USED ON GATEWAYS RUNNING EGP. 340 */ 341 gwkludge() 342 { 343 struct sockaddr_in dst, gate; 344 FILE *fp; 345 char *type, *dname, *gname, *qual, buf[BUFSIZ]; 346 struct interface *ifp; 347 int metric, n; 348 struct rt_entry route; 349 350 fp = fopen(_PATH_GATEWAYS, "r"); 351 if (fp == NULL) 352 return; 353 qual = buf; 354 dname = buf + 64; 355 gname = buf + ((BUFSIZ - 64) / 3); 356 type = buf + (((BUFSIZ - 64) * 2) / 3); 357 bzero((char *)&dst, sizeof (dst)); 358 bzero((char *)&gate, sizeof (gate)); 359 bzero((char *)&route, sizeof(route)); 360 /* format: {net | host} XX gateway XX metric DD [passive | external]\n */ 361 #define readentry(fp) \ 362 fscanf((fp), "%s %s gateway %s metric %d %s\n", \ 363 type, dname, gname, &metric, qual) 364 for (;;) { 365 if ((n = readentry(fp)) == EOF) 366 break; 367 if (!getnetorhostname(type, dname, &dst)) 368 continue; 369 if (!gethostnameornumber(gname, &gate)) 370 continue; 371 if (metric == 0) /* XXX */ 372 metric = 1; 373 if (strcmp(qual, "passive") == 0) { 374 /* 375 * Passive entries aren't placed in our tables, 376 * only the kernel's, so we don't copy all of the 377 * external routing information within a net. 378 * Internal machines should use the default 379 * route to a suitable gateway (like us). 380 */ 381 route.rt_dst = *(struct sockaddr *) &dst; 382 route.rt_router = *(struct sockaddr *) &gate; 383 route.rt_flags = RTF_UP; 384 if (strcmp(type, "host") == 0) 385 route.rt_flags |= RTF_HOST; 386 if (metric) 387 route.rt_flags |= RTF_GATEWAY; 388 (void) rtioctl(ADD, &route.rt_rt); 389 continue; 390 } 391 if (strcmp(qual, "external") == 0) { 392 /* 393 * Entries marked external are handled 394 * by other means, e.g. EGP, 395 * and are placed in our tables only 396 * to prevent overriding them 397 * with something else. 398 */ 399 rtadd(&dst, &gate, metric, RTS_EXTERNAL|RTS_PASSIVE); 400 continue; 401 } 402 /* assume no duplicate entries */ 403 externalinterfaces++; 404 ifp = (struct interface *)malloc(sizeof (*ifp)); 405 bzero((char *)ifp, sizeof (*ifp)); 406 ifp->int_flags = IFF_REMOTE; 407 /* can't identify broadcast capability */ 408 ifp->int_net = inet_netof(dst.sin_addr); 409 if (strcmp(type, "host") == 0) { 410 ifp->int_flags |= IFF_POINTOPOINT; 411 ifp->int_dstaddr = *((struct sockaddr *)&dst); 412 } 413 ifp->int_addr = *((struct sockaddr *)&gate); 414 ifp->int_metric = metric; 415 ifp->int_next = ifnet; 416 ifnet = ifp; 417 addrouteforif(ifp); 418 } 419 fclose(fp); 420 } 421 422 getnetorhostname(type, name, sin) 423 char *type, *name; 424 struct sockaddr_in *sin; 425 { 426 427 if (strcmp(type, "net") == 0) { 428 struct netent *np = getnetbyname(name); 429 int n; 430 431 if (np == 0) 432 n = inet_network(name); 433 else { 434 if (np->n_addrtype != AF_INET) 435 return (0); 436 n = np->n_net; 437 /* 438 * getnetbyname returns right-adjusted value. 439 */ 440 if (n < 128) 441 n <<= IN_CLASSA_NSHIFT; 442 else if (n < 65536) 443 n <<= IN_CLASSB_NSHIFT; 444 else 445 n <<= IN_CLASSC_NSHIFT; 446 } 447 sin->sin_family = AF_INET; 448 sin->sin_addr = inet_makeaddr(n, INADDR_ANY); 449 return (1); 450 } 451 if (strcmp(type, "host") == 0) { 452 struct hostent *hp = gethostbyname(name); 453 454 if (hp == 0) 455 sin->sin_addr.s_addr = inet_addr(name); 456 else { 457 if (hp->h_addrtype != AF_INET) 458 return (0); 459 bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); 460 } 461 sin->sin_family = AF_INET; 462 return (1); 463 } 464 return (0); 465 } 466 467 gethostnameornumber(name, sin) 468 char *name; 469 struct sockaddr_in *sin; 470 { 471 struct hostent *hp; 472 473 hp = gethostbyname(name); 474 if (hp) { 475 bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); 476 sin->sin_family = hp->h_addrtype; 477 return (1); 478 } 479 sin->sin_addr.s_addr = inet_addr(name); 480 sin->sin_family = AF_INET; 481 return (sin->sin_addr.s_addr != -1); 482 } 483