Date: Mon, 15 Dec 2008 15:34:07 GMT From: Etienne <na.eb.ml@gmail.com> To: freebsd-gnats-submit@FreeBSD.org Subject: ports/129660: net/mpd does not enumerate all interfaces when their number is too large Message-ID: <200812151534.mBFFY7SV094822@www.freebsd.org> Resent-Message-ID: <200812151540.mBFFe4PM020365@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 129660 >Category: ports >Synopsis: net/mpd does not enumerate all interfaces when their number is too large >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-ports-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Mon Dec 15 15:40:04 UTC 2008 >Closed-Date: >Last-Modified: >Originator: Etienne >Release: 7.0 >Organization: NETASQ >Environment: FreeBSD host.localdomain 7.0-STABLE FreeBSD 7.0-STABLE #0: Thu Aug 14 14:05:02 CEST 2008 root@host.localdomain:/usr/obj/usr/src/sys/GENERIC i386 >Description: The problem exists on mpd-5.2 and prior. When the number of interfaces is too large the interface enumeration does not work very well (it misses some interfaces). For instance, this leads, when there is too many pptp client connected to the mpd server, to not send the arp annoucement of newly added clients. This is because "ioctl(s, SIOCGIFCONF, ...)" is done once with a too small fixed size for the result buffer ("sizeof(struct ifreq) * MAX_INTERFACES" (= 32*2048)). Moreover, the size used by the return of this ioctl is not directly bound to the number of interfaces (so MAX_INTERFACES has not a real meaning here). A better way to do this is to perform the call with an arbitrary buffer size and increase the size if the call does not succeed. As attachment, a patch to apply on mpd-5.2 which modify the code in a such way (buffsize and buffmaxsize need to be tuned). >How-To-Repeat: >Fix: Patch attached with submission follows: --- src/util.c.orig 2008-12-15 10:41:00.000000000 +0100 +++ src/util.c 2008-12-15 11:42:33.000000000 +0100 @@ -1261,6 +1261,7 @@ struct ifreq *ifr, *ifend; struct ifreq ifreq; struct ifconf ifc; + unsigned int buffsize = IFCONF_BUFFSIZE; /* use cached IP to reduce number of syscalls */ if (ifname == NULL && have_nipa) { @@ -1291,14 +1292,28 @@ /* If simple is not enouth try complex call */ if (ipa.s_addr == 0) { struct ifreq *ifs; - ifc.ifc_len = sizeof(struct ifreq) * MAX_INTERFACES; - ifc.ifc_req = ifs = Malloc(MB_UTIL, ifc.ifc_len); - if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { - Freee(ifs); - if (errno != ENXIO) - Perror("%s: ioctl(SIOCGIFCONF)", __FUNCTION__); - close(s); - return(-1); + while (1) { + ifc.ifc_len = buffsize; + ifc.ifc_req = ifs = Malloc(MB_UTIL, ifc.ifc_len); + if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { + Freee(ifs); + if (errno != ENXIO) + Perror("%s: ioctl(SIOCGIFCONF)", __FUNCTION__); + close(s); + return(-1); + } + + /* if used size is too close to allocated size retry with a larger buffer */ + if (ifc.ifc_len + 64 < buffsize) + break; + + Freee(ifs); + if (buffsize >= IFCONF_BUFFMAXSIZE) { + Log(LG_ERR, ("%s: Max buffer size reached", __FUNCTION__)); + close(s); + return(-1); + } + buffsize *= 2; } for (ifend = (struct ifreq *)(void *)(ifc.ifc_buf + ifc.ifc_len), @@ -1360,6 +1375,7 @@ struct ifreq ifreq; struct ifconf ifc; struct ifreq *ifs; + unsigned int buffsize = IFCONF_BUFFSIZE; static struct sockaddr_dl nhwaddr; static int have_nhwaddr = 0; @@ -1377,13 +1393,27 @@ return(-1); } - ifc.ifc_len = sizeof(struct ifreq) * MAX_INTERFACES; - ifc.ifc_req = ifs = Malloc(MB_UTIL, ifc.ifc_len); - if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { - Freee(ifs); - Perror("%s: ioctl(SIOCGIFCONF)", __FUNCTION__); - close(s); - return(-1); + while (1) { + ifc.ifc_len = buffsize; + ifc.ifc_req = ifs = Malloc(MB_UTIL, ifc.ifc_len); + if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { + Freee(ifs); + Perror("%s: ioctl(SIOCGIFCONF)", __FUNCTION__); + close(s); + return(-1); + } + + /* if used size is too close to allocated size retry with a larger buffer */ + if (ifc.ifc_len + 64 < buffsize) + break; + + Freee(ifs); + if (buffsize >= IFCONF_BUFFMAXSIZE) { + Log(LG_ERR, ("%s: Max buffer size reached", __FUNCTION__)); + close(s); + return(-1); + } + buffsize *= 2; } /* --- src/util.h.orig 2008-12-15 10:41:00.000000000 +0100 +++ src/util.h 2008-12-15 11:42:31.000000000 +0100 @@ -36,7 +36,8 @@ #define MAX_U_INT32 0xffffffffU - #define MAX_INTERFACES 2048 + #define IFCONF_BUFFSIZE (1<<14) + #define IFCONF_BUFFMAXSIZE (IFCONF_BUFFSIZE << 6) struct configfile { char *label; >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200812151534.mBFFY7SV094822>