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