Bug#219108: [PATCH] using an interface without IP address

Chris Hanson <[email protected]>
Newsgroups gmane.comp.security.libnet
Message-ID <[email protected]>
OK, I've made an appropriate patch to fix the problem, which is
attached to this message.  This is a patch against version 1.1.1.

I've tested it and as far as I can tell it fixes the problem.  Feel
free to massage as needed to fit your style.

The next upload of the Debian package will contain this patch, which
will close the two bugs filed against it.

Chris
libnet_if_addr.c-patch (text/plain, 7.1 KB)
--- libnet/src/libnet_if_addr.c	2003-10-30 18:26:33.000000000 -0500
+++ ../libnet-1.1.1rel/src/libnet_if_addr.c	2004-02-27 12:35:28.000000000 -0500
@@ -47,6 +47,15 @@
 #define MAX_IPADDR 32
 
 #if !(__WIN32__)
+
+static struct ifreq * get_interface_list (int, int8_t *, unsigned int *);
+static struct ifreq * conf_interface_list (int, int8_t *, unsigned int *);
+#ifdef __linux__
+static struct ifreq * proc_interface_list (int8_t *, unsigned int *);
+static void discard_line (FILE *);
+static int proc_interface_name (FILE *, struct ifreq *);
+#endif
+
 /*
  *  Return the interface list
  */
@@ -58,11 +67,12 @@
 #ifdef HAVE_SOCKADDR_SA_LEN
     register int n;
 #endif
+    struct ifreq * ifcs;
+    unsigned int n_ifcs;
     register struct ifreq *ifrp, *ifend, *ifnext, *mp;
     register struct sockaddr_in *sin;
     register struct libnet_ifaddr_list *al;
-    struct ifconf ifc;
-    struct ifreq ibuf[MAX_IPADDR], ifr;
+    struct ifreq ifr;
     int8_t device[sizeof(ifr.ifr_name)];
     static struct libnet_ifaddr_list ifaddrlist[MAX_IPADDR];
 
@@ -73,20 +83,14 @@
         return (-1);
     }
 
-	memset(&ifc, 0, sizeof(ifc));
-	ifc.ifc_len = sizeof(ibuf);
-    ifc.ifc_buf = (caddr_t)ibuf;
-
-    if (ioctl(fd,
-            SIOCGIFCONF,
-            (int8_t *)&ifc) < 0 || ifc.ifc_len < sizeof(struct ifreq))
-    {
-        snprintf(errbuf, LIBNET_ERRBUF_SIZE, "SIOCGIFCONF: %s", strerror(errno));
-        close(fd);
+    ifcs = (get_interface_list (fd, errbuf, (&n_ifcs)));
+    if (ifcs == 0)
+      {
+        close (fd);
         return (-1);
-    }
-    ifrp = ibuf;
-    ifend = (struct ifreq *)((int8_t *)ibuf + ifc.ifc_len);
+      }
+    ifrp = ifcs;
+    ifend = (ifcs + n_ifcs);
 
     al = ifaddrlist;
     mp = NULL;
@@ -124,6 +128,7 @@
                     (int)sizeof(ifr.ifr_name),
                      ifr.ifr_name,
                      strerror(errno));
+	    free (ifcs);
             close(fd);
             return (-1);
         }
@@ -143,15 +148,25 @@
         device[sizeof(device) - 1] = '\0';
 
         if (ioctl(fd, SIOCGIFADDR, (int8_t *)&ifr) < 0)
-        {
-            snprintf(errbuf, LIBNET_ERRBUF_SIZE,
-				    "SIOCGIFADDR: %s: %s", device, strerror(errno));
-            close(fd);
-            return (-1);
-        }
-    
-        sin = (struct sockaddr_in *)&ifr.ifr_addr;
-        al->addr = sin->sin_addr.s_addr;
+	  {
+	    if (errno == EADDRNOTAVAIL)
+	      {
+		al->addr = INADDR_NONE;
+	      }
+	    else
+	      {
+		snprintf(errbuf, LIBNET_ERRBUF_SIZE,
+			 "SIOCGIFADDR: %s: %s", device, strerror(errno));
+		free (ifcs);
+		close(fd);
+		return (-1);
+	      }
+	  }
+	else
+	  {
+	    sin = (struct sockaddr_in *)&ifr.ifr_addr;
+	    al->addr = sin->sin_addr.s_addr;
+	  }
         /*
          *  Replaced savestr() with strdup().  -- MDS
          */
@@ -159,11 +174,208 @@
         ++al;
         ++nipaddr;
     }
+    free (ifcs);
     close(fd);
 
     *ipaddrp = ifaddrlist;
     return (nipaddr);
 }
