Imported Upstream version 0.1.17
[platform/upstream/libnice.git] / agent / interfaces.c
index f3f6d7f..95e64a8 100644 (file)
 
 #endif /* G_OS_UNIX */
 
+#ifdef IGNORED_IFACE_PREFIX
+static const gchar *ignored_iface_prefix_list[] = {
+  IGNORED_IFACE_PREFIX,
+  NULL
+};
+#endif
+
 #if (defined(G_OS_UNIX) && defined(HAVE_GETIFADDRS)) || defined(G_OS_WIN32)
 /* Works on both UNIX and Windows. Magic! */
 static gchar *
@@ -99,6 +106,58 @@ sockaddr_to_string (const struct sockaddr *addr)
 
 #ifdef G_OS_UNIX
 
+static GList *
+get_local_interfaces_ioctl (void)
+{
+  GList *interfaces = NULL;
+  gint sockfd;
+  gint size = 0;
+  struct ifreq *ifr;
+  struct ifconf ifc;
+
+  if ((sockfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
+    nice_debug ("error : Cannot open socket to retrieve interface list");
+    return NULL;
+  }
+
+  ifc.ifc_len = 0;
+  ifc.ifc_req = NULL;
+
+  /* Loop and get each interface the system has, one by one... */
+  do {
+    size += sizeof (struct ifreq);
+    /* realloc buffer size until no overflow occurs  */
+    if (NULL == (ifc.ifc_req = realloc (ifc.ifc_req, size))) {
+      nice_debug ("Error : Out of memory while allocation interface"
+          "configuration structure");
+      close (sockfd);
+      return NULL;
+    }
+    ifc.ifc_len = size;
+
+    if (ioctl (sockfd, SIOCGIFCONF, &ifc)) {
+      perror ("ioctl SIOCFIFCONF");
+      close (sockfd);
+      free (ifc.ifc_req);
+      return NULL;
+    }
+  } while (size <= ifc.ifc_len);
+
+
+  /* Loop throught the interface list and get the IP address of each IF */
+  for (ifr = ifc.ifc_req;
+       (gchar *) ifr < (gchar *) ifc.ifc_req + ifc.ifc_len;
+       ++ifr) {
+    nice_debug ("Found interface : %s", ifr->ifr_name);
+    interfaces = g_list_prepend (interfaces, g_strdup (ifr->ifr_name));
+  }
+
+  free (ifc.ifc_req);
+  close (sockfd);
+
+  return interfaces;
+}
+
 #ifdef HAVE_GETIFADDRS
 
 GList *
@@ -108,7 +167,9 @@ nice_interfaces_get_local_interfaces (void)
   struct ifaddrs *ifa, *results;
 
   if (getifaddrs (&results) < 0) {
-    return NULL;
+    nice_debug ("Failed to retrieve list of network interfaces with \"getifaddrs\": %s."
+      "Trying to use fallback ...", strerror (errno));
+    return get_local_interfaces_ioctl ();
   }
 
   /* Loop and get each interface the system has, one by one... */
@@ -136,14 +197,60 @@ nice_interfaces_get_local_interfaces (void)
 GList *
 nice_interfaces_get_local_interfaces (void)
 {
-  GList *interfaces = NULL;
+  return get_local_interfaces_ioctl ();
+}
+
+#endif /* HAVE_GETIFADDRS */
+
+
+static gboolean
+nice_interfaces_is_private_ip (const struct sockaddr *sa)
+{
+  NiceAddress niceaddr;
+
+  nice_address_init (&niceaddr);
+  nice_address_set_from_sockaddr (&niceaddr, sa);
+  return nice_address_is_private (&niceaddr);
+}
+
+static GList *
+add_ip_to_list (GList *list, gchar *ip, gboolean append)
+{
+  GList *i;
+
+  for (i = list; i; i = i->next) {
+    gchar *addr = (gchar *) i->data;
+
+    if (g_strcmp0 (addr, ip) == 0)
+      return list;
+  }
+  if (append)
+    return g_list_append (list, ip);
+  else
+    return g_list_prepend (list, ip);
+}
+
+static GList *
+get_local_ips_ioctl (gboolean include_loopback)
+{
+  GList *ips = NULL;
   gint sockfd;
   gint size = 0;
   struct ifreq *ifr;
   struct ifconf ifc;
+  union {
+    struct sockaddr_in *sin;
+    struct sockaddr *sa;
+  } sa;
+  
+  GList *loopbacks = NULL;
+#ifdef IGNORED_IFACE_PREFIX
+  const gchar **prefix;
+  gboolean ignored;
+#endif
 
   if ((sockfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
-    nice_debug ("error : Cannot open socket to retrieve interface list");
+    nice_debug ("Error : Cannot open socket to retrieve interface list");
     return NULL;
   }
 
@@ -156,7 +263,7 @@ nice_interfaces_get_local_interfaces (void)
     /* realloc buffer size until no overflow occurs  */
     if (NULL == (ifc.ifc_req = realloc (ifc.ifc_req, size))) {
       nice_debug ("Error : Out of memory while allocation interface"
-          "configuration structure");
+          " configuration structure");
       close (sockfd);
       return NULL;
     }
@@ -168,71 +275,68 @@ nice_interfaces_get_local_interfaces (void)
       free (ifc.ifc_req);
       return NULL;
     }
-  } while (size <= ifc.ifc_len);
+  } while  (size <= ifc.ifc_len);
 
 
   /* Loop throught the interface list and get the IP address of each IF */
   for (ifr = ifc.ifc_req;
        (gchar *) ifr < (gchar *) ifc.ifc_req + ifc.ifc_len;
        ++ifr) {
-    nice_debug ("Found interface : %s", ifr->ifr_name);
-    interfaces = g_list_prepend (interfaces, g_strdup (ifr->ifr_name));
-  }
-
-  free (ifc.ifc_req);
-  close (sockfd);
-
-  return interfaces;
-}
-#endif /* HAVE_GETIFADDRS */
 
