*BSD News Article 20588


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