Return to BSD News archive
Xref: sserve comp.os.386bsd.questions:4909 comp.os.386bsd.bugs:1341 Newsgroups: comp.os.386bsd.questions,comp.os.386bsd.bugs Path: sserve!newshost.anu.edu.au!munnari.oz.au!news.Hawaii.Edu!ames!agate!doc.ic.ac.uk!pipex!sunic!ugle.unit.no!ugle.unit.no!jarle From: jarle@idt.unit.no Subject: Re: bootpd problem In-Reply-To: frodo@idt.unit.no's message of Fri, 3 Sep 93 15:32:14 GMT Message-ID: <JARLE.93Sep8011611@villrips.idt.unit.no> Sender: news@ugle.unit.no (NetNews Administrator) Organization: Free Hardware Foundation, UnLtd. References: <1993Sep3.153214.28893@ugle.unit.no> Date: 8 Sep 93 01:16:11 Lines: 84 In article <1993Sep3.153214.28893@ugle.unit.no>, frodo@idt.unit.no (Frode Bergh) writes: fb> Has anybody succeded in using the bootpd ver. 2.1 fb> under 386BSD 0.1.7 ? Okay, we have found a bug and a fix. This is a fix to stop bootpd from erronously dropping packets. It corrects for ifreq structures with variable lengths (as returned from ioctl(?,SIOCGIFCONF,?)) and does only compare the bootp reply packet destination address with AF_INET type addresses. (In case the diff is done the wrong way, the new code is the one with the sockaddr pointer *sa and the AF_INET if-statement.) The fix seems to work OK on our 386bsd-0.1 machine with 3 ethernet interfaces and a approx. 40 clients on one segment and 10 on another one. Enjoy, (if possible)! 848c848,850 < --- > register struct sockaddr *sa; > struct sockaddr_in *sin; > 851,856c853,871 < for (; len > 0; len -= sizeof(ifreq[0]), ifrq++) { < m = nmatch(&dst, &((struct sockaddr_in *) < (&ifrq->ifr_addr))->sin_addr); < if (m > maxmatch) { < maxmatch = m; < ifrmax = ifrq; --- > > while ( len > 0 ) { > sa = (struct sockaddr *) &ifrq->ifr_addr; > if (sa->sa_family == AF_INET) { > sin = (struct sockaddr_in *)sa; > m = nmatch(&dst, &sin->sin_addr); > if (m > maxmatch) { > maxmatch = m; > ifrmax = ifrq; > } > } > if (sa->sa_len > sizeof(*sa)) { > len -= sizeof(*ifrq); > len -= sa->sa_len - sizeof(*sa); > ifrq = (struct ifreq *) (sa->sa_len + (caddr_t)&ifrq->ifr_addr); > } > else { > len -= sizeof(*ifrq); > ifrq++; Explanation for the really curious: The cause of the bug is really a misunderstanding of what ioctl(?,SIOCGIFCONF,?) does. Basically, it fills in an array of ifreq structures with information about the configured network interfaces. As long as the sockaddrs (there may be more than one) of an interface fits into an ifreq structure everything is OK (almost). However, if one sockaddr doesn't fit, the ioctl function will step its pointers in a non-sizeof(ifreq) multiple fashion to account for the extra space needed. The original bootpd does not account for this, and as soon as one sockaddr busts the space limit, everything will be misaligned and bootpd will see bogus IP-addresses. This again implies that no IP-address (sub)matches are found. On our 386bsd-0.1 machine the first ifreq in the array turned out to be some AF_LINK type address, which length was longer than the standard "struct sockaddr_in". This led bootpd to think that the longest match for a network to put the reply packet onto was 0. Bootpd then could not find a gateway for the packet, and the network interfaces for the machine didn't match the packet's address at all, hence it dropped the packet. The new code corrects for return structures with nonstandard lengths and only compares AF_INET type addresses. If I have really misunderstood the matters involved, please send corrections to "jarle@idt.unit.no" -jarle ---- "Don't get suckered in by the comments -- they can be terribly misleading. Debug only code." -- Dave Storer