diff options
author | svn2git <svn2git@FreeBSD.org> | 1994-07-01 08:00:00 +0000 |
---|---|---|
committer | svn2git <svn2git@FreeBSD.org> | 1994-07-01 08:00:00 +0000 |
commit | 5e0e9b99dc3fc0ecd49d929db0d57c784b66f481 (patch) | |
tree | e779b5a6edddbb949b7990751b12d6f25304ba86 /usr.sbin/routed/startup.c | |
parent | a16f65c7d117419bd266c28a1901ef129a337569 (diff) |
Diffstat (limited to 'usr.sbin/routed/startup.c')
-rw-r--r-- | usr.sbin/routed/startup.c | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/usr.sbin/routed/startup.c b/usr.sbin/routed/startup.c new file mode 100644 index 000000000000..de4d58da2f45 --- /dev/null +++ b/usr.sbin/routed/startup.c @@ -0,0 +1,486 @@ +/* + * Copyright (c) 1983, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)startup.c 5.19 (Berkeley) 2/28/91"; +#endif /* not lint */ + +/* + * Routing Table Management Daemon + */ +#include "defs.h" +#include <sys/ioctl.h> +#include <net/if.h> +#include <syslog.h> +#include <stdlib.h> +#include "pathnames.h" + +struct interface *ifnet; +struct interface **ifnext = &ifnet; +int lookforinterfaces = 1; +int externalinterfaces = 0; /* # of remote and local interfaces */ +int foundloopback; /* valid flag for loopaddr */ +struct sockaddr loopaddr; /* our address on loopback */ + +/* + * 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 ifs, *ifp; + int s; + char buf[BUFSIZ], *cp, *cplim; + struct ifconf ifc; + struct ifreq ifreq, *ifr; + struct sockaddr_in *sin; + u_long i; + + 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; +#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_KERNELPUN) | IFF_INTERFACE; + if ((ifs.int_flags & IFF_UP) == 0 || + ifr->ifr_addr.sa_family == AF_UNSPEC) { + lookforinterfaces = 1; + continue; + } + /* argh, this'll have to change sometime */ + 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; + 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.int_flags & IFF_LOOPBACK) == 0 && + ((ifs.int_flags & IFF_POINTOPOINT) == 0 || + if_ifwithaddr(&ifs.int_dstaddr) == 0)) + externalinterfaces++; + /* + * 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"); + syslog(LOG_ERR, "routed: ifinit: out of memory\n"); + close(s); + return; + } + strcpy(ifp->int_name, ifr->ifr_name); + *ifnext = ifp; + ifnext = &ifp->int_next; + traceinit(ifp); + addrouteforif(ifp); + } + if (externalinterfaces > 1 && supplier < 0) + supplier = 1; + 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) + register struct interface *ifp; +{ + struct sockaddr_in net; + struct sockaddr *dst; + 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_subnet, INADDR_ANY); + dst = (struct sockaddr *)&net; + } + 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); +} + +/* + * As a concession to the ARPANET we read a list of gateways + * from /etc/gateways and add them to our tables. This file + * exists at each ARPANET gateway and indicates a set of ``remote'' + * gateways (i.e. a gateway which we can't immediately determine + * if it's present or not as we can do for those directly connected + * at the hardware level). If a gateway is marked ``passive'' + * in the file, then we assume it doesn't have a routing process + * of our design and simply assume it's always present. Those + * 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() +{ + struct sockaddr_in dst, gate; + FILE *fp; + char *type, *dname, *gname, *qual, buf[BUFSIZ]; + struct interface *ifp; + int metric, n; + struct rt_entry route; + + fp = fopen(_PATH_GATEWAYS, "r"); + if (fp == NULL) + return; + qual = buf; + dname = buf + 64; + gname = buf + ((BUFSIZ - 64) / 3); + type = buf + (((BUFSIZ - 64) * 2) / 3); + bzero((char *)&dst, sizeof (dst)); + bzero((char *)&gate, sizeof (gate)); + bzero((char *)&route, sizeof(route)); +/* 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 ((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, + * only the kernel's, so we don't copy all of the + * external routing information within a net. + * Internal machines should use the default + * route to a suitable gateway (like us). + */ + route.rt_dst = *(struct sockaddr *) &dst; + route.rt_router = *(struct sockaddr *) &gate; + route.rt_flags = RTF_UP; + if (strcmp(type, "host") == 0) + route.rt_flags |= RTF_HOST; + if (metric) + route.rt_flags |= RTF_GATEWAY; + (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)); + bzero((char *)ifp, sizeof (*ifp)); + ifp->int_flags = IFF_REMOTE; + /* can't identify broadcast capability */ + ifp->int_net = inet_netof(dst.sin_addr); + if (strcmp(type, "host") == 0) { + ifp->int_flags |= IFF_POINTOPOINT; + ifp->int_dstaddr = *((struct sockaddr *)&dst); + } + ifp->int_addr = *((struct sockaddr *)&gate); + ifp->int_metric = metric; + ifp->int_next = ifnet; + ifnet = ifp; + addrouteforif(ifp); + } + fclose(fp); +} + +getnetorhostname(type, name, sin) + char *type, *name; + struct sockaddr_in *sin; +{ + + if (strcmp(type, "net") == 0) { + struct netent *np = getnetbyname(name); + int n; + + if (np == 0) + n = inet_network(name); + else { + 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); + return (1); + } + if (strcmp(type, "host") == 0) { + struct hostent *hp = gethostbyname(name); + + if (hp == 0) + sin->sin_addr.s_addr = inet_addr(name); + else { + if (hp->h_addrtype != AF_INET) + return (0); + bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); + } + sin->sin_family = AF_INET; + return (1); + } + return (0); +} + +gethostnameornumber(name, sin) + char *name; + struct sockaddr_in *sin; +{ + struct hostent *hp; + + hp = gethostbyname(name); + if (hp) { + bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); + sin->sin_family = hp->h_addrtype; + return (1); + } + sin->sin_addr.s_addr = inet_addr(name); + sin->sin_family = AF_INET; + return (sin->sin_addr.s_addr != -1); +} |