+    if (ioctl (sockfd, SIOCGIFFLAGS, ifr)) {
+      nice_debug ("Error : Unable to get IP information for interface %s."
+          " Skipping...", ifr->ifr_name);
+      continue;  /* failed to get flags, skip it */
+    }
 
-static gboolean
-nice_interfaces_is_private_ip (const struct sockaddr *_sa)
-{
-  union {
-    const struct sockaddr *addr;
-    const struct sockaddr_in *in;
-  } sa;
+    /* no ip address from interface that is down */
+    if ((ifr->ifr_flags & IFF_UP) == 0)
+      continue;
 
-  sa.addr = _sa;
+    /* no ip address from interface that isn't running */
+    if ((ifr->ifr_flags & IFF_RUNNING) == 0)
+      continue;
 
-  if (sa.addr->sa_family == AF_INET) {
-    /* 10.x.x.x/8 */
-    if (sa.in->sin_addr.s_addr >> 24 == 0x0A)
-      return TRUE;
+    sa.sa = &ifr->ifr_addr;
+    nice_debug ("Interface:  %s", ifr->ifr_name);
+    nice_debug ("IP Address: %s", inet_ntoa (sa.sin->sin_addr));
+    if ((ifr->ifr_flags & IFF_LOOPBACK) == IFF_LOOPBACK){
+      if (include_loopback)
+        loopbacks = add_ip_to_list (loopbacks, g_strdup (inet_ntoa (sa.sin->sin_addr)), TRUE);
+      else
+        nice_debug ("Ignoring loopback interface");
+      continue;
+    }
 
-    /* 172.16.0.0 - 172.31.255.255 = 172.16.0.0/10 */
-    if (sa.in->sin_addr.s_addr >> 20 == 0xAC1)
-      return TRUE;
+#ifdef IGNORED_IFACE_PREFIX
+    ignored = FALSE;
+    for (prefix = ignored_iface_prefix_list; *prefix; prefix++) {
+      if (g_str_has_prefix (ifr->ifr_name, *prefix)) {
+        nice_debug ("Ignoring interface %s as it matches prefix %s",
+            ifr->ifr_name, *prefix);
+        ignored = TRUE;
+        break;
+      }
+    }
 
-    /* 192.168.x.x/16 */
-    if (sa.in->sin_addr.s_addr >> 16 == 0xC0A8)
-      return TRUE;
+    if (ignored)
+      continue;
+#endif
 
-    /* 169.254.x.x/16  (for APIPA) */
-    if (sa.in->sin_addr.s_addr >> 16 == 0xA9FE)
-      return TRUE;
+    if (nice_interfaces_is_private_ip (sa.sa)) {
+      ips = add_ip_to_list (ips, g_strdup (inet_ntoa (sa.sin->sin_addr)), TRUE);
+    } else {
+      ips = add_ip_to_list (ips, g_strdup (inet_ntoa (sa.sin->sin_addr)), FALSE);
+    }
   }
-  
-  return FALSE;
-}
 
