121998Sdist /* 234568Skarels * Copyright (c) 1983, 1988 Regents of the University of California. 333489Sbostic * All rights reserved. 433489Sbostic * 5*42712Sbostic * %sccs.include.redist.c% 621998Sdist */ 721998Sdist 89019Ssam #ifndef lint 9*42712Sbostic static char sccsid[] = "@(#)startup.c 5.18 (Berkeley) 06/01/90"; 1033489Sbostic #endif /* not lint */ 119019Ssam 129019Ssam /* 139019Ssam * Routing Table Management Daemon 149019Ssam */ 1510245Ssam #include "defs.h" 1616327Skarels #include <sys/ioctl.h> 179019Ssam #include <net/if.h> 1817571Skarels #include <syslog.h> 1937292Sbostic #include "pathnames.h" 209019Ssam 219019Ssam struct interface *ifnet; 2236831Skarels struct interface **ifnext = &ifnet; 239019Ssam int lookforinterfaces = 1; 249019Ssam int externalinterfaces = 0; /* # of remote and local interfaces */ 2531220Skarels int foundloopback; /* valid flag for loopaddr */ 2631220Skarels struct sockaddr loopaddr; /* our address on loopback */ 279019Ssam 289019Ssam /* 2921842Skarels * Find the network interfaces which have configured themselves. 3021842Skarels * If the interface is present but not yet up (for example an 319019Ssam * ARPANET IMP), set the lookforinterfaces flag so we'll 329019Ssam * come back later and look again. 339019Ssam */ 349019Ssam ifinit() 359019Ssam { 3621842Skarels struct interface ifs, *ifp; 3738685Ssklower int s; 3838685Ssklower char buf[BUFSIZ], *cp, *cplim; 3921842Skarels struct ifconf ifc; 4021842Skarels struct ifreq ifreq, *ifr; 4121842Skarels struct sockaddr_in *sin; 4221842Skarels u_long i; 439019Ssam 4421842Skarels if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 4521842Skarels syslog(LOG_ERR, "socket: %m"); 4636831Skarels close(s); 4736831Skarels return; 489019Ssam } 4921842Skarels ifc.ifc_len = sizeof (buf); 5021842Skarels ifc.ifc_buf = buf; 5121842Skarels if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { 5221842Skarels syslog(LOG_ERR, "ioctl (get interface configuration)"); 5321842Skarels close(s); 5436831Skarels return; 5521842Skarels } 5621842Skarels ifr = ifc.ifc_req; 579019Ssam lookforinterfaces = 0; 5838685Ssklower #ifdef RTM_ADD 5938685Ssklower #define max(a, b) (a > b ? a : b) 6038685Ssklower #define size(p) max((p).sa_len, sizeof(p)) 6138685Ssklower #else 6238685Ssklower #define size(p) (sizeof (p)) 6338685Ssklower #endif 6438685Ssklower cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ 6538685Ssklower for (cp = buf; cp < cplim; 6638685Ssklower cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) { 6738685Ssklower ifr = (struct ifreq *)cp; 6821842Skarels bzero((char *)&ifs, sizeof(ifs)); 6921842Skarels ifs.int_addr = ifr->ifr_addr; 7021842Skarels ifreq = *ifr; 7121842Skarels if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) { 7236831Skarels syslog(LOG_ERR, "%s: ioctl (get interface flags)", 7336831Skarels ifr->ifr_name); 7421842Skarels continue; 7521842Skarels } 7621842Skarels ifs.int_flags = ifreq.ifr_flags | IFF_INTERFACE; 7721842Skarels if ((ifs.int_flags & IFF_UP) == 0 || 7821842Skarels ifr->ifr_addr.sa_family == AF_UNSPEC) { 799019Ssam lookforinterfaces = 1; 809019Ssam continue; 819019Ssam } 8236831Skarels /* argh, this'll have to change sometime */ 8336831Skarels if (ifs.int_addr.sa_family != AF_INET) 8436831Skarels continue; 8536831Skarels if (ifs.int_flags & IFF_POINTOPOINT) { 8636831Skarels if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) { 8736831Skarels syslog(LOG_ERR, "%s: ioctl (get dstaddr)", 8836831Skarels ifr->ifr_name); 8936831Skarels continue; 9036831Skarels } 9136831Skarels if (ifr->ifr_addr.sa_family == AF_UNSPEC) { 9236831Skarels lookforinterfaces = 1; 9336831Skarels continue; 9436831Skarels } 9536831Skarels ifs.int_dstaddr = ifreq.ifr_dstaddr; 9636831Skarels } 9734568Skarels /* 9834568Skarels * already known to us? 9934568Skarels * This allows multiple point-to-point links 10034568Skarels * to share a source address (possibly with one 10134568Skarels * other link), but assumes that there will not be 10234568Skarels * multiple links with the same destination address. 10334568Skarels */ 10434568Skarels if (ifs.int_flags & IFF_POINTOPOINT) { 10534568Skarels if (if_ifwithdstaddr(&ifs.int_dstaddr)) 10634568Skarels continue; 10734568Skarels } else if (if_ifwithaddr(&ifs.int_addr)) 1089019Ssam continue; 10931220Skarels if (ifs.int_flags & IFF_LOOPBACK) { 11034568Skarels ifs.int_flags |= IFF_PASSIVE; 11131220Skarels foundloopback = 1; 11231220Skarels loopaddr = ifs.int_addr; 11331220Skarels for (ifp = ifnet; ifp; ifp = ifp->int_next) 11431220Skarels if (ifp->int_flags & IFF_POINTOPOINT) 11531220Skarels add_ptopt_localrt(ifp); 11631220Skarels } 11721842Skarels if (ifs.int_flags & IFF_BROADCAST) { 11821842Skarels if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { 11936831Skarels syslog(LOG_ERR, "%s: ioctl (get broadaddr)", 12036831Skarels ifr->ifr_name); 12121842Skarels continue; 12221842Skarels } 12336831Skarels #ifndef sun 12421842Skarels ifs.int_broadaddr = ifreq.ifr_broadaddr; 12536831Skarels #else 12636831Skarels ifs.int_broadaddr = ifreq.ifr_addr; 12736831Skarels #endif 12821842Skarels } 12936831Skarels #ifdef SIOCGIFMETRIC 13036831Skarels if (ioctl(s, SIOCGIFMETRIC, (char *)&ifreq) < 0) { 13136831Skarels syslog(LOG_ERR, "%s: ioctl (get metric)", 13236831Skarels ifr->ifr_name); 13336831Skarels ifs.int_metric = 0; 13436831Skarels } else 13526099Skarels ifs.int_metric = ifreq.ifr_metric; 13636831Skarels #else 13736831Skarels ifs.int_metric = 0; 13836831Skarels #endif 13934568Skarels /* 14034568Skarels * Use a minimum metric of one; 14134568Skarels * treat the interface metric (default 0) 14234568Skarels * as an increment to the hop count of one. 14334568Skarels */ 14434568Skarels ifs.int_metric++; 14521842Skarels if (ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) < 0) { 14636831Skarels syslog(LOG_ERR, "%s: ioctl (get netmask)", 14736831Skarels ifr->ifr_name); 14821842Skarels continue; 14921842Skarels } 15021842Skarels sin = (struct sockaddr_in *)&ifreq.ifr_addr; 15121842Skarels ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr); 15221842Skarels sin = (struct sockaddr_in *)&ifs.int_addr; 15321842Skarels i = ntohl(sin->sin_addr.s_addr); 15421842Skarels if (IN_CLASSA(i)) 15521842Skarels ifs.int_netmask = IN_CLASSA_NET; 15621842Skarels else if (IN_CLASSB(i)) 15721842Skarels ifs.int_netmask = IN_CLASSB_NET; 15821842Skarels else 15921842Skarels ifs.int_netmask = IN_CLASSC_NET; 16021842Skarels ifs.int_net = i & ifs.int_netmask; 16121842Skarels ifs.int_subnet = i & ifs.int_subnetmask; 16227231Skarels if (ifs.int_subnetmask != ifs.int_netmask) 16327231Skarels ifs.int_flags |= IFF_SUBNET; 1649019Ssam ifp = (struct interface *)malloc(sizeof (struct interface)); 1659019Ssam if (ifp == 0) { 1669019Ssam printf("routed: out of memory\n"); 1679019Ssam break; 1689019Ssam } 16921842Skarels *ifp = ifs; 1709019Ssam /* 1719019Ssam * Count the # of directly connected networks 1729019Ssam * and point to point links which aren't looped 1739019Ssam * back to ourself. This is used below to 1749019Ssam * decide if we should be a routing ``supplier''. 1759019Ssam */ 17631220Skarels if ((ifs.int_flags & IFF_LOOPBACK) == 0 && 17731220Skarels ((ifs.int_flags & IFF_POINTOPOINT) == 0 || 17831220Skarels if_ifwithaddr(&ifs.int_dstaddr) == 0)) 1799019Ssam externalinterfaces++; 18025505Skarels /* 18125505Skarels * If we have a point-to-point link, we want to act 18225505Skarels * as a supplier even if it's our only interface, 18325505Skarels * as that's the only way our peer on the other end 18425505Skarels * can tell that the link is up. 18525505Skarels */ 18625505Skarels if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0) 18725505Skarels supplier = 1; 18821842Skarels ifp->int_name = malloc(strlen(ifr->ifr_name) + 1); 1899019Ssam if (ifp->int_name == 0) { 1909019Ssam fprintf(stderr, "routed: ifinit: out of memory\n"); 19131220Skarels syslog(LOG_ERR, "routed: ifinit: out of memory\n"); 19236831Skarels close(s); 19331220Skarels return; 1949019Ssam } 19521842Skarels strcpy(ifp->int_name, ifr->ifr_name); 19636831Skarels *ifnext = ifp; 19736831Skarels ifnext = &ifp->int_next; 1989019Ssam traceinit(ifp); 1999019Ssam addrouteforif(ifp); 2009019Ssam } 2019019Ssam if (externalinterfaces > 1 && supplier < 0) 2029019Ssam supplier = 1; 20321842Skarels close(s); 2049019Ssam } 2059019Ssam 20627231Skarels /* 20727231Skarels * Add route for interface if not currently installed. 20827231Skarels * Create route to other end if a point-to-point link, 20927231Skarels * otherwise a route to this (sub)network. 21027231Skarels * INTERNET SPECIFIC. 21127231Skarels */ 2129019Ssam addrouteforif(ifp) 21331220Skarels register struct interface *ifp; 2149019Ssam { 2159019Ssam struct sockaddr_in net; 2169019Ssam struct sockaddr *dst; 21734661Skarels int state; 21831220Skarels register struct rt_entry *rt; 2199019Ssam 2209019Ssam if (ifp->int_flags & IFF_POINTOPOINT) 2219019Ssam dst = &ifp->int_dstaddr; 2229019Ssam else { 2239019Ssam bzero((char *)&net, sizeof (net)); 2249019Ssam net.sin_family = AF_INET; 22521842Skarels net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY); 2269019Ssam dst = (struct sockaddr *)&net; 2279019Ssam } 22821842Skarels rt = rtfind(dst); 22929002Skarels if (rt && 23029002Skarels (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE) 23118114Skarels return; 23221842Skarels if (rt) 23321842Skarels rtdelete(rt); 23427231Skarels /* 23527231Skarels * If interface on subnetted network, 23627231Skarels * install route to network as well. 23727231Skarels * This is meant for external viewers. 23827231Skarels */ 23927231Skarels if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) { 24031220Skarels struct in_addr subnet; 24131220Skarels 24231220Skarels subnet = net.sin_addr; 24327231Skarels net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); 24427231Skarels rt = rtfind(dst); 24529002Skarels if (rt == 0) 24629002Skarels rtadd(dst, &ifp->int_addr, ifp->int_metric, 24729002Skarels ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) | 24831220Skarels RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET)); 24931220Skarels else if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET)) == 25031220Skarels (RTS_INTERNAL|RTS_SUBNET) && 25131220Skarels ifp->int_metric < rt->rt_metric) 25231220Skarels rtchange(rt, &rt->rt_router, ifp->int_metric); 25331220Skarels net.sin_addr = subnet; 25427231Skarels } 25529002Skarels if (ifp->int_transitions++ > 0) 25629002Skarels syslog(LOG_ERR, "re-installing interface %s", ifp->int_name); 25731220Skarels state = ifp->int_flags & 25831220Skarels (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET); 25931220Skarels if (ifp->int_flags & IFF_POINTOPOINT && 26031220Skarels (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr) & 26131220Skarels ifp->int_netmask) != ifp->int_net) 26231220Skarels state &= ~RTS_SUBNET; 26331220Skarels if (ifp->int_flags & IFF_LOOPBACK) 26434568Skarels state |= RTS_EXTERNAL; 26531220Skarels rtadd(dst, &ifp->int_addr, ifp->int_metric, state); 26631220Skarels if (ifp->int_flags & IFF_POINTOPOINT && foundloopback) 26731220Skarels add_ptopt_localrt(ifp); 26831220Skarels } 26929002Skarels 27031220Skarels /* 27131220Skarels * Add route to local end of point-to-point using loopback. 27231220Skarels * If a route to this network is being sent to neighbors on other nets, 27331220Skarels * mark this route as subnet so we don't have to propagate it too. 27431220Skarels */ 27531220Skarels add_ptopt_localrt(ifp) 27631220Skarels register struct interface *ifp; 27731220Skarels { 27831220Skarels struct rt_entry *rt; 27931220Skarels struct sockaddr *dst; 28031220Skarels struct sockaddr_in net; 28131220Skarels int state; 28231220Skarels 28331220Skarels state = RTS_INTERFACE | RTS_PASSIVE; 28431220Skarels 28531220Skarels /* look for route to logical network */ 28631220Skarels bzero((char *)&net, sizeof (net)); 28731220Skarels net.sin_family = AF_INET; 28831220Skarels net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); 28931220Skarels dst = (struct sockaddr *)&net; 29031220Skarels rt = rtfind(dst); 29131220Skarels if (rt && rt->rt_state & RTS_INTERNAL) 29231220Skarels state |= RTS_SUBNET; 29331220Skarels 29431220Skarels dst = &ifp->int_addr; 29531220Skarels if (rt = rtfind(dst)) { 29631220Skarels if (rt && rt->rt_state & RTS_INTERFACE) 29731220Skarels return; 29831220Skarels rtdelete(rt); 29931220Skarels } 30034661Skarels rtadd(dst, &loopaddr, 1, state); 3019019Ssam } 3029019Ssam 3039019Ssam /* 3049019Ssam * As a concession to the ARPANET we read a list of gateways 3059019Ssam * from /etc/gateways and add them to our tables. This file 3069019Ssam * exists at each ARPANET gateway and indicates a set of ``remote'' 3079019Ssam * gateways (i.e. a gateway which we can't immediately determine 3089019Ssam * if it's present or not as we can do for those directly connected 3099019Ssam * at the hardware level). If a gateway is marked ``passive'' 3109019Ssam * in the file, then we assume it doesn't have a routing process 3119019Ssam * of our design and simply assume it's always present. Those 3129019Ssam * not marked passive are treated as if they were directly 3139019Ssam * connected -- they're added into the interface list so we'll 3149019Ssam * send them routing updates. 31531220Skarels * 31631220Skarels * PASSIVE ENTRIES AREN'T NEEDED OR USED ON GATEWAYS RUNNING EGP. 3179019Ssam */ 3189019Ssam gwkludge() 3199019Ssam { 3209019Ssam struct sockaddr_in dst, gate; 3219019Ssam FILE *fp; 3229019Ssam char *type, *dname, *gname, *qual, buf[BUFSIZ]; 3239019Ssam struct interface *ifp; 32428906Skarels int metric, n; 32516327Skarels struct rt_entry route; 3269019Ssam 32737292Sbostic fp = fopen(_PATH_GATEWAYS, "r"); 3289019Ssam if (fp == NULL) 3299019Ssam return; 3309019Ssam qual = buf; 3319019Ssam dname = buf + 64; 3329019Ssam gname = buf + ((BUFSIZ - 64) / 3); 3339019Ssam type = buf + (((BUFSIZ - 64) * 2) / 3); 3349019Ssam bzero((char *)&dst, sizeof (dst)); 3359019Ssam bzero((char *)&gate, sizeof (gate)); 33616327Skarels bzero((char *)&route, sizeof(route)); 33730745Skarels /* format: {net | host} XX gateway XX metric DD [passive | external]\n */ 3389019Ssam #define readentry(fp) \ 3399019Ssam fscanf((fp), "%s %s gateway %s metric %d %s\n", \ 3409019Ssam type, dname, gname, &metric, qual) 3419019Ssam for (;;) { 34228906Skarels if ((n = readentry(fp)) == EOF) 3439019Ssam break; 34410245Ssam if (!getnetorhostname(type, dname, &dst)) 3459019Ssam continue; 34610245Ssam if (!gethostnameornumber(gname, &gate)) 3479019Ssam continue; 34834661Skarels if (metric == 0) /* XXX */ 34934661Skarels metric = 1; 35016327Skarels if (strcmp(qual, "passive") == 0) { 35116327Skarels /* 35216327Skarels * Passive entries aren't placed in our tables, 35316327Skarels * only the kernel's, so we don't copy all of the 35416327Skarels * external routing information within a net. 35516327Skarels * Internal machines should use the default 35616327Skarels * route to a suitable gateway (like us). 35716327Skarels */ 35816327Skarels route.rt_dst = *(struct sockaddr *) &dst; 35916327Skarels route.rt_router = *(struct sockaddr *) &gate; 36016327Skarels route.rt_flags = RTF_UP; 36116327Skarels if (strcmp(type, "host") == 0) 36216327Skarels route.rt_flags |= RTF_HOST; 36316327Skarels if (metric) 36416327Skarels route.rt_flags |= RTF_GATEWAY; 36516327Skarels (void) ioctl(s, SIOCADDRT, (char *)&route.rt_rt); 36616327Skarels continue; 36716327Skarels } 36827231Skarels if (strcmp(qual, "external") == 0) { 36927231Skarels /* 37027231Skarels * Entries marked external are handled 37127231Skarels * by other means, e.g. EGP, 37227231Skarels * and are placed in our tables only 37327231Skarels * to prevent overriding them 37427231Skarels * with something else. 37527231Skarels */ 37627231Skarels rtadd(&dst, &gate, metric, RTS_EXTERNAL|RTS_PASSIVE); 37728906Skarels continue; 37827231Skarels } 37916327Skarels /* assume no duplicate entries */ 38016327Skarels externalinterfaces++; 3819019Ssam ifp = (struct interface *)malloc(sizeof (*ifp)); 3829019Ssam bzero((char *)ifp, sizeof (*ifp)); 3839019Ssam ifp->int_flags = IFF_REMOTE; 3849019Ssam /* can't identify broadcast capability */ 3859019Ssam ifp->int_net = inet_netof(dst.sin_addr); 3869019Ssam if (strcmp(type, "host") == 0) { 3879019Ssam ifp->int_flags |= IFF_POINTOPOINT; 3889019Ssam ifp->int_dstaddr = *((struct sockaddr *)&dst); 3899019Ssam } 3909019Ssam ifp->int_addr = *((struct sockaddr *)&gate); 3919019Ssam ifp->int_metric = metric; 3929019Ssam ifp->int_next = ifnet; 3939019Ssam ifnet = ifp; 3949019Ssam addrouteforif(ifp); 3959019Ssam } 3969019Ssam fclose(fp); 3979019Ssam } 39810245Ssam 39910245Ssam getnetorhostname(type, name, sin) 40010245Ssam char *type, *name; 40110245Ssam struct sockaddr_in *sin; 40210245Ssam { 40310245Ssam 40410245Ssam if (strcmp(type, "net") == 0) { 40510245Ssam struct netent *np = getnetbyname(name); 40610245Ssam int n; 40710245Ssam 40810245Ssam if (np == 0) 40910245Ssam n = inet_network(name); 41011527Ssam else { 41111527Ssam if (np->n_addrtype != AF_INET) 41211527Ssam return (0); 41310245Ssam n = np->n_net; 41421842Skarels /* 41521842Skarels * getnetbyname returns right-adjusted value. 41621842Skarels */ 41721842Skarels if (n < 128) 41821842Skarels n <<= IN_CLASSA_NSHIFT; 41921842Skarels else if (n < 65536) 42021842Skarels n <<= IN_CLASSB_NSHIFT; 42121842Skarels else 42221842Skarels n <<= IN_CLASSC_NSHIFT; 42311527Ssam } 42410245Ssam sin->sin_family = AF_INET; 42510245Ssam sin->sin_addr = inet_makeaddr(n, INADDR_ANY); 42610245Ssam return (1); 42710245Ssam } 42810245Ssam if (strcmp(type, "host") == 0) { 42910245Ssam struct hostent *hp = gethostbyname(name); 43010245Ssam 43110245Ssam if (hp == 0) 43210245Ssam sin->sin_addr.s_addr = inet_addr(name); 43311527Ssam else { 43411527Ssam if (hp->h_addrtype != AF_INET) 43511527Ssam return (0); 43610245Ssam bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); 43711527Ssam } 43810245Ssam sin->sin_family = AF_INET; 43910245Ssam return (1); 44010245Ssam } 44110245Ssam return (0); 44210245Ssam } 44310245Ssam 44410245Ssam gethostnameornumber(name, sin) 44510245Ssam char *name; 44610245Ssam struct sockaddr_in *sin; 44710245Ssam { 44810245Ssam struct hostent *hp; 44910245Ssam 45010245Ssam hp = gethostbyname(name); 45110245Ssam if (hp) { 45210245Ssam bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); 45310245Ssam sin->sin_family = hp->h_addrtype; 45410245Ssam return (1); 45510245Ssam } 45610245Ssam sin->sin_addr.s_addr = inet_addr(name); 45710245Ssam sin->sin_family = AF_INET; 45810245Ssam return (sin->sin_addr.s_addr != -1); 45910245Ssam } 460