X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/f804e0463c414935ba61eb58e1fc67b06fdc82ca..4fad5a6eeb6297fea5e2a7c10ee0fe5db9cd1192:/usr/src/sbin/routed/startup.c diff --git a/usr/src/sbin/routed/startup.c b/usr/src/sbin/routed/startup.c index f6f01fe708..5f4d24424f 100644 --- a/usr/src/sbin/routed/startup.c +++ b/usr/src/sbin/routed/startup.c @@ -1,6 +1,12 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + #ifndef lint -static char sccsid[] = "@(#)startup.c 4.6 (Berkeley) %G%"; -#endif +static char sccsid[] = "@(#)startup.c 5.4 (Berkeley) %G%"; +#endif not lint /* * Routing Table Management Daemon @@ -8,117 +14,129 @@ static char sccsid[] = "@(#)startup.c 4.6 (Berkeley) %G%"; #include "defs.h" #include #include -#include +#include struct interface *ifnet; -int kmem = -1; 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" }, - { "" }, -}; /* - * 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, n; + char buf[BUFSIZ]; + 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"); + exit(1); } + 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 (0); + } + 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) { + for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) { + bzero((char *)&ifs, sizeof(ifs)); + ifs.int_addr = ifr->ifr_addr; + ifreq = *ifr; + if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) { + syslog(LOG_ERR, "ioctl (get interface flags)"); + continue; + } + ifs.int_flags = ifreq.ifr_flags | IFF_INTERFACE; + /* no one cares about software loopback interfaces */ + if (ifs.int_flags & IFF_LOOPBACK) + continue; + 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)) + if (if_ifwithaddr(&ifs.int_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; - /* no one cares about software loopback interfaces */ - if (ifs.if_net == LOOPBACKNET) + if (ifs.int_flags & IFF_POINTOPOINT) { + if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) { + syslog(LOG_ERR, "ioctl (get dstaddr)"); + continue; + } + ifs.int_dstaddr = ifreq.ifr_dstaddr; + } + if (ifs.int_flags & IFF_BROADCAST) { + if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { + syslog(LOG_ERR, "ioctl (get broadaddr)"); + continue; + } + ifs.int_broadaddr = ifreq.ifr_broadaddr; + } + if (ioctl(s, SIOCGIFMETRIC, (char *)&ifreq) < 0) + syslog(LOG_ERR, "ioctl (get metric)"); + else + ifs.int_metric = ifreq.ifr_metric; + if (ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) < 0) { + syslog(LOG_ERR, "ioctl (get netmask)"); 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_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; /* ??? */ } - 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; + strcpy(ifp->int_name, ifr->ifr_name); ifp->int_next = ifnet; ifnet = ifp; traceinit(ifp); @@ -126,6 +144,7 @@ ifinit() } if (externalinterfaces > 1 && supplier < 0) supplier = 1; + close(s); return; bad: sleep(60); @@ -134,6 +153,12 @@ bad: _exit(0177); } +/* + * 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; { @@ -147,14 +172,33 @@ addrouteforif(ifp) 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)) + return; if (rt) rtdelete(rt); + if (ifp->int_transitions++ > 0) + syslog(LOG_ERR, "re-installing interface %s", ifp->int_name); + rtadd(dst, &ifp->int_addr, ifp->int_metric, + ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE|IFF_SUBNET)); + + /* + * 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) { + net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); + rt = rtfind(dst); + if (rt && (rt->rt_state & RTS_INTERFACE)) + return; + rtadd(dst, &ifp->int_addr, ifp->int_metric, + (ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE) | + RTS_INTERNAL)); + } } /* @@ -218,6 +262,16 @@ 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); + } /* assume no duplicate entries */ externalinterfaces++; ifp = (struct interface *)malloc(sizeof (*ifp)); @@ -253,6 +307,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);