-static GList *
-add_ip_to_list (GList *list, gchar *ip, gboolean append)
-{
-  GList *i;
+  close (sockfd);
+  free (ifc.ifc_req);
 
-  for (i = list; i; i = i->next) {
-    gchar *addr = (gchar *) i->data;
+  if (loopbacks)
+    ips = g_list_concat (ips, loopbacks);
 
-    if (g_strcmp0 (addr, ip) == 0)
-      return list;
-  }
-  if (append)
-    return g_list_append (list, ip);
-  else
-    return g_list_prepend (list, ip);
+  return ips;
 }
 
 #ifdef HAVE_GETIFADDRS
@@ -243,10 +347,16 @@ nice_interfaces_get_local_ips (gboolean include_loopback)
   GList *ips = NULL;
   struct ifaddrs *ifa, *results;
   GList *loopbacks = NULL;
+#ifdef IGNORED_IFACE_PREFIX
+  const gchar **prefix;
+  gboolean ignored;
+#endif
 
-
-  if (getifaddrs (&results) < 0)
-      return NULL;
+  if (getifaddrs (&results) < 0) {
+    nice_debug ("Failed to retrieve list of network interfaces with \"getifaddrs\": %s."
+      "Trying to use fallback ...", strerror (errno));
+    return get_local_ips_ioctl (include_loopback);
+  }
 
   /* Loop through the interface list and get the IP address of each IF */
   for (ifa = results; ifa; ifa = ifa->ifa_next) {
@@ -256,6 +366,10 @@ nice_interfaces_get_local_ips (gboolean include_loopback)
     if ((ifa->ifa_flags & IFF_UP) == 0)
       continue;
 
+    /* no ip address from interface that isn't running */
+    if ((ifa->ifa_flags & IFF_RUNNING) == 0)
+      continue;
+
     if (ifa->ifa_addr == NULL)
       continue;
 
@@ -276,18 +390,29 @@ nice_interfaces_get_local_ips (gboolean include_loopback)
         nice_debug ("Ignoring loopback interface");
         g_free (addr_string);
       }
+      continue;
+    }
+
 #ifdef IGNORED_IFACE_PREFIX
