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: #ifndef lint 8: static char sccsid[] = "@(#)startup.c 5.7 (Berkeley) 6/3/86"; 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("/etc/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: int state, metric; 168: struct rt_entry *rt; 169: 170: if (ifp->int_flags & IFF_POINTOPOINT) 171: dst = &ifp->int_dstaddr; 172: else { 173: bzero((char *)&net, sizeof (net)); 174: net.sin_family = AF_INET; 175: net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY); 176: dst = (struct sockaddr *)&net; 177: } 178: rt = rtfind(dst); 179: if (rt && 180: (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE) 181: return; 182: if (rt) 183: rtdelete(rt); 184: /* 185: * If interface on subnetted network, 186: * install route to network as well. 187: * This is meant for external viewers. 188: */ 189: if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) { 190: net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); 191: rt = rtfind(dst); 192: if (rt == 0) 193: rtadd(dst, &ifp->int_addr, ifp->int_metric, 194: ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) | 195: RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET)); 196: net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY); 197: } 198: if (ifp->int_transitions++ > 0) 199: syslog(LOG_ERR, "re-installing interface %s", ifp->int_name); 200: rtadd(dst, &ifp->int_addr, ifp->int_metric, 201: ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE|IFF_SUBNET)); 202: 203: } 204: 205: /* 206: * As a concession to the ARPANET we read a list of gateways 207: * from /etc/gateways and add them to our tables. This file 208: * exists at each ARPANET gateway and indicates a set of ``remote'' 209: * gateways (i.e. a gateway which we can't immediately determine 210: * if it's present or not as we can do for those directly connected 211: * at the hardware level). If a gateway is marked ``passive'' 212: * in the file, then we assume it doesn't have a routing process 213: * of our design and simply assume it's always present. Those 214: * not marked passive are treated as if they were directly 215: * connected -- they're added into the interface list so we'll 216: * send them routing updates. 217: */ 218: gwkludge() 219: { 220: struct sockaddr_in dst, gate; 221: FILE *fp; 222: char *type, *dname, *gname, *qual, buf[BUFSIZ]; 223: struct interface *ifp; 224: int metric, n; 225: struct rt_entry route; 226: 227: fp = fopen("/etc/gateways", "r"); 228: if (fp == NULL) 229: return; 230: qual = buf; 231: dname = buf + 64; 232: gname = buf + ((BUFSIZ - 64) / 3); 233: type = buf + (((BUFSIZ - 64) * 2) / 3); 234: bzero((char *)&dst, sizeof (dst)); 235: bzero((char *)&gate, sizeof (gate)); 236: bzero((char *)&route, sizeof(route)); 237: /* format: {net | host} XX gateway XX metric DD [passive]\n */ 238: #define readentry(fp) \ 239: fscanf((fp), "%s %s gateway %s metric %d %s\n", \ 240: type, dname, gname, &metric, qual) 241: for (;;) { 242: if ((n = readentry(fp)) == EOF) 243: break; 244: if (!getnetorhostname(type, dname, &dst)) 245: continue; 246: if (!gethostnameornumber(gname, &gate)) 247: continue; 248: if (strcmp(qual, "passive") == 0) { 249: /* 250: * Passive entries aren't placed in our tables, 251: * only the kernel's, so we don't copy all of the 252: * external routing information within a net. 253: * Internal machines should use the default 254: * route to a suitable gateway (like us). 255: */ 256: route.rt_dst = *(struct sockaddr *) &dst; 257: route.rt_router = *(struct sockaddr *) &gate; 258: route.rt_flags = RTF_UP; 259: if (strcmp(type, "host") == 0) 260: route.rt_flags |= RTF_HOST; 261: if (metric) 262: route.rt_flags |= RTF_GATEWAY; 263: (void) ioctl(s, SIOCADDRT, (char *)&route.rt_rt); 264: continue; 265: } 266: if (strcmp(qual, "external") == 0) { 267: /* 268: * Entries marked external are handled 269: * by other means, e.g. EGP, 270: * and are placed in our tables only 271: * to prevent overriding them 272: * with something else. 273: */ 274: rtadd(&dst, &gate, metric, RTS_EXTERNAL|RTS_PASSIVE); 275: continue; 276: } 277: /* assume no duplicate entries */ 278: externalinterfaces++; 279: ifp = (struct interface *)malloc(sizeof (*ifp)); 280: bzero((char *)ifp, sizeof (*ifp)); 281: ifp->int_flags = IFF_REMOTE; 282: /* can't identify broadcast capability */ 283: ifp->int_net = inet_netof(dst.sin_addr); 284: if (strcmp(type, "host") == 0) { 285: ifp->int_flags |= IFF_POINTOPOINT; 286: ifp->int_dstaddr = *((struct sockaddr *)&dst); 287: } 288: ifp->int_addr = *((struct sockaddr *)&gate); 289: ifp->int_metric = metric; 290: ifp->int_next = ifnet; 291: ifnet = ifp; 292: addrouteforif(ifp); 293: } 294: fclose(fp); 295: } 296: 297: getnetorhostname(type, name, sin) 298: char *type, *name; 299: struct sockaddr_in *sin; 300: { 301: 302: if (strcmp(type, "net") == 0) { 303: struct netent *np = getnetbyname(name); 304: int n; 305: 306: if (np == 0) 307: n = inet_network(name); 308: else { 309: if (np->n_addrtype != AF_INET) 310: return (0); 311: n = np->n_net; 312: /* 313: * getnetbyname returns right-adjusted value. 314: */ 315: if (n < 128) 316: n <<= IN_CLASSA_NSHIFT; 317: else if (n < 65536) 318: n <<= IN_CLASSB_NSHIFT; 319: else 320: n <<= IN_CLASSC_NSHIFT; 321: } 322: sin->sin_family = AF_INET; 323: sin->sin_addr = inet_makeaddr(n, INADDR_ANY); 324: return (1); 325: } 326: if (strcmp(type, "host") == 0) { 327: struct hostent *hp = gethostbyname(name); 328: 329: if (hp == 0) 330: sin->sin_addr.s_addr = inet_addr(name); 331: else { 332: if (hp->h_addrtype != AF_INET) 333: return (0); 334: bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); 335: } 336: sin->sin_family = AF_INET; 337: return (1); 338: } 339: return (0); 340: } 341: 342: gethostnameornumber(name, sin) 343: char *name; 344: struct sockaddr_in *sin; 345: { 346: struct hostent *hp; 347: 348: hp = gethostbyname(name); 349: if (hp) { 350: bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); 351: sin->sin_family = hp->h_addrtype; 352: return (1); 353: } 354: sin->sin_addr.s_addr = inet_addr(name); 355: sin->sin_family = AF_INET; 356: return (sin->sin_addr.s_addr != -1); 357: }