1: /* 2: * Copyright (c) 1983 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #if !defined(lint) && defined(DOSCCS) 8: static char sccsid[] = "@(#)startup.c 5.7.1 (2.11BSD) 1996/11/19"; 9: #endif not lint 10: 11: /* 12: * Routing Table Management Daemon 13: */ 14: #include "defs.h" 15: #include <sys/ioctl.h> 16: #include <net/if.h> 17: #include <syslog.h> 18: 19: struct interface *ifnet; 20: int lookforinterfaces = 1; 21: int externalinterfaces = 0; /* # of remote and local interfaces */ 22: 23: /* 24: * Find the network interfaces which have configured themselves. 25: * If the interface is present but not yet up (for example an 26: * ARPANET IMP), set the lookforinterfaces flag so we'll 27: * come back later and look again. 28: */ 29: ifinit() 30: { 31: struct interface ifs, *ifp; 32: int s, n; 33: char buf[BUFSIZ]; 34: struct ifconf ifc; 35: struct ifreq ifreq, *ifr; 36: struct sockaddr_in *sin; 37: u_long i; 38: 39: if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 40: syslog(LOG_ERR, "socket: %m"); 41: exit(1); 42: } 43: ifc.ifc_len = sizeof (buf); 44: ifc.ifc_buf = buf; 45: if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { 46: syslog(LOG_ERR, "ioctl (get interface configuration)"); 47: close(s); 48: return (0); 49: } 50: ifr = ifc.ifc_req; 51: lookforinterfaces = 0; 52: for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) { 53: bzero((char *)&ifs, sizeof(ifs)); 54: ifs.int_addr = ifr->ifr_addr; 55: ifreq = *ifr; 56: if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) { 57: syslog(LOG_ERR, "ioctl (get interface flags)"); 58: continue; 59: } 60: ifs.int_flags = ifreq.ifr_flags | IFF_INTERFACE; 61: /* no one cares about software loopback interfaces */ 62: if (ifs.int_flags & IFF_LOOPBACK) 63: continue; 64: if ((ifs.int_flags & IFF_UP) == 0 || 65: ifr->ifr_addr.sa_family == AF_UNSPEC) { 66: lookforinterfaces = 1; 67: continue; 68: } 69: /* already known to us? */ 70: if (if_ifwithaddr(&ifs.int_addr)) 71: continue; 72: /* argh, this'll have to change sometime */ 73: if (ifs.int_addr.sa_family != AF_INET) 74: continue; 75: if (ifs.int_flags & IFF_POINTOPOINT) { 76: if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) { 77: syslog(LOG_ERR, "ioctl (get dstaddr)"); 78: continue; 79: } 80: ifs.int_dstaddr = ifreq.ifr_dstaddr; 81: } 82: if (ifs.int_flags & IFF_BROADCAST) { 83: if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { 84: syslog(LOG_ERR, "ioctl (get broadaddr)"); 85: continue; 86: } 87: ifs.int_broadaddr = ifreq.ifr_broadaddr; 88: } 89: if (ioctl(s, SIOCGIFMETRIC, (char *)&ifreq) < 0) 90: syslog(LOG_ERR, "ioctl (get metric)"); 91: else 92: ifs.int_metric = ifreq.ifr_metric; 93: if (ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) < 0) { 94: syslog(LOG_ERR, "ioctl (get netmask)"); 95: continue; 96: } 97: sin = (struct sockaddr_in *)&ifreq.ifr_addr; 98: ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr); 99: sin = (struct sockaddr_in *)&ifs.int_addr; 100: i = ntohl(sin->sin_addr.s_addr); 101: if (IN_CLASSA(i)) 102: ifs.int_netmask = IN_CLASSA_NET; 103: else if (IN_CLASSB(i)) 104: ifs.int_netmask = IN_CLASSB_NET; 105: else 106: ifs.int_netmask = IN_CLASSC_NET; 107: ifs.int_net = i & ifs.int_netmask; 108: ifs.int_subnet = i & ifs.int_subnetmask; 109: if (ifs.int_subnetmask != ifs.int_netmask) 110: ifs.int_flags |= IFF_SUBNET; 111: ifp = (struct interface *)malloc(sizeof (struct interface)); 112: if (ifp == 0) { 113: printf("routed: out of memory\n"); 114: break; 115: } 116: *ifp = ifs; 117: /* 118: * Count the # of directly connected networks 119: * and point to point links which aren't looped 120: * back to ourself. This is used below to 121: * decide if we should be a routing ``supplier''. 122: */ 123: if ((ifs.int_flags & IFF_POINTOPOINT) == 0 || 124: if_ifwithaddr(&ifs.int_dstaddr) == 0) 125: externalinterfaces++; 126: /* 127: * If we have a point-to-point link, we want to act 128: * as a supplier even if it's our only interface, 129: * as that's the only way our peer on the other end 130: * can tell that the link is up. 131: */ 132: if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0) 133: supplier = 1; 134: ifp->int_name = malloc(strlen(ifr->ifr_name) + 1); 135: if (ifp->int_name == 0) { 136: fprintf(stderr, "routed: ifinit: out of memory\n"); 137: goto bad; /* ??? */ 138: } 139: strcpy(ifp->int_name, ifr->ifr_name); 140: ifp->int_next = ifnet; 141: ifnet = ifp; 142: traceinit(ifp); 143: addrouteforif(ifp); 144: } 145: if (externalinterfaces > 1 && supplier < 0) 146: supplier = 1; 147: close(s); 148: return; 149: bad: 150: sleep(60); 151: close(kmem), close(s); 152: execv("/sbin/routed", argv0); 153: _exit(0177); 154: } 155: 156: /* 157: * Add route for interface if not currently installed. 158: * Create route to other end if a point-to-point link, 159: * otherwise a route to this (sub)network. 160: * INTERNET SPECIFIC. 161: */ 162: addrouteforif(ifp) 163: struct interface *ifp; 164: { 165: struct sockaddr_in net; 166: struct sockaddr *dst; 167: struct rt_entry *rt; 168: 169: if (ifp->int_flags & IFF_POINTOPOINT) 170: dst = &ifp->int_dstaddr; 171: else { 172: bzero((char *)&net, sizeof (net)); 173: net.sin_family = AF_INET; 174: net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY); 175: dst = (struct sockaddr *)&net; 176: } 177: rt = rtfind(dst); 178: if (rt && 179: (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE) 180: return; 181: if (rt) 182: rtdelete(rt); 183: /* 184: * If interface on subnetted network, 185: * install route to network as well. 186: * This is meant for external viewers. 187: */ 188: if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) { 189: net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); 190: rt = rtfind(dst); 191: if (rt == 0) 192: rtadd(dst, &ifp->int_addr, ifp->int_metric, 193: ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) | 194: RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET)); 195: net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY); 196: } 197: if (ifp->int_transitions++ > 0) 198: syslog(LOG_ERR, "re-installing interface %s", ifp->int_name); 199: rtadd(dst, &ifp->int_addr, ifp->int_metric, 200: ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE|IFF_SUBNET)); 201: 202: } 203: 204: /* 205: * As a concession to the ARPANET we read a list of gateways 206: * from /etc/gateways and add them to our tables. This file 207: * exists at each ARPANET gateway and indicates a set of ``remote'' 208: * gateways (i.e. a gateway which we can't immediately determine 209: * if it's present or not as we can do for those directly connected 210: * at the hardware level). If a gateway is marked ``passive'' 211: * in the file, then we assume it doesn't have a routing process 212: * of our design and simply assume it's always present. Those 213: * not marked passive are treated as if they were directly 214: * connected -- they're added into the interface list so we'll 215: * send them routing updates. 216: */ 217: gwkludge() 218: { 219: struct sockaddr_in dst, gate; 220: FILE *fp; 221: char *type, *dname, *gname, *qual, buf[BUFSIZ]; 222: struct interface *ifp; 223: int metric, n; 224: struct rt_entry route; 225: 226: fp = fopen("/etc/gateways", "r"); 227: if (fp == NULL) 228: return; 229: qual = buf; 230: dname = buf + 64; 231: gname = buf + ((BUFSIZ - 64) / 3); 232: type = buf + (((BUFSIZ - 64) * 2) / 3); 233: bzero((char *)&dst, sizeof (dst)); 234: bzero((char *)&gate, sizeof (gate)); 235: bzero((char *)&route, sizeof(route)); 236: /* format: {net | host} XX gateway XX metric DD [passive]\n */ 237: #define readentry(fp) \ 238: fscanf((fp), "%s %s gateway %s metric %d %s\n", \ 239: type, dname, gname, &metric, qual) 240: for (;;) { 241: if ((n = readentry(fp)) == EOF) 242: break; 243: if (!getnetorhostname(type, dname, &dst)) 244: continue; 245: if (!gethostnameornumber(gname, &gate)) 246: continue; 247: if (strcmp(qual, "passive") == 0) { 248: /* 249: * Passive entries aren't placed in our tables, 250: * only the kernel's, so we don't copy all of the 251: * external routing information within a net. 252: * Internal machines should use the default 253: * route to a suitable gateway (like us). 254: */ 255: route.rt_dst = *(struct sockaddr *) &dst; 256: route.rt_router = *(struct sockaddr *) &gate; 257: route.rt_flags = RTF_UP; 258: if (strcmp(type, "host") == 0) 259: route.rt_flags |= RTF_HOST; 260: if (metric) 261: route.rt_flags |= RTF_GATEWAY; 262: (void) ioctl(s, SIOCADDRT, (char *)&route.rt_rt); 263: continue; 264: } 265: if (strcmp(qual, "external") == 0) { 266: /* 267: * Entries marked external are handled 268: * by other means, e.g. EGP, 269: * and are placed in our tables only 270: * to prevent overriding them 271: * with something else. 272: */ 273: rtadd(&dst, &gate, metric, RTS_EXTERNAL|RTS_PASSIVE); 274: continue; 275: } 276: /* assume no duplicate entries */ 277: externalinterfaces++; 278: ifp = (struct interface *)malloc(sizeof (*ifp)); 279: bzero((char *)ifp, sizeof (*ifp)); 280: ifp->int_flags = IFF_REMOTE; 281: /* can't identify broadcast capability */ 282: ifp->int_net = inet_netof(dst.sin_addr); 283: if (strcmp(type, "host") == 0) { 284: ifp->int_flags |= IFF_POINTOPOINT; 285: ifp->int_dstaddr = *((struct sockaddr *)&dst); 286: } 287: ifp->int_addr = *((struct sockaddr *)&gate); 288: ifp->int_metric = metric; 289: ifp->int_next = ifnet; 290: ifnet = ifp; 291: addrouteforif(ifp); 292: } 293: fclose(fp); 294: } 295: 296: getnetorhostname(type, name, sin) 297: char *type, *name; 298: struct sockaddr_in *sin; 299: { 300: 301: if (strcmp(type, "net") == 0) { 302: struct netent *np = getnetbyname(name); 303: u_long n; 304: 305: if (np == 0) 306: n = inet_network(name); 307: else { 308: if (np->n_addrtype != AF_INET) 309: return (0); 310: n = np->n_net; 311: /* 312: * getnetbyname returns right-adjusted value. 313: */ 314: if (n < 128) 315: n <<= IN_CLASSA_NSHIFT; 316: else if (n < 65536) 317: n <<= IN_CLASSB_NSHIFT; 318: else 319: n <<= IN_CLASSC_NSHIFT; 320: } 321: sin->sin_family = AF_INET; 322: sin->sin_addr = inet_makeaddr(n, INADDR_ANY); 323: return (1); 324: } 325: if (strcmp(type, "host") == 0) { 326: struct hostent *hp = gethostbyname(name); 327: 328: if (hp == 0) 329: sin->sin_addr.s_addr = inet_addr(name); 330: else { 331: if (hp->h_addrtype != AF_INET) 332: return (0); 333: bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); 334: } 335: sin->sin_family = AF_INET; 336: return (1); 337: } 338: return (0); 339: } 340: 341: gethostnameornumber(name, sin) 342: char *name; 343: struct sockaddr_in *sin; 344: { 345: struct hostent *hp; 346: 347: hp = gethostbyname(name); 348: if (hp) { 349: bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); 350: sin->sin_family = hp->h_addrtype; 351: return (1); 352: } 353: sin->sin_addr.s_addr = inet_addr(name); 354: sin->sin_family = AF_INET; 355: return (sin->sin_addr.s_addr != -1); 356: }