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