SOLVED: lo0 not in ioctl( SIOCGIFCONF )

Jens Rehsack rehsack at web.de
Tue Jul 22 07:16:48 UTC 2008


Brooks Davis wrote:
> On Mon, Jul 21, 2008 at 10:36:34PM +0000, Jens Rehsack wrote:
>> Brooks Davis wrote:
>>> On Mon, Jul 21, 2008 at 09:30:39PM +0000, Jens Rehsack wrote:
>>>> Brooks Davis wrote:
>>>>>> Hi,
>>>>>>
>>>>>> maybe this question is better asked in this list ...
>>>>>>
>>>>>> I was searching why ports/net/p5-Net-Interface was not working as
>>>>>> expected and found some reasons. Most of them I can answer by implementing
>>>>>> some test code as attached, but now I'm wondering why em0 is shown twice
>>>>>> and lo0 is not included.
>>>>>> The same situation on another machine ..
>>>>> The attachment didn't make it through.
>>>>>
>>>>> -- Brooks
>>>> Copy&Paste starts here ...
>>>> #include <stdio.h>
>>>> #include <stdlib.h>
>>>> #include <sys/socket.h>
>>>> #include <net/if.h>
>>>> #include <errno.h>
>>>> #include <strings.h>
>>>> #include <sys/ioctl.h>
>>>> #include <ifaddrs.h>
>>>>
>>>> #ifndef _SIZEOF_ADDR_IFREQ
>>>> #define	_SIZEOF_ADDR_IFREQ(ifr) \
>>>> 	((ifr).ifr_addr.sa_len > sizeof(struct sockaddr) ? \
>>>> 	 (sizeof(struct ifreq) - sizeof(struct sockaddr) + \
>>>> 	  (ifr).ifr_addr.sa_len) : sizeof(struct ifreq))
>>>> #endif
>>>>
>>>> int
>>>> main()
>>>> {
>>>>     struct ifconf ifc;
>>>>     struct ifreq *ifr, *lifr;
>>>>     int fd;
>>>>     unsigned int n;
>>>>
>>>>     fd = socket( AF_INET, SOCK_STREAM, 0 );
>>>>     bzero(&ifc, sizeof(ifc));
>>>>         n = 3;
>>>>         ifr = calloc( ifc.ifc_len, sizeof(*ifr) );
>>>>         do
>>>>         {
>>>>             n *= 2;
>>>>             ifr = realloc( ifr, sizeof(*ifr) * n );
>>>>             bzero( ifr, sizeof(*ifr) * n );
>>>>             ifc.ifc_req = ifr;
>>>>             ifc.ifc_len = n * sizeof(*ifr);
>>>>         } while( ( ioctl( fd, SIOCGIFCONF, &ifc ) == -1 ) || ( 
>>>> ifc.ifc_len == n * sizeof(*ifr)) );
>>> There are several problems with this loop.  First, icoctl won't return
>>> an error in the overflow case because that's not how SIOCGIFCONF works.
>>> SIOCGIFCONF is badly designed in a number of ways, but that's how it
>>> is.  Second, checking that the array is completely full isn't at all
>>> reliable because what is returned is actually ifreq structures which
>>> might or might not vary in length as they contain addresses.  Thus you
>>> need <=.  Third, you should start by allocating a significant amount of
>>> space.  Yes, your algorithm is O(sqrt(n)), but allocating a larger
>>> value has effectively no cost so you might as well save some system calls
>>> on average.
>> Thanks - that was the information I miss. I'll try tomorrow (it's slightly 
>> late here) and send back the result.
>> Using <= should produce an endless loop, but maybe checking if ifc.ifc_len 
>> <= (n/2) * sizeof(*ifr) could bring wanted results ...
> 
> Oops, you're right.  Actually, the condition to check is probably
> (n*sizeof(*ifr) - ifc.ifc_len < sizeof(*ifr)).  Actually, since the size
> of the returned values aren't actually a multiple of sizeof(*ifr), I'd
> probably switch to allocating a multiple of 4k.

Actually, because there're very different sizes of sockaddr's (sockaddr_in, 
sockaddr_in6, ...), I require at least a page must be left over.
Because of other OS may support return of errors in overflow, I didn't 
remove the check - finally it must run on AIX, Windows and Linux, too.

>>>>     lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
>>>>
>>>>     while (ifr < lifr) >     {
>>>>         printf( "%s\n", ifr->ifr_name );
>>>>         ifr = (struct ifreq *)(((char *)ifr) + _SIZEOF_ADDR_IFREQ(*ifr));
>>>>     }
>>> This loop has two problems.  First, the ifr's are variable length so you
>>> immediately go off into the weeds.
>> The _SIZEOF_ADDR_IFREQ macro should handle that correctly, shouldn't it?
> 
> Right here as well.

Finally - I must enhance this using SA_LEN if available to support systems 
without sa_len member support. I'll try it in office with our linux machines 
there, because I don't have any penguins at home ;)

>>>  Second, there is at least one per
>>> interface and one per address so you to keep track of the last interface
>>> name and not repeat them.
>> Good point - if it's sure in this order, this is a good way to handle it.
> 
> It is in the current implementation and it's hard to imaging that we'd
> break that.

By the way, because I'm looking for interfaces, I skip everything which is 
no AF_LINK - should work, too (and does for my test-machines ...).

Final question: would it make sense to submit a patch against 
ports/net/p5-Net-Interface using this knowledge to unbreak the port, or must 
I submit the patch to CPAN and hope, that it will be committed fastly?

/Jens


More information about the freebsd-net mailing list