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