beau@ultra.UUCP (Beau James {Manager - SW Development - Ultra Networks}) (09/22/89)
This is a followup to a message I posted two weeks ago regarding a problem with the 4.3-tahoe BSD route daemon (and also SunOS through 4.0.3). We've identified the bug and at least a partial fix. Symptom recap: Remote network gateways identified to routed as "active" gateways in the /etc/gateways file are entered on the local machine as gateways to destination net "0.0.0.0" instead of the destination network named in the /etc/gateways file. That invalid information is then broadcast by the local system's route daemon. Problem identified: The routine "gwkludge()" in routed/startup.c processes the entries from the /etc/gateways file. For active gateways, it ends up adding the route by calling the subroutine "addrouteforif()", in the same module. "addrouteforif()" is also called by "ifinit()" when the hardware interfaces found by the kernel are added to the route daemon's tables. It appears that when "ifinit()" and "addrouteforif()" were extended to handle subnetted networks, several new fields were added to the (struct interface). However, "gwkludge()" was not modified to correctly initialize those fields before calling "addrouteforif()". Partial (?) bugfix: The following change to the bottom of "gwkludge()" will result in the proper destination network address being entered into the routing tables: /* 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); ADD--> ifp->int_subnet = ifp->int_net; 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); This change has been tested on a non-subnetted Ethernet environment. There are two additional fields in the (struct interface) that probably should be initialized to non-zero values, but it is not clear to me what the proper initialization is, for remote gateways. The fields are: ifp->int_netmask ifp->int_subnetmask For interfaces found by the kernel, "ifinit()" uses an ioctl(SIOCGIFNETMASK) and a series of tests to set these fields: 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; If anyone out there has better insight as to the proper way to initialize these netmasks for the case of remote gateways, please pass it along. Thanks, Beau James beau@Ultra.COM Ultra Network Technologies {sun,ames}!ultra.com!beau