ports/129660: net/mpd does not enumerate all interfaces when their number is too large

Etienne na.eb.ml at gmail.com
Mon Dec 15 15:40:05 UTC 2008


>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 at 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:



More information about the freebsd-ports-bugs mailing list