2 * interfaces.c - Source for interface discovery code
4 * Copyright (C) 2006 Youness Alaoui <kakaroto@kakaroto.homelinux.net>
5 * Copyright (C) 2007 Collabora, Nokia
6 * Contact: Youness Alaoui
7 * Copyright (C) 2008 Haakon Sporsheim <haakon.sporsheim@tandberg.com>
9 * The contents of this file are subject to the Mozilla Public License Version
10 * 1.1 (the "License"); you may not use this file except in compliance with
11 * the License. You may obtain a copy of the License at
12 * http://www.mozilla.org/MPL/
14 * Software distributed under the License is distributed on an "AS IS" basis,
15 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
16 * for the specific language governing rights and limitations under the
19 * The Original Code is the Nice GLib ICE library.
21 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
22 * Corporation. All Rights Reserved.
25 * Dafydd Harries, Collabora Ltd.
26 * Youness Alaoui, Collabora Ltd.
28 * Philip Withnall, Collabora Ltd.
31 * Alternatively, the contents of this file may be used under the terms of the
32 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
33 * case the provisions of LGPL are applicable instead of those above. If you
34 * wish to allow use of your version of this file only under the terms of the
35 * LGPL and not to allow others to use your version of this file under the
36 * MPL, indicate your decision by deleting the provisions above and replace
37 * them with the notice and other provisions required by the LGPL. If you do
38 * not delete the provisions above, a recipient may use your version of this
39 * file under either the MPL or the LGPL.
46 #include "interfaces.h"
47 #include "agent-priv.h"
56 #include <sys/ioctl.h>
57 #include <sys/types.h>
59 #include <sys/socket.h>
60 #include <netinet/in.h>
64 #include <sys/sockio.h>
67 #ifdef HAVE_GETIFADDRS
72 #include <arpa/inet.h>
74 #endif /* G_OS_UNIX */
76 #ifdef IGNORED_IFACE_PREFIX
77 static const gchar *ignored_iface_prefix_list[] = {
83 #if (defined(G_OS_UNIX) && defined(HAVE_GETIFADDRS)) || defined(G_OS_WIN32)
84 /* Works on both UNIX and Windows. Magic! */
86 sockaddr_to_string (const struct sockaddr *addr)
88 char addr_as_string[INET6_ADDRSTRLEN+1];
91 switch (addr->sa_family) {
92 case AF_INET: addr_len = sizeof (struct sockaddr_in); break;
93 case AF_INET6: addr_len = sizeof (struct sockaddr_in6); break;
97 if (getnameinfo (addr, addr_len,
98 addr_as_string, sizeof (addr_as_string), NULL, 0,
99 NI_NUMERICHOST) != 0) {
103 return g_strdup (addr_as_string);
110 get_local_interfaces_ioctl (void)
112 GList *interfaces = NULL;
118 if ((sockfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
119 nice_debug ("error : Cannot open socket to retrieve interface list");
126 /* Loop and get each interface the system has, one by one... */
128 size += sizeof (struct ifreq);
129 /* realloc buffer size until no overflow occurs */
130 if (NULL == (ifc.ifc_req = realloc (ifc.ifc_req, size))) {
131 nice_debug ("Error : Out of memory while allocation interface"
132 "configuration structure");
138 if (ioctl (sockfd, SIOCGIFCONF, &ifc)) {
139 perror ("ioctl SIOCFIFCONF");
144 } while (size <= ifc.ifc_len);
147 /* Loop throught the interface list and get the IP address of each IF */
148 for (ifr = ifc.ifc_req;
149 (gchar *) ifr < (gchar *) ifc.ifc_req + ifc.ifc_len;
151 nice_debug ("Found interface : %s", ifr->ifr_name);
152 interfaces = g_list_prepend (interfaces, g_strdup (ifr->ifr_name));
161 #ifdef HAVE_GETIFADDRS
164 nice_interfaces_get_local_interfaces (void)
166 GList *interfaces = NULL;
167 struct ifaddrs *ifa, *results;
169 if (getifaddrs (&results) < 0) {
170 nice_debug ("Failed to retrieve list of network interfaces with \"getifaddrs\": %s."
171 "Trying to use fallback ...", strerror (errno));
172 return get_local_interfaces_ioctl ();
175 /* Loop and get each interface the system has, one by one... */
176 for (ifa = results; ifa; ifa = ifa->ifa_next) {
177 /* no ip address from interface that is down */
178 if ((ifa->ifa_flags & IFF_UP) == 0)
181 if (ifa->ifa_addr == NULL)
184 if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6) {
185 nice_debug ("Found interface : %s", ifa->ifa_name);
186 interfaces = g_list_prepend (interfaces, g_strdup (ifa->ifa_name));
190 freeifaddrs (results);
195 #else /* ! HAVE_GETIFADDRS */
198 nice_interfaces_get_local_interfaces (void)
200 return get_local_interfaces_ioctl ();
203 #endif /* HAVE_GETIFADDRS */
207 nice_interfaces_is_private_ip (const struct sockaddr *sa)
209 NiceAddress niceaddr;
211 nice_address_init (&niceaddr);
212 nice_address_set_from_sockaddr (&niceaddr, sa);
213 return nice_address_is_private (&niceaddr);
217 add_ip_to_list (GList *list, gchar *ip, gboolean append)
221 for (i = list; i; i = i->next) {
222 gchar *addr = (gchar *) i->data;
224 if (g_strcmp0 (addr, ip) == 0)
228 return g_list_append (list, ip);
230 return g_list_prepend (list, ip);
234 get_local_ips_ioctl (gboolean include_loopback)
242 struct sockaddr_in *sin;
246 GList *loopbacks = NULL;
247 #ifdef IGNORED_IFACE_PREFIX
248 const gchar **prefix;
252 if ((sockfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
253 nice_debug ("Error : Cannot open socket to retrieve interface list");
260 /* Loop and get each interface the system has, one by one... */
262 size += sizeof (struct ifreq);
263 /* realloc buffer size until no overflow occurs */
264 if (NULL == (ifc.ifc_req = realloc (ifc.ifc_req, size))) {
265 nice_debug ("Error : Out of memory while allocation interface"
266 " configuration structure");
272 if (ioctl (sockfd, SIOCGIFCONF, &ifc)) {
273 perror ("ioctl SIOCFIFCONF");
278 } while (size <= ifc.ifc_len);
281 /* Loop throught the interface list and get the IP address of each IF */
282 for (ifr = ifc.ifc_req;
283 (gchar *) ifr < (gchar *) ifc.ifc_req + ifc.ifc_len;
286 if (ioctl (sockfd, SIOCGIFFLAGS, ifr)) {
287 nice_debug ("Error : Unable to get IP information for interface %s."
288 " Skipping...", ifr->ifr_name);
289 continue; /* failed to get flags, skip it */
292 /* no ip address from interface that is down */
293 if ((ifr->ifr_flags & IFF_UP) == 0)
296 /* no ip address from interface that isn't running */
297 if ((ifr->ifr_flags & IFF_RUNNING) == 0)
300 sa.sa = &ifr->ifr_addr;
301 nice_debug ("Interface: %s", ifr->ifr_name);
302 nice_debug ("IP Address: %s", inet_ntoa (sa.sin->sin_addr));
303 if ((ifr->ifr_flags & IFF_LOOPBACK) == IFF_LOOPBACK){
304 if (include_loopback)
305 loopbacks = add_ip_to_list (loopbacks, g_strdup (inet_ntoa (sa.sin->sin_addr)), TRUE);
307 nice_debug ("Ignoring loopback interface");
311 #ifdef IGNORED_IFACE_PREFIX
313 for (prefix = ignored_iface_prefix_list; *prefix; prefix++) {
314 if (g_str_has_prefix (ifr->ifr_name, *prefix)) {
315 nice_debug ("Ignoring interface %s as it matches prefix %s",
316 ifr->ifr_name, *prefix);
326 if (nice_interfaces_is_private_ip (sa.sa)) {
327 ips = add_ip_to_list (ips, g_strdup (inet_ntoa (sa.sin->sin_addr)), TRUE);
329 ips = add_ip_to_list (ips, g_strdup (inet_ntoa (sa.sin->sin_addr)), FALSE);
337 ips = g_list_concat (ips, loopbacks);
342 #ifdef HAVE_GETIFADDRS
345 nice_interfaces_get_local_ips (gboolean include_loopback)
348 struct ifaddrs *ifa, *results;
349 GList *loopbacks = NULL;
350 #ifdef IGNORED_IFACE_PREFIX
351 const gchar **prefix;
355 if (getifaddrs (&results) < 0) {
356 nice_debug ("Failed to retrieve list of network interfaces with \"getifaddrs\": %s."
357 "Trying to use fallback ...", strerror (errno));
358 return get_local_ips_ioctl (include_loopback);
361 /* Loop through the interface list and get the IP address of each IF */
362 for (ifa = results; ifa; ifa = ifa->ifa_next) {
365 /* no ip address from interface that is down */
366 if ((ifa->ifa_flags & IFF_UP) == 0)
369 /* no ip address from interface that isn't running */
370 if ((ifa->ifa_flags & IFF_RUNNING) == 0)
373 if (ifa->ifa_addr == NULL)
376 /* Convert to a string. */
377 addr_string = sockaddr_to_string (ifa->ifa_addr);
378 if (addr_string == NULL) {
379 nice_debug ("Failed to convert address to string for interface ‘%s’.",
384 nice_debug ("Interface: %s", ifa->ifa_name);
385 nice_debug ("IP Address: %s", addr_string);
386 if ((ifa->ifa_flags & IFF_LOOPBACK) == IFF_LOOPBACK) {
387 if (include_loopback) {
388 loopbacks = add_ip_to_list (loopbacks, addr_string, TRUE);
390 nice_debug ("Ignoring loopback interface");
391 g_free (addr_string);
396 #ifdef IGNORED_IFACE_PREFIX
398 for (prefix = ignored_iface_prefix_list; *prefix; prefix++) {
399 if (g_str_has_prefix (ifa->ifa_name, *prefix)) {
400 nice_debug ("Ignoring interface %s as it matches prefix %s",
401 ifa->ifa_name, *prefix);
402 g_free (addr_string);
412 if (nice_interfaces_is_private_ip (ifa->ifa_addr))
413 ips = add_ip_to_list (ips, addr_string, TRUE);
415 ips = add_ip_to_list (ips, addr_string, FALSE);
418 freeifaddrs (results);
421 ips = g_list_concat (ips, loopbacks);
426 #else /* ! HAVE_GETIFADDRS */
429 nice_interfaces_get_local_ips (gboolean include_loopback)
431 return get_local_ips_ioctl (include_loopback);
434 #endif /* HAVE_GETIFADDRS */
437 nice_interfaces_get_ip_for_interface (gchar *interface_name)
441 struct sockaddr *addr;
442 struct sockaddr_in *in;
446 g_return_val_if_fail (interface_name != NULL, NULL);
448 ifr.ifr_addr.sa_family = AF_INET;
449 memset (ifr.ifr_name, 0, sizeof (ifr.ifr_name));
450 g_strlcpy (ifr.ifr_name, interface_name, sizeof (ifr.ifr_name));
452 if ((sockfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
453 nice_debug ("Error : Cannot open socket to retrieve interface list");
457 if (ioctl (sockfd, SIOCGIFADDR, &ifr) < 0) {
458 nice_debug ("Error : Unable to get IP information for interface %s",
465 sa.addr = &ifr.ifr_addr;
466 nice_debug ("Address for %s: %s", interface_name, inet_ntoa (sa.in->sin_addr));
467 return g_strdup (inet_ntoa (sa.in->sin_addr));
470 #else /* G_OS_UNIX */
473 #include <winsock2.h>
474 #include <iphlpapi.h>
476 // Should be in Iphlpapi.h, but mingw doesn't seem to have these
477 // Values copied directly from:
478 // http://msdn.microsoft.com/en-us/library/aa366845(v=vs.85).aspx
479 // (Title: MIB_IPADDRROW structure)
481 #ifndef MIB_IPADDR_DISCONNECTED
482 #define MIB_IPADDR_DISCONNECTED 0x0008
485 #ifndef MIB_IPADDR_DELETED
486 #define MIB_IPADDR_DELETED 0x0040
490 static gboolean started_wsa_engine = FALSE;
493 * private function that initializes the WinSock engine and
494 * returns a prebuilt socket
496 SOCKET nice_interfaces_get_WSA_socket ()
498 WORD wVersionRequested;
503 if (started_wsa_engine == FALSE) {
504 wVersionRequested = MAKEWORD ( 2, 0 );
506 err = WSAStartup ( wVersionRequested, &wsaData );
508 nice_debug ("Error : Could not start the winsocket engine");
509 return INVALID_SOCKET;
511 started_wsa_engine = TRUE;
515 if ((sock = socket (AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
516 nice_debug ("Error : Could not open socket to retrieve interface list,"
517 " error no : %d", WSAGetLastError ());
518 return INVALID_SOCKET;
525 GList * nice_interfaces_get_local_interfaces (void)
528 PMIB_IFTABLE if_table;
531 GetIfTable(NULL, &size, TRUE);
536 if_table = (PMIB_IFTABLE)g_malloc0(size);
538 if (GetIfTable(if_table, &size, TRUE) == ERROR_SUCCESS) {
540 for (i = 0; i < if_table->dwNumEntries; i++) {
541 ret = g_list_prepend (ret, g_strdup ((gchar*)if_table->table[i].bDescr));
550 GList * nice_interfaces_get_local_ips (gboolean include_loopback)
552 IP_ADAPTER_ADDRESSES *addresses = NULL, *a;
555 ULONG addresses_size;
560 * http://msdn.microsoft.com/en-gb/library/windows/desktop/aa365915%28v=vs.85%29.aspx */
562 #define INITIAL_BUFFER_SIZE 15000
564 addresses_size = INITIAL_BUFFER_SIZE;
569 addresses = g_malloc0 (addresses_size);
571 status = GetAdaptersAddresses (AF_UNSPEC,
572 GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
573 GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &addresses_size);
574 } while ((status == ERROR_BUFFER_OVERFLOW) && (iterations++ < MAX_TRIES));
576 nice_debug ("Queried addresses with status %lu.", status);
578 #undef INITIAL_BUFFER_SIZE
582 if (status != NO_ERROR) {
583 nice_debug ("Error retrieving local addresses (error code %lu).", status);
589 * Get the best interface for transport to 0.0.0.0.
590 * This interface should be first in list!
592 if (GetBestInterface (0, &pref) != NO_ERROR)
595 /* Loop over the adapters. */
596 for (a = addresses; a != NULL; a = a->Next) {
597 IP_ADAPTER_UNICAST_ADDRESS *unicast;
599 nice_debug ("Interface ‘%S’:", a->FriendlyName);
601 /* Various conditions for ignoring the interface. */
602 if (a->Flags & IP_ADAPTER_RECEIVE_ONLY ||
603 a->OperStatus == IfOperStatusDown ||
604 a->OperStatus == IfOperStatusNotPresent ||
605 a->OperStatus == IfOperStatusLowerLayerDown) {
606 nice_debug ("Rejecting interface due to being down or read-only.");
610 if (!include_loopback &&
611 a->IfType == IF_TYPE_SOFTWARE_LOOPBACK) {
612 nice_debug ("Rejecting loopback interface ‘%S’.", a->FriendlyName);
616 /* Grab the interface’s unicast addresses. */
617 for (unicast = a->FirstUnicastAddress;
618 unicast != NULL; unicast = unicast->Next) {
621 addr_string = sockaddr_to_string (unicast->Address.lpSockaddr);
622 if (addr_string == NULL) {
623 nice_debug ("Failed to convert address to string for interface ‘%S’.",
628 nice_debug ("IP address: %s", addr_string);
630 if (a->IfIndex == pref || a->Ipv6IfIndex == pref)
631 ret = g_list_prepend (ret, addr_string);
633 ret = g_list_append (ret, addr_string);
643 * returns ip address as an utf8 string
645 // Source for idx's type (Was IF_INDEX):
646 // http://msdn.microsoft.com/en-us/library/aa366836(v=VS.85).aspx
647 // (Title: MIB_IFROW structure)
649 win32_get_ip_for_interface (DWORD idx)
652 PMIB_IPADDRTABLE ip_table;
655 GetIpAddrTable (NULL, &size, TRUE);
660 ip_table = (PMIB_IPADDRTABLE)g_malloc0 (size);
662 if (GetIpAddrTable (ip_table, &size, TRUE) == ERROR_SUCCESS) {
664 for (i = 0; i < ip_table->dwNumEntries; i++) {
665 PMIB_IPADDRROW ipaddr = &ip_table->table[i];
666 if (ipaddr->dwIndex == idx &&
667 !(ipaddr->wType & (MIB_IPADDR_DISCONNECTED | MIB_IPADDR_DELETED))) {
668 ret = g_strdup_printf ("%lu.%lu.%lu.%lu",
669 (ipaddr->dwAddr ) & 0xFF,
670 (ipaddr->dwAddr >> 8) & 0xFF,
671 (ipaddr->dwAddr >> 16) & 0xFF,
672 (ipaddr->dwAddr >> 24) & 0xFF);
682 gchar * nice_interfaces_get_ip_for_interface (gchar *interface_name)
685 PMIB_IFTABLE if_table;
688 GetIfTable (NULL, &size, TRUE);
693 if_table = (PMIB_IFTABLE)g_malloc0 (size);
695 if (GetIfTable (if_table, &size, TRUE) == ERROR_SUCCESS) {
698 for (i = 0; i < if_table->dwNumEntries; i++) {
699 tmp_str = g_utf16_to_utf8 (
700 if_table->table[i].wszName, MAX_INTERFACE_NAME_LEN,
703 if (strlen (interface_name) == strlen (tmp_str) &&
704 g_ascii_strncasecmp (interface_name, tmp_str, strlen (interface_name)) == 0) {
705 ret = win32_get_ip_for_interface (if_table->table[i].dwIndex);
720 #else /* G_OS_WIN32 */
721 #error Can not use this method for retreiving ip list from OS other than unix or windows
722 #endif /* G_OS_WIN32 */
723 #endif /* G_OS_UNIX */