+
+/* Use /proc/net/dev if available, since that will give us a list of
+   all of the interfaces.  Otherwise use SIOCGIFCONF, which will at
+   least give us the interfaces that are up.  */
+
+static struct ifreq *
+get_interface_list (int fd, int8_t * errbuf, unsigned int * n_ifcs_return)
+{
+#ifdef __linux__
+  struct ifreq * ifcs = (proc_interface_list (errbuf, n_ifcs_return));
+  return
+    ((ifcs == 0)
+     ? (conf_interface_list (fd, errbuf, n_ifcs_return))
+     : ifcs);
+#else
+  return (conf_interface_list (fd, errbuf, n_ifcs_return));
+#endif
+}
+
+static struct ifreq *
+conf_interface_list (int fd, int8_t * errbuf, unsigned int * n_ifcs_return)
+{
+  struct ifconf ifc;
+  unsigned int n_ifcs = 4;
+  unsigned int n_bytes = ((sizeof (struct ifreq)) * n_ifcs);
+
+  (ifc . ifc_len) = n_bytes;
+  (ifc . ifc_req) = (malloc (n_bytes));
+  if ((ifc . ifc_req) == 0)
+    {
+      snprintf (errbuf, LIBNET_ERRBUF_SIZE, "Can't malloc() interface list.");
+      return (0);
+    }
+  while (1)
+    {
+      if ((ioctl (fd, SIOCGIFCONF, (&ifc))) < 0)
+	{
+	  snprintf (errbuf, LIBNET_ERRBUF_SIZE, "SIOCGIFCONF: %s",
+		    (strerror (errno)));
+	  free (ifc . ifc_req);
+	  return (0);
+	}
+      if ((ifc . ifc_len) < n_bytes)
+	break;
+      n_ifcs *= 2;
+      n_bytes = ((sizeof (struct ifreq)) * n_ifcs);
+      (ifc . ifc_req) = (realloc ((ifc . ifc_req), n_bytes));
+      if ((ifc . ifc_req) == 0)
+	{
+	  snprintf (errbuf, LIBNET_ERRBUF_SIZE,
+		    "Can't realloc() interface list.");
+	  return (0);
+	}
+    }
+
+  (*n_ifcs_return) = ((ifc . ifc_len) / (sizeof (struct ifreq)));
+  return (ifc . ifc_req);
+}
+
+#ifdef __linux__
+
+static struct ifreq *
+proc_interface_list (int8_t * errbuf, unsigned int * n_ifcs_return)
+{
+  FILE * s = (fopen ("/proc/net/dev", "r"));
+  if (s == 0)
+    {
+      snprintf (errbuf, LIBNET_ERRBUF_SIZE, "Unable to open /proc/net/dev");
+      return (0);
+    }
+  discard_line (s);
+  discard_line (s);
+  {
+    unsigned int i = 0;
+    unsigned int n = 4;
+    struct ifreq * ifcs;
+    struct ifreq ifc;
+
+    ifcs = (malloc ((sizeof (struct ifreq)) * n));
+    if (ifcs == 0)
+      {
+	snprintf (errbuf, LIBNET_ERRBUF_SIZE,
+		  "Can't malloc() interface list.");
+	return (0);
+      }
+    while (proc_interface_name (s, (&ifc)))
+      {
+	if (i == n)
+	  {
+	    n *= 2;
+	    ifcs = (realloc (ifcs, ((sizeof (struct ifreq)) * n)));
+	    if (ifcs == 0)
+	      {
+		snprintf (errbuf, LIBNET_ERRBUF_SIZE,
+			  "Can't realloc() interface list.");
+		return (0);
+	      }
+	  }
+	(ifcs[i++]) = ifc;
+      }
+    fclose (s);
+    (*n_ifcs_return) = i;
+    return (ifcs);
+  }
+}
+
+static void
+discard_line (FILE * s)
+{
+  while (1)
+    {
+      int c = (getc (s));
+      if ((c == EOF) || (c == '\n'))
+	break;
+    }
+}
+
+#define PIN_GETC(c, s)							\
+{									\
+  c = (getc (s));							\
+  if (c == EOF)								\
+    return (0);								\
+  if (c == '\0')							\
+    {									\
+      discard_line (s);							\
+      goto restart;							\
+    }									\
+}
+
+#define PIN_ACCUM(c)							\
+{									\
+  if (i < n)								\
+    (name[i++]) = (c);							\
+  else									\
+    {									\
+      discard_line (s);							\
+      goto restart;							\
+    }									\
+}
+
+static int
+proc_interface_name (FILE * s, struct ifreq * ifc)
+{
+  char * name = (ifc -> ifr_name);
+  unsigned int n = (sizeof (ifc -> ifr_name));
+  unsigned int i;
+  int c;
+
+ restart:
+  do
+    {
+      PIN_GETC (c, s);
+    }
+  while (isspace (c));
+  i = 0;
+  while (1)
+    {
+      PIN_ACCUM (c);
+      PIN_GETC (c, s);
+      if (isspace (c))
+	{
+	  if (c != '\n')
+	    discard_line (s);
+	  break;
+	}
+      if (c == ':')
+	{
+	  if (i < n)
+	    /* Might be part of an alias; check.  */
+	    {
+	      unsigned int saved_i = i;
+	      while (1)
+		{
+		  PIN_ACCUM (c);
+		  PIN_GETC (c, s);
+		  if (!isdigit (c))
+		    {
+		      if (c != ':')
+			/* Not an alias; first colon was name terminator.  */
+			i = saved_i;
+		      if (c != '\n')
+			discard_line (s);
+		      break;
+		    }
+		}
+	    }
+	  break;
+	}
+    }
+  if (i < n)
+    (name[i]) = '\0';
+  return (1);
+}
+
+#endif /* __linux__ */
+
 #else
 /* From tcptraceroute, convert a numeric IP address to a string */
 #define IPTOSBUFFERS    12
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.