-    } else if (g_str_has_prefix (ifa->ifa_name, IGNORED_IFACE_PREFIX)) {
-      nice_debug ("Ignoring interface %s as it matches prefix %s",
-          ifa->ifa_name, IGNORED_IFACE_PREFIX);
-      g_free (addr_string);
-#endif
-    } else {
-      if (nice_interfaces_is_private_ip (ifa->ifa_addr))
-        ips = add_ip_to_list (ips, addr_string, TRUE);
-      else
-        ips = add_ip_to_list (ips, addr_string, FALSE);
+    ignored = FALSE;
+    for (prefix = ignored_iface_prefix_list; *prefix; prefix++) {
+      if (g_str_has_prefix (ifa->ifa_name, *prefix)) {
+        nice_debug ("Ignoring interface %s as it matches prefix %s",
+            ifa->ifa_name, *prefix);
+        g_free (addr_string);
+        ignored = TRUE;
+        break;
+      }
     }
+
+    if (ignored)
+      continue;
+#endif
+
+    if (nice_interfaces_is_private_ip (ifa->ifa_addr))
+      ips = add_ip_to_list (ips, addr_string, TRUE);
+    else
+      ips = add_ip_to_list (ips, addr_string, FALSE);
   }
 
   freeifaddrs (results);
@@ -303,77 +428,7 @@ nice_interfaces_get_local_ips (gboolean include_loopback)
 GList *
 nice_interfaces_get_local_ips (gboolean include_loopback)
 {
-  GList *ips = NULL;
-  gint sockfd;
-  gint size = 0;
-  struct ifreq *ifr;
-  struct ifconf ifc;
-  struct sockaddr_in *sa;
-  gchar *loopback = NULL;
-
-  if ((sockfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
-    nice_debug ("Error : Cannot open socket to retrieve interface list");
-    return NULL;
-  }
-
-  ifc.ifc_len = 0;
-  ifc.ifc_req = NULL;
-
-  /* Loop and get each interface the system has, one by one... */
-  do {
-    size += sizeof (struct ifreq);
-    /* realloc buffer size until no overflow occurs  */
-    if (NULL == (ifc.ifc_req = realloc (ifc.ifc_req, size))) {
-      nice_debug ("Error : Out of memory while allocation interface"
-          " configuration structure");
-      close (sockfd);
-      return NULL;
-    }
-    ifc.ifc_len = size;
-
-    if (ioctl (sockfd, SIOCGIFCONF, &ifc)) {
-      perror ("ioctl SIOCFIFCONF");
-      close (sockfd);
-      free (ifc.ifc_req);
-      return NULL;
-    }
-  } while  (size <= ifc.ifc_len);
-
-
-  /* Loop throught the interface list and get the IP address of each IF */
-  for (ifr = ifc.ifc_req;
-       (gchar *) ifr < (gchar *) ifc.ifc_req + ifc.ifc_len;
-       ++ifr) {
-
-    if (ioctl (sockfd, SIOCGIFFLAGS, ifr)) {
-      nice_debug ("Error : Unable to get IP information for interface %s."
-          " Skipping...", ifr->ifr_name);
-      continue;  /* failed to get flags, skip it */
-    }
-    sa = (struct sockaddr_in *) &ifr->ifr_addr;
-    nice_debug ("Interface:  %s", ifr->ifr_name);
-    nice_debug ("IP Address: %s", inet_ntoa (sa->sin_addr));
-    if ((ifr->ifr_flags & IFF_LOOPBACK) == IFF_LOOPBACK){
-      if (include_loopback)
-        loopback = g_strdup (inet_ntoa (sa->sin_addr));
-      else
-        nice_debug ("Ignoring loopback interface");
-    } else {
-      if (nice_interfaces_is_private_ip ((struct sockaddr *) sa)) {
-        ips = add_ip_to_list (ips, g_strdup (inet_ntoa (sa->sin_addr)), TRUE);
-      } else {
-        ips = add_ip_to_list (ips, g_strdup (inet_ntoa (sa->sin_addr)), FALSE);
-      }
-    }
-  }
-
-  close (sockfd);
-  free (ifc.ifc_req);
-
-  if (loopback)
-    ips = add_ip_to_list (ips, loopback, TRUE);
-
-  return ips;
+  return get_local_ips_ioctl (include_loopback);
 }
 
 #endif /* HAVE_GETIFADDRS */