121998Sdist /* 234568Skarels * Copyright (c) 1983, 1988 Regents of the University of California. 333489Sbostic * All rights reserved. 433489Sbostic * 542712Sbostic * %sccs.include.redist.c% 621998Sdist */ 721998Sdist 89019Ssam #ifndef lint 9*55904Ssklower static char sccsid[] = "@(#)startup.c 5.22 (Berkeley) 08/14/92"; 1033489Sbostic #endif /* not lint */ 119019Ssam 129019Ssam /* 139019Ssam * Routing Table Management Daemon 149019Ssam */ 1510245Ssam #include "defs.h" 1616327Skarels #include <sys/ioctl.h> 1752583Ssklower #include <sys/kinfo.h> 189019Ssam #include <net/if.h> 1952583Ssklower #include <net/if_dl.h> 2017571Skarels #include <syslog.h> 2146784Sbostic #include <stdlib.h> 2237292Sbostic #include "pathnames.h" 239019Ssam 249019Ssam struct interface *ifnet; 2536831Skarels struct interface **ifnext = &ifnet; 269019Ssam int lookforinterfaces = 1; 279019Ssam int externalinterfaces = 0; /* # of remote and local interfaces */ 2831220Skarels int foundloopback; /* valid flag for loopaddr */ 2931220Skarels struct sockaddr loopaddr; /* our address on loopback */ 309019Ssam 3152583Ssklower 3252583Ssklower void 3352583Ssklower quit(s) 3452583Ssklower char *s; 3552583Ssklower { 3652583Ssklower extern int errno; 3752583Ssklower int sverrno = errno; 3852583Ssklower 3952583Ssklower (void) fprintf(stderr, "route: "); 4052583Ssklower if (s) 4152583Ssklower (void) fprintf(stderr, "%s: ", s); 4252583Ssklower (void) fprintf(stderr, "%s\n", strerror(sverrno)); 4352583Ssklower exit(1); 4452583Ssklower /* NOTREACHED */ 4552583Ssklower } 4652583Ssklower 4752583Ssklower struct rt_addrinfo info; 4852583Ssklower /* Sleazy use of local variables throughout file, warning!!!! */ 4952583Ssklower #define netmask info.rti_info[RTAX_NETMASK] 5052583Ssklower #define ifaaddr info.rti_info[RTAX_IFA] 5152583Ssklower #define brdaddr info.rti_info[RTAX_BRD] 5252583Ssklower 5352583Ssklower #define ROUNDUP(a) \ 5452583Ssklower ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 5552583Ssklower #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 5652583Ssklower 5752583Ssklower void 5852583Ssklower rt_xaddrs(cp, cplim, rtinfo) 5952583Ssklower register caddr_t cp, cplim; 6052583Ssklower register struct rt_addrinfo *rtinfo; 6152583Ssklower { 6252583Ssklower register struct sockaddr *sa; 6352583Ssklower register int i; 6452583Ssklower 6552583Ssklower bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 6652583Ssklower for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 6752583Ssklower if ((rtinfo->rti_addrs & (1 << i)) == 0) 6852583Ssklower continue; 6952583Ssklower rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 7052583Ssklower ADVANCE(cp, sa); 7152583Ssklower } 7252583Ssklower } 7352583Ssklower 749019Ssam /* 7521842Skarels * Find the network interfaces which have configured themselves. 7621842Skarels * If the interface is present but not yet up (for example an 779019Ssam * ARPANET IMP), set the lookforinterfaces flag so we'll 789019Ssam * come back later and look again. 799019Ssam */ 809019Ssam ifinit() 819019Ssam { 8221842Skarels struct interface ifs, *ifp; 8352583Ssklower int needed, rlen, no_ipaddr = 0, flags = 0; 8452583Ssklower char *buf, *cplim, *cp; 8552583Ssklower register struct if_msghdr *ifm; 8652583Ssklower register struct ifa_msghdr *ifam; 8752583Ssklower struct sockaddr_dl *sdl; 8821842Skarels struct sockaddr_in *sin; 8921842Skarels u_long i; 909019Ssam 9152583Ssklower if ((needed = getkerninfo(KINFO_RT_IFLIST, 0, 0, 0)) < 0) 9252583Ssklower quit("route-getkerninfo-estimate"); 9352583Ssklower if ((buf = malloc(needed)) == NULL) 9452583Ssklower quit("malloc"); 9552583Ssklower if ((rlen = getkerninfo(KINFO_RT_IFLIST, buf, &needed, 0)) < 0) 9652583Ssklower quit("actual retrieval of interface table"); 979019Ssam lookforinterfaces = 0; 9852583Ssklower cplim = buf + rlen; 9952583Ssklower for (cp = buf; cp < cplim; cp += ifm->ifm_msglen) { 10052583Ssklower ifm = (struct if_msghdr *)cp; 10152583Ssklower if (ifm->ifm_type == RTM_IFINFO) { 10252583Ssklower bzero(&ifs, sizeof(ifs)); 103*55904Ssklower ifs.int_flags = flags = (0xffff & ifm->ifm_flags) | IFF_INTERFACE; 10452583Ssklower if ((flags & IFF_UP) == 0 || no_ipaddr) 10552583Ssklower lookforinterfaces = 1; 10652583Ssklower sdl = (struct sockaddr_dl *) (ifm + 1); 10752583Ssklower sdl->sdl_data[sdl->sdl_nlen] = 0; 10852583Ssklower no_ipaddr = 1; 1099019Ssam continue; 1109019Ssam } 11152583Ssklower if (ifm->ifm_type != RTM_NEWADDR) 11252583Ssklower quit("ifinit: out of sync"); 11352583Ssklower if ((flags & IFF_UP) == 0) 11452583Ssklower continue; 11552583Ssklower ifam = (struct ifa_msghdr *)ifm; 11652583Ssklower info.rti_addrs = ifam->ifam_addrs; 11752583Ssklower rt_xaddrs((char *)(ifam + 1), cp + ifam->ifam_msglen, &info); 11852583Ssklower if (ifaaddr == 0) { 11952583Ssklower syslog(LOG_ERR, "%s: (get addr)", sdl->sdl_data); 12052583Ssklower continue; 12152583Ssklower } 12252583Ssklower ifs.int_addr = *ifaaddr; 12336831Skarels if (ifs.int_addr.sa_family != AF_INET) 12436831Skarels continue; 12552583Ssklower no_ipaddr = 0; 12652583Ssklower if (ifs.int_flags & IFF_POINTOPOINT) { 12752583Ssklower if (brdaddr == 0) { 12852583Ssklower syslog(LOG_ERR, "%s: (get dstaddr)", 12952583Ssklower sdl->sdl_data); 13052583Ssklower continue; 13136831Skarels } 13252583Ssklower if (brdaddr->sa_family == AF_UNSPEC) { 13336831Skarels lookforinterfaces = 1; 13436831Skarels continue; 13536831Skarels } 13652583Ssklower ifs.int_dstaddr = *brdaddr; 13736831Skarels } 13834568Skarels /* 13934568Skarels * already known to us? 14034568Skarels * This allows multiple point-to-point links 14134568Skarels * to share a source address (possibly with one 14234568Skarels * other link), but assumes that there will not be 14334568Skarels * multiple links with the same destination address. 14434568Skarels */ 14534568Skarels if (ifs.int_flags & IFF_POINTOPOINT) { 14634568Skarels if (if_ifwithdstaddr(&ifs.int_dstaddr)) 14734568Skarels continue; 14834568Skarels } else if (if_ifwithaddr(&ifs.int_addr)) 1499019Ssam continue; 15031220Skarels if (ifs.int_flags & IFF_LOOPBACK) { 15134568Skarels ifs.int_flags |= IFF_PASSIVE; 15231220Skarels foundloopback = 1; 15331220Skarels loopaddr = ifs.int_addr; 15431220Skarels for (ifp = ifnet; ifp; ifp = ifp->int_next) 15531220Skarels if (ifp->int_flags & IFF_POINTOPOINT) 15631220Skarels add_ptopt_localrt(ifp); 15731220Skarels } 15852583Ssklower if (ifs.int_flags & IFF_BROADCAST) { 15952583Ssklower if (brdaddr == 0) { 16052583Ssklower syslog(LOG_ERR, "%s: (get broadaddr)", 16152583Ssklower sdl->sdl_data); 16252583Ssklower continue; 16352583Ssklower } 16452583Ssklower ifs.int_dstaddr = *brdaddr; 16521842Skarels } 16652621Ssklower /* 16752621Ssklower * Use a minimum metric of one; 16852621Ssklower * treat the interface metric (default 0) 16952621Ssklower * as an increment to the hop count of one. 17052621Ssklower */ 17152621Ssklower ifs.int_metric = ifam->ifam_metric + 1; 17252583Ssklower if (netmask == 0) { 17352583Ssklower syslog(LOG_ERR, "%s: (get netmask)", 17452583Ssklower sdl->sdl_data); 17552583Ssklower continue; 17621842Skarels } 17752583Ssklower sin = (struct sockaddr_in *)netmask; 17821842Skarels ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr); 17921842Skarels sin = (struct sockaddr_in *)&ifs.int_addr; 18021842Skarels i = ntohl(sin->sin_addr.s_addr); 18121842Skarels if (IN_CLASSA(i)) 18221842Skarels ifs.int_netmask = IN_CLASSA_NET; 18321842Skarels else if (IN_CLASSB(i)) 18421842Skarels ifs.int_netmask = IN_CLASSB_NET; 18521842Skarels else 18621842Skarels ifs.int_netmask = IN_CLASSC_NET; 18721842Skarels ifs.int_net = i & ifs.int_netmask; 18821842Skarels ifs.int_subnet = i & ifs.int_subnetmask; 18927231Skarels if (ifs.int_subnetmask != ifs.int_netmask) 19027231Skarels ifs.int_flags |= IFF_SUBNET; 19152583Ssklower ifp = (struct interface *) 19252583Ssklower malloc(sdl->sdl_nlen + 1 + sizeof(ifs)); 1939019Ssam if (ifp == 0) { 1949019Ssam printf("routed: out of memory\n"); 19552583Ssklower lookforinterfaces = 1; 1969019Ssam break; 1979019Ssam } 19821842Skarels *ifp = ifs; 1999019Ssam /* 2009019Ssam * Count the # of directly connected networks 2019019Ssam * and point to point links which aren't looped 2029019Ssam * back to ourself. This is used below to 2039019Ssam * decide if we should be a routing ``supplier''. 2049019Ssam */ 20531220Skarels if ((ifs.int_flags & IFF_LOOPBACK) == 0 && 20631220Skarels ((ifs.int_flags & IFF_POINTOPOINT) == 0 || 20731220Skarels if_ifwithaddr(&ifs.int_dstaddr) == 0)) 2089019Ssam externalinterfaces++; 20925505Skarels /* 21025505Skarels * If we have a point-to-point link, we want to act 21125505Skarels * as a supplier even if it's our only interface, 21225505Skarels * as that's the only way our peer on the other end 21325505Skarels * can tell that the link is up. 21425505Skarels */ 21525505Skarels if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0) 21625505Skarels supplier = 1; 21752583Ssklower ifp->int_name = (char *)(ifp + 1); 21852583Ssklower strcpy(ifp->int_name, sdl->sdl_data); 21936831Skarels *ifnext = ifp; 22036831Skarels ifnext = &ifp->int_next; 2219019Ssam traceinit(ifp); 2229019Ssam addrouteforif(ifp); 2239019Ssam } 2249019Ssam if (externalinterfaces > 1 && supplier < 0) 2259019Ssam supplier = 1; 22652583Ssklower free(buf); 2279019Ssam } 2289019Ssam 22927231Skarels /* 23027231Skarels * Add route for interface if not currently installed. 23127231Skarels * Create route to other end if a point-to-point link, 23227231Skarels * otherwise a route to this (sub)network. 23327231Skarels * INTERNET SPECIFIC. 23427231Skarels */ 2359019Ssam addrouteforif(ifp) 23631220Skarels register struct interface *ifp; 2379019Ssam { 2389019Ssam struct sockaddr_in net; 2399019Ssam struct sockaddr *dst; 24034661Skarels int state; 24131220Skarels register struct rt_entry *rt; 2429019Ssam 2439019Ssam if (ifp->int_flags & IFF_POINTOPOINT) 2449019Ssam dst = &ifp->int_dstaddr; 2459019Ssam else { 2469019Ssam bzero((char *)&net, sizeof (net)); 2479019Ssam net.sin_family = AF_INET; 24821842Skarels net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY); 2499019Ssam dst = (struct sockaddr *)&net; 2509019Ssam } 25121842Skarels rt = rtfind(dst); 25229002Skarels if (rt && 25329002Skarels (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE) 25418114Skarels return; 25521842Skarels if (rt) 25621842Skarels rtdelete(rt); 25727231Skarels /* 25827231Skarels * If interface on subnetted network, 25927231Skarels * install route to network as well. 26027231Skarels * This is meant for external viewers. 26127231Skarels */ 26227231Skarels if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) { 26331220Skarels struct in_addr subnet; 26431220Skarels 26531220Skarels subnet = net.sin_addr; 26627231Skarels net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); 26727231Skarels rt = rtfind(dst); 26829002Skarels if (rt == 0) 26929002Skarels rtadd(dst, &ifp->int_addr, ifp->int_metric, 27029002Skarels ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) | 27131220Skarels RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET)); 27231220Skarels else if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET)) == 27331220Skarels (RTS_INTERNAL|RTS_SUBNET) && 27431220Skarels ifp->int_metric < rt->rt_metric) 27531220Skarels rtchange(rt, &rt->rt_router, ifp->int_metric); 27631220Skarels net.sin_addr = subnet; 27727231Skarels } 27829002Skarels if (ifp->int_transitions++ > 0) 27929002Skarels syslog(LOG_ERR, "re-installing interface %s", ifp->int_name); 28031220Skarels state = ifp->int_flags & 28131220Skarels (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET); 28231220Skarels if (ifp->int_flags & IFF_POINTOPOINT && 28331220Skarels (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr) & 28431220Skarels ifp->int_netmask) != ifp->int_net) 28531220Skarels state &= ~RTS_SUBNET; 28631220Skarels if (ifp->int_flags & IFF_LOOPBACK) 28734568Skarels state |= RTS_EXTERNAL; 28831220Skarels rtadd(dst, &ifp->int_addr, ifp->int_metric, state); 28931220Skarels if (ifp->int_flags & IFF_POINTOPOINT && foundloopback) 29031220Skarels add_ptopt_localrt(ifp); 29131220Skarels } 29229002Skarels 29331220Skarels /* 29431220Skarels * Add route to local end of point-to-point using loopback. 29531220Skarels * If a route to this network is being sent to neighbors on other nets, 29631220Skarels * mark this route as subnet so we don't have to propagate it too. 29731220Skarels */ 29831220Skarels add_ptopt_localrt(ifp) 29931220Skarels register struct interface *ifp; 30031220Skarels { 30131220Skarels struct rt_entry *rt; 30231220Skarels struct sockaddr *dst; 30331220Skarels struct sockaddr_in net; 30431220Skarels int state; 30531220Skarels 30631220Skarels state = RTS_INTERFACE | RTS_PASSIVE; 30731220Skarels 30831220Skarels /* look for route to logical network */ 30931220Skarels bzero((char *)&net, sizeof (net)); 31031220Skarels net.sin_family = AF_INET; 31131220Skarels net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); 31231220Skarels dst = (struct sockaddr *)&net; 31331220Skarels rt = rtfind(dst); 31431220Skarels if (rt && rt->rt_state & RTS_INTERNAL) 31531220Skarels state |= RTS_SUBNET; 31631220Skarels 31731220Skarels dst = &ifp->int_addr; 31831220Skarels if (rt = rtfind(dst)) { 31931220Skarels if (rt && rt->rt_state & RTS_INTERFACE) 32031220Skarels return; 32131220Skarels rtdelete(rt); 32231220Skarels } 32334661Skarels rtadd(dst, &loopaddr, 1, state); 3249019Ssam } 3259019Ssam 3269019Ssam /* 3279019Ssam * As a concession to the ARPANET we read a list of gateways 3289019Ssam * from /etc/gateways and add them to our tables. This file 3299019Ssam * exists at each ARPANET gateway and indicates a set of ``remote'' 3309019Ssam * gateways (i.e. a gateway which we can't immediately determine 3319019Ssam * if it's present or not as we can do for those directly connected 3329019Ssam * at the hardware level). If a gateway is marked ``passive'' 3339019Ssam * in the file, then we assume it doesn't have a routing process 3349019Ssam * of our design and simply assume it's always present. Those 3359019Ssam * not marked passive are treated as if they were directly 3369019Ssam * connected -- they're added into the interface list so we'll 3379019Ssam * send them routing updates. 33831220Skarels * 33931220Skarels * PASSIVE ENTRIES AREN'T NEEDED OR USED ON GATEWAYS RUNNING EGP. 3409019Ssam */ 3419019Ssam gwkludge() 3429019Ssam { 3439019Ssam struct sockaddr_in dst, gate; 3449019Ssam FILE *fp; 3459019Ssam char *type, *dname, *gname, *qual, buf[BUFSIZ]; 3469019Ssam struct interface *ifp; 34728906Skarels int metric, n; 34816327Skarels struct rt_entry route; 3499019Ssam 35037292Sbostic fp = fopen(_PATH_GATEWAYS, "r"); 3519019Ssam if (fp == NULL) 3529019Ssam return; 3539019Ssam qual = buf; 3549019Ssam dname = buf + 64; 3559019Ssam gname = buf + ((BUFSIZ - 64) / 3); 3569019Ssam type = buf + (((BUFSIZ - 64) * 2) / 3); 3579019Ssam bzero((char *)&dst, sizeof (dst)); 3589019Ssam bzero((char *)&gate, sizeof (gate)); 35916327Skarels bzero((char *)&route, sizeof(route)); 36030745Skarels /* format: {net | host} XX gateway XX metric DD [passive | external]\n */ 3619019Ssam #define readentry(fp) \ 3629019Ssam fscanf((fp), "%s %s gateway %s metric %d %s\n", \ 3639019Ssam type, dname, gname, &metric, qual) 3649019Ssam for (;;) { 36528906Skarels if ((n = readentry(fp)) == EOF) 3669019Ssam break; 36710245Ssam if (!getnetorhostname(type, dname, &dst)) 3689019Ssam continue; 36910245Ssam if (!gethostnameornumber(gname, &gate)) 3709019Ssam continue; 37134661Skarels if (metric == 0) /* XXX */ 37234661Skarels metric = 1; 37316327Skarels if (strcmp(qual, "passive") == 0) { 37416327Skarels /* 37516327Skarels * Passive entries aren't placed in our tables, 37616327Skarels * only the kernel's, so we don't copy all of the 37716327Skarels * external routing information within a net. 37816327Skarels * Internal machines should use the default 37916327Skarels * route to a suitable gateway (like us). 38016327Skarels */ 38116327Skarels route.rt_dst = *(struct sockaddr *) &dst; 38216327Skarels route.rt_router = *(struct sockaddr *) &gate; 38316327Skarels route.rt_flags = RTF_UP; 38416327Skarels if (strcmp(type, "host") == 0) 38516327Skarels route.rt_flags |= RTF_HOST; 38616327Skarels if (metric) 38716327Skarels route.rt_flags |= RTF_GATEWAY; 38852583Ssklower (void) rtioctl(ADD, &route.rt_rt); 38916327Skarels continue; 39016327Skarels } 39127231Skarels if (strcmp(qual, "external") == 0) { 39227231Skarels /* 39327231Skarels * Entries marked external are handled 39427231Skarels * by other means, e.g. EGP, 39527231Skarels * and are placed in our tables only 39627231Skarels * to prevent overriding them 39727231Skarels * with something else. 39827231Skarels */ 39927231Skarels rtadd(&dst, &gate, metric, RTS_EXTERNAL|RTS_PASSIVE); 40028906Skarels continue; 40127231Skarels } 40216327Skarels /* assume no duplicate entries */ 40316327Skarels externalinterfaces++; 4049019Ssam ifp = (struct interface *)malloc(sizeof (*ifp)); 4059019Ssam bzero((char *)ifp, sizeof (*ifp)); 4069019Ssam ifp->int_flags = IFF_REMOTE; 4079019Ssam /* can't identify broadcast capability */ 4089019Ssam ifp->int_net = inet_netof(dst.sin_addr); 4099019Ssam if (strcmp(type, "host") == 0) { 4109019Ssam ifp->int_flags |= IFF_POINTOPOINT; 4119019Ssam ifp->int_dstaddr = *((struct sockaddr *)&dst); 4129019Ssam } 4139019Ssam ifp->int_addr = *((struct sockaddr *)&gate); 4149019Ssam ifp->int_metric = metric; 4159019Ssam ifp->int_next = ifnet; 4169019Ssam ifnet = ifp; 4179019Ssam addrouteforif(ifp); 4189019Ssam } 4199019Ssam fclose(fp); 4209019Ssam } 42110245Ssam 42210245Ssam getnetorhostname(type, name, sin) 42310245Ssam char *type, *name; 42410245Ssam struct sockaddr_in *sin; 42510245Ssam { 42610245Ssam 42710245Ssam if (strcmp(type, "net") == 0) { 42810245Ssam struct netent *np = getnetbyname(name); 42910245Ssam int n; 43010245Ssam 43110245Ssam if (np == 0) 43210245Ssam n = inet_network(name); 43311527Ssam else { 43411527Ssam if (np->n_addrtype != AF_INET) 43511527Ssam return (0); 43610245Ssam n = np->n_net; 43721842Skarels /* 43821842Skarels * getnetbyname returns right-adjusted value. 43921842Skarels */ 44021842Skarels if (n < 128) 44121842Skarels n <<= IN_CLASSA_NSHIFT; 44221842Skarels else if (n < 65536) 44321842Skarels n <<= IN_CLASSB_NSHIFT; 44421842Skarels else 44521842Skarels n <<= IN_CLASSC_NSHIFT; 44611527Ssam } 44710245Ssam sin->sin_family = AF_INET; 44810245Ssam sin->sin_addr = inet_makeaddr(n, INADDR_ANY); 44910245Ssam return (1); 45010245Ssam } 45110245Ssam if (strcmp(type, "host") == 0) { 45210245Ssam struct hostent *hp = gethostbyname(name); 45310245Ssam 45410245Ssam if (hp == 0) 45510245Ssam sin->sin_addr.s_addr = inet_addr(name); 45611527Ssam else { 45711527Ssam if (hp->h_addrtype != AF_INET) 45811527Ssam return (0); 45910245Ssam bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); 46011527Ssam } 46110245Ssam sin->sin_family = AF_INET; 46210245Ssam return (1); 46310245Ssam } 46410245Ssam return (0); 46510245Ssam } 46610245Ssam 46710245Ssam gethostnameornumber(name, sin) 46810245Ssam char *name; 46910245Ssam struct sockaddr_in *sin; 47010245Ssam { 47110245Ssam struct hostent *hp; 47210245Ssam 47310245Ssam hp = gethostbyname(name); 47410245Ssam if (hp) { 47510245Ssam bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); 47610245Ssam sin->sin_family = hp->h_addrtype; 47710245Ssam return (1); 47810245Ssam } 47910245Ssam sin->sin_addr.s_addr = inet_addr(name); 48010245Ssam sin->sin_family = AF_INET; 48110245Ssam return (sin->sin_addr.s_addr != -1); 48210245Ssam } 483