X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/f804e0463c414935ba61eb58e1fc67b06fdc82ca..42758f3596507dfab5ac4c00963422dbfa708402:/usr/src/sbin/routed/startup.c diff --git a/usr/src/sbin/routed/startup.c b/usr/src/sbin/routed/startup.c index f6f01fe708..86857991ae 100644 --- a/usr/src/sbin/routed/startup.c +++ b/usr/src/sbin/routed/startup.c @@ -1,6 +1,13 @@ +/* + * Copyright (c) 1983, 1988 Regents of the University of California. + * All rights reserved. + * + * %sccs.include.redist.c% + */ + #ifndef lint -static char sccsid[] = "@(#)startup.c 4.6 (Berkeley) %G%"; -#endif +static char sccsid[] = "@(#)startup.c 5.18 (Berkeley) %G%"; +#endif /* not lint */ /* * Routing Table Management Daemon @@ -8,153 +15,289 @@ static char sccsid[] = "@(#)startup.c 4.6 (Berkeley) %G%"; #include "defs.h" #include #include -#include +#include +#include "pathnames.h" struct interface *ifnet; -int kmem = -1; +struct interface **ifnext = &ifnet; int lookforinterfaces = 1; -int performnlist = 1; int externalinterfaces = 0; /* # of remote and local interfaces */ -int gateway = 0; /* 1 if we are a gateway to parts beyond */ - -struct nlist nl[] = { -#define N_IFNET 0 - { "_ifnet" }, - { "" }, -}; +int foundloopback; /* valid flag for loopaddr */ +struct sockaddr loopaddr; /* our address on loopback */ /* - * Probe the kernel through /dev/kmem to find the network - * interfaces which have configured themselves. If the - * interface is present but not yet up (for example an + * Find the network interfaces which have configured themselves. + * If the interface is present but not yet up (for example an * ARPANET IMP), set the lookforinterfaces flag so we'll * come back later and look again. */ ifinit() { - struct interface *ifp; - struct ifnet ifs, *next; - char name[32], *cp, *index(); + struct interface ifs, *ifp; + int s; + char buf[BUFSIZ], *cp, *cplim; + struct ifconf ifc; + struct ifreq ifreq, *ifr; + struct sockaddr_in *sin; + u_long i; - if (performnlist) { - nlist("/vmunix", nl); - if (nl[N_IFNET].n_value == 0) { - printf("ifnet: not in namelist\n"); - goto bad; - } - performnlist = 0; - if (gateway > 0) - rtdefault(); - } - if (kmem < 0) { - kmem = open("/dev/kmem", 0); - if (kmem < 0) { - perror("/dev/kmem"); - goto bad; - } - } - if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 || - read(kmem, (char *)&next, sizeof (next)) != sizeof (next)) { - printf("ifnet: error reading kmem\n"); - goto bad; + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "socket: %m"); + close(s); + return; } + ifc.ifc_len = sizeof (buf); + ifc.ifc_buf = buf; + if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { + syslog(LOG_ERR, "ioctl (get interface configuration)"); + close(s); + return; + } + ifr = ifc.ifc_req; lookforinterfaces = 0; - while (next) { - if (lseek(kmem, (long)next, 0) == -1 || - read(kmem, (char *)&ifs, sizeof (ifs)) != sizeof (ifs)) { - perror("read"); - goto bad; - } - next = ifs.if_next; - if ((ifs.if_flags & IFF_UP) == 0) { +#ifdef RTM_ADD +#define max(a, b) (a > b ? a : b) +#define size(p) max((p).sa_len, sizeof(p)) +#else +#define size(p) (sizeof (p)) +#endif + cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ + for (cp = buf; cp < cplim; + cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) { + ifr = (struct ifreq *)cp; + bzero((char *)&ifs, sizeof(ifs)); + ifs.int_addr = ifr->ifr_addr; + ifreq = *ifr; + if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) { + syslog(LOG_ERR, "%s: ioctl (get interface flags)", + ifr->ifr_name); + continue; + } + ifs.int_flags = ifreq.ifr_flags | IFF_INTERFACE; + if ((ifs.int_flags & IFF_UP) == 0 || + ifr->ifr_addr.sa_family == AF_UNSPEC) { lookforinterfaces = 1; continue; } - /* already known to us? */ - if (if_ifwithaddr(&ifs.if_addr)) - continue; /* argh, this'll have to change sometime */ - if (ifs.if_addr.sa_family != AF_INET) + if (ifs.int_addr.sa_family != AF_INET) + continue; + if (ifs.int_flags & IFF_POINTOPOINT) { + if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) { + syslog(LOG_ERR, "%s: ioctl (get dstaddr)", + ifr->ifr_name); + continue; + } + if (ifr->ifr_addr.sa_family == AF_UNSPEC) { + lookforinterfaces = 1; + continue; + } + ifs.int_dstaddr = ifreq.ifr_dstaddr; + } + /* + * already known to us? + * This allows multiple point-to-point links + * to share a source address (possibly with one + * other link), but assumes that there will not be + * multiple links with the same destination address. + */ + if (ifs.int_flags & IFF_POINTOPOINT) { + if (if_ifwithdstaddr(&ifs.int_dstaddr)) + continue; + } else if (if_ifwithaddr(&ifs.int_addr)) continue; - /* no one cares about software loopback interfaces */ - if (ifs.if_net == LOOPBACKNET) + if (ifs.int_flags & IFF_LOOPBACK) { + ifs.int_flags |= IFF_PASSIVE; + foundloopback = 1; + loopaddr = ifs.int_addr; + for (ifp = ifnet; ifp; ifp = ifp->int_next) + if (ifp->int_flags & IFF_POINTOPOINT) + add_ptopt_localrt(ifp); + } + if (ifs.int_flags & IFF_BROADCAST) { + if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { + syslog(LOG_ERR, "%s: ioctl (get broadaddr)", + ifr->ifr_name); + continue; + } +#ifndef sun + ifs.int_broadaddr = ifreq.ifr_broadaddr; +#else + ifs.int_broadaddr = ifreq.ifr_addr; +#endif + } +#ifdef SIOCGIFMETRIC + if (ioctl(s, SIOCGIFMETRIC, (char *)&ifreq) < 0) { + syslog(LOG_ERR, "%s: ioctl (get metric)", + ifr->ifr_name); + ifs.int_metric = 0; + } else + ifs.int_metric = ifreq.ifr_metric; +#else + ifs.int_metric = 0; +#endif + /* + * Use a minimum metric of one; + * treat the interface metric (default 0) + * as an increment to the hop count of one. + */ + ifs.int_metric++; + if (ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) < 0) { + syslog(LOG_ERR, "%s: ioctl (get netmask)", + ifr->ifr_name); continue; + } + sin = (struct sockaddr_in *)&ifreq.ifr_addr; + ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr); + sin = (struct sockaddr_in *)&ifs.int_addr; + i = ntohl(sin->sin_addr.s_addr); + if (IN_CLASSA(i)) + ifs.int_netmask = IN_CLASSA_NET; + else if (IN_CLASSB(i)) + ifs.int_netmask = IN_CLASSB_NET; + else + ifs.int_netmask = IN_CLASSC_NET; + ifs.int_net = i & ifs.int_netmask; + ifs.int_subnet = i & ifs.int_subnetmask; + if (ifs.int_subnetmask != ifs.int_netmask) + ifs.int_flags |= IFF_SUBNET; ifp = (struct interface *)malloc(sizeof (struct interface)); if (ifp == 0) { printf("routed: out of memory\n"); break; } + *ifp = ifs; /* * Count the # of directly connected networks * and point to point links which aren't looped * back to ourself. This is used below to * decide if we should be a routing ``supplier''. */ - if ((ifs.if_flags & IFF_POINTOPOINT) == 0 || - if_ifwithaddr(&ifs.if_dstaddr) == 0) + if ((ifs.int_flags & IFF_LOOPBACK) == 0 && + ((ifs.int_flags & IFF_POINTOPOINT) == 0 || + if_ifwithaddr(&ifs.int_dstaddr) == 0)) externalinterfaces++; - if ((ifs.if_flags & IFF_LOCAL) == 0 && gateway == 0) { - /* - * If we have an interface to a non-local network, - * we are a candidate for use as a gateway. - */ - gateway = 1; - rtdefault(); - } - lseek(kmem, ifs.if_name, 0); - read(kmem, name, sizeof (name)); - name[sizeof (name) - 1] = '\0'; - cp = index(name, '\0'); - *cp++ = ifs.if_unit + '0'; - *cp = '\0'; - ifp->int_name = malloc(strlen(name) + 1); + /* + * If we have a point-to-point link, we want to act + * as a supplier even if it's our only interface, + * as that's the only way our peer on the other end + * can tell that the link is up. + */ + if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0) + supplier = 1; + ifp->int_name = malloc(strlen(ifr->ifr_name) + 1); if (ifp->int_name == 0) { fprintf(stderr, "routed: ifinit: out of memory\n"); - goto bad; /* ??? */ + syslog(LOG_ERR, "routed: ifinit: out of memory\n"); + close(s); + return; } - strcpy(ifp->int_name, name); - ifp->int_addr = ifs.if_addr; - ifp->int_flags = ifs.if_flags | IFF_INTERFACE; - /* this works because broadaddr overlaps dstaddr */ - ifp->int_broadaddr = ifs.if_broadaddr; - ifp->int_net = ifs.if_net; - ifp->int_metric = 0; - ifp->int_next = ifnet; - ifnet = ifp; + strcpy(ifp->int_name, ifr->ifr_name); + *ifnext = ifp; + ifnext = &ifp->int_next; traceinit(ifp); addrouteforif(ifp); } if (externalinterfaces > 1 && supplier < 0) supplier = 1; - return; -bad: - sleep(60); - close(kmem), close(s); - execv("/etc/routed", argv0); - _exit(0177); + close(s); } +/* + * Add route for interface if not currently installed. + * Create route to other end if a point-to-point link, + * otherwise a route to this (sub)network. + * INTERNET SPECIFIC. + */ addrouteforif(ifp) - struct interface *ifp; + register struct interface *ifp; { struct sockaddr_in net; struct sockaddr *dst; - int state, metric; - struct rt_entry *rt; + int state; + register struct rt_entry *rt; if (ifp->int_flags & IFF_POINTOPOINT) dst = &ifp->int_dstaddr; else { bzero((char *)&net, sizeof (net)); net.sin_family = AF_INET; - net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); + net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY); dst = (struct sockaddr *)&net; } - rt = rtlookup(dst); - rtadd(dst, &ifp->int_addr, ifp->int_metric, - ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE)); + rt = rtfind(dst); + if (rt && + (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE) + return; if (rt) rtdelete(rt); + /* + * If interface on subnetted network, + * install route to network as well. + * This is meant for external viewers. + */ + if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) { + struct in_addr subnet; + + subnet = net.sin_addr; + net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); + rt = rtfind(dst); + if (rt == 0) + rtadd(dst, &ifp->int_addr, ifp->int_metric, + ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) | + RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET)); + else if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET)) == + (RTS_INTERNAL|RTS_SUBNET) && + ifp->int_metric < rt->rt_metric) + rtchange(rt, &rt->rt_router, ifp->int_metric); + net.sin_addr = subnet; + } + if (ifp->int_transitions++ > 0) + syslog(LOG_ERR, "re-installing interface %s", ifp->int_name); + state = ifp->int_flags & + (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET); + if (ifp->int_flags & IFF_POINTOPOINT && + (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr) & + ifp->int_netmask) != ifp->int_net) + state &= ~RTS_SUBNET; + if (ifp->int_flags & IFF_LOOPBACK) + state |= RTS_EXTERNAL; + rtadd(dst, &ifp->int_addr, ifp->int_metric, state); + if (ifp->int_flags & IFF_POINTOPOINT && foundloopback) + add_ptopt_localrt(ifp); +} + +/* + * Add route to local end of point-to-point using loopback. + * If a route to this network is being sent to neighbors on other nets, + * mark this route as subnet so we don't have to propagate it too. + */ +add_ptopt_localrt(ifp) + register struct interface *ifp; +{ + struct rt_entry *rt; + struct sockaddr *dst; + struct sockaddr_in net; + int state; + + state = RTS_INTERFACE | RTS_PASSIVE; + + /* look for route to logical network */ + bzero((char *)&net, sizeof (net)); + net.sin_family = AF_INET; + net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); + dst = (struct sockaddr *)&net; + rt = rtfind(dst); + if (rt && rt->rt_state & RTS_INTERNAL) + state |= RTS_SUBNET; + + dst = &ifp->int_addr; + if (rt = rtfind(dst)) { + if (rt && rt->rt_state & RTS_INTERFACE) + return; + rtdelete(rt); + } + rtadd(dst, &loopaddr, 1, state); } /* @@ -169,6 +312,8 @@ addrouteforif(ifp) * not marked passive are treated as if they were directly * connected -- they're added into the interface list so we'll * send them routing updates. + * + * PASSIVE ENTRIES AREN'T NEEDED OR USED ON GATEWAYS RUNNING EGP. */ gwkludge() { @@ -176,10 +321,10 @@ gwkludge() FILE *fp; char *type, *dname, *gname, *qual, buf[BUFSIZ]; struct interface *ifp; - int metric; + int metric, n; struct rt_entry route; - fp = fopen("/etc/gateways", "r"); + fp = fopen(_PATH_GATEWAYS, "r"); if (fp == NULL) return; qual = buf; @@ -189,17 +334,19 @@ gwkludge() bzero((char *)&dst, sizeof (dst)); bzero((char *)&gate, sizeof (gate)); bzero((char *)&route, sizeof(route)); - /* format: {net | host} XX gateway XX metric DD [passive]\n */ +/* format: {net | host} XX gateway XX metric DD [passive | external]\n */ #define readentry(fp) \ fscanf((fp), "%s %s gateway %s metric %d %s\n", \ type, dname, gname, &metric, qual) for (;;) { - if (readentry(fp) == EOF) + if ((n = readentry(fp)) == EOF) break; if (!getnetorhostname(type, dname, &dst)) continue; if (!gethostnameornumber(gname, &gate)) continue; + if (metric == 0) /* XXX */ + metric = 1; if (strcmp(qual, "passive") == 0) { /* * Passive entries aren't placed in our tables, @@ -218,6 +365,17 @@ gwkludge() (void) ioctl(s, SIOCADDRT, (char *)&route.rt_rt); continue; } + if (strcmp(qual, "external") == 0) { + /* + * Entries marked external are handled + * by other means, e.g. EGP, + * and are placed in our tables only + * to prevent overriding them + * with something else. + */ + rtadd(&dst, &gate, metric, RTS_EXTERNAL|RTS_PASSIVE); + continue; + } /* assume no duplicate entries */ externalinterfaces++; ifp = (struct interface *)malloc(sizeof (*ifp)); @@ -253,6 +411,15 @@ getnetorhostname(type, name, sin) if (np->n_addrtype != AF_INET) return (0); n = np->n_net; + /* + * getnetbyname returns right-adjusted value. + */ + if (n < 128) + n <<= IN_CLASSA_NSHIFT; + else if (n < 65536) + n <<= IN_CLASSB_NSHIFT; + else + n <<= IN_CLASSC_NSHIFT; } sin->sin_family = AF_INET; sin->sin_addr = inet_makeaddr(n, INADDR_ANY);