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>
8 * @author: Youness Alaoui <kakaroto@kakaroto.homelinux.net>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 #include "interfaces.h"
39 #include <sys/ioctl.h>
40 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
46 #include <sys/sockio.h>
49 #ifdef HAVE_GETIFADDRS
54 #include <net/if_arp.h>
55 #include <arpa/inet.h>
57 #ifdef HAVE_GETIFADDRS
60 nice_interfaces_get_local_interfaces (void)
62 GList
*interfaces
= NULL
;
63 struct ifaddrs
*ifa
, *results
;
65 if (getifaddrs (&results
) < 0) {
69 /* Loop and get each interface the system has, one by one... */
70 for (ifa
= results
; ifa
; ifa
= ifa
->ifa_next
) {
71 /* no ip address from interface that is down */
72 if ((ifa
->ifa_flags
& IFF_UP
) == 0)
75 if (ifa
->ifa_addr
== NULL
)
78 if (ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
) {
79 nice_debug ("Found interface : %s", ifa
->ifa_name
);
80 interfaces
= g_list_prepend (interfaces
, g_strdup (ifa
->ifa_name
));
84 freeifaddrs (results
);
89 #else /* ! HAVE_GETIFADDRS */
92 nice_interfaces_get_local_interfaces (void)
94 GList
*interfaces
= NULL
;
100 if ((sockfd
= socket (AF_INET
, SOCK_DGRAM
, IPPROTO_IP
)) < 0) {
101 nice_debug ("error : Cannot open socket to retreive interface list");
108 /* Loop and get each interface the system has, one by one... */
110 size
+= sizeof (struct ifreq
);
111 /* realloc buffer size until no overflow occurs */
112 if (NULL
== (ifc
.ifc_req
= realloc (ifc
.ifc_req
, size
))) {
113 nice_debug ("Error : Out of memory while allocation interface"
114 "configuration structure");
120 if (ioctl (sockfd
, SIOCGIFCONF
, &ifc
)) {
121 perror ("ioctl SIOCFIFCONF");
126 } while (size
<= ifc
.ifc_len
);
129 /* Loop throught the interface list and get the IP address of each IF */
130 for (ifr
= ifc
.ifc_req
;
131 (gchar
*) ifr
< (gchar
*) ifc
.ifc_req
+ ifc
.ifc_len
;
133 nice_debug ("Found interface : %s", ifr
->ifr_name
);
134 interfaces
= g_list_prepend (interfaces
, g_strdup (ifr
->ifr_name
));
142 #endif /* HAVE_GETIFADDRS */
146 nice_interfaces_is_private_ip (const struct sockaddr
*sa
)
148 if (sa
->sa_family
== AF_INET
) {
149 struct sockaddr_in
*sa4
= (struct sockaddr_in
*) sa
;
152 if (sa4
->sin_addr
.s_addr
>> 24 == 0x0A)
155 /* 172.16.0.0 - 172.31.255.255 = 172.16.0.0/10 */
156 if (sa4
->sin_addr
.s_addr
>> 20 == 0xAC1)
160 if (sa4
->sin_addr
.s_addr
>> 16 == 0xC0A8)
163 /* 169.254.x.x/16 (for APIPA) */
164 if (sa4
->sin_addr
.s_addr
>> 16 == 0xA9FE)
171 #ifdef HAVE_GETIFADDRS
174 nice_interfaces_get_local_ips (gboolean include_loopback
)
177 struct ifaddrs
*ifa
, *results
;
178 GList
*loopbacks
= NULL
;
181 if (getifaddrs (&results
) < 0)
184 /* Loop through the interface list and get the IP address of each IF */
185 for (ifa
= results
; ifa
; ifa
= ifa
->ifa_next
) {
186 char addr_as_string
[INET6_ADDRSTRLEN
+1];
188 /* no ip address from interface that is down */
189 if ((ifa
->ifa_flags
& IFF_UP
) == 0)
192 if (ifa
->ifa_addr
== NULL
) {
194 } else if (ifa
->ifa_addr
->sa_family
== AF_INET
) {
195 struct sockaddr_in
*sa4
= (struct sockaddr_in
*) ifa
->ifa_addr
;
197 if (inet_ntop (AF_INET
, &sa4
->sin_addr
, addr_as_string
,
198 INET6_ADDRSTRLEN
) == NULL
)
200 } else if (ifa
->ifa_addr
->sa_family
== AF_INET6
) {
201 struct sockaddr_in6
*sa6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
203 /* Skip link-local addresses, they require a scope */
204 if (IN6_IS_ADDR_LINKLOCAL (&sa6
->sin6_addr
))
207 if (inet_ntop (AF_INET6
, &sa6
->sin6_addr
, addr_as_string
,
208 INET6_ADDRSTRLEN
) == NULL
)
214 nice_debug ("Interface: %s", ifa
->ifa_name
);
215 nice_debug ("IP Address: %s", addr_as_string
);
216 if ((ifa
->ifa_flags
& IFF_LOOPBACK
) == IFF_LOOPBACK
) {
217 if (include_loopback
)
218 loopbacks
= g_list_append (loopbacks
, g_strdup (addr_as_string
));
220 nice_debug ("Ignoring loopback interface");
222 if (nice_interfaces_is_private_ip (ifa
->ifa_addr
))
223 ips
= g_list_append (ips
, g_strdup (addr_as_string
));
225 ips
= g_list_prepend (ips
, g_strdup (addr_as_string
));
229 freeifaddrs (results
);
232 ips
= g_list_concat (ips
, loopbacks
);
237 #else /* ! HAVE_GETIFADDRS */
240 nice_interfaces_get_local_ips (gboolean include_loopback
)
247 struct sockaddr_in
*sa
;
248 gchar
*loopback
= NULL
;
250 if ((sockfd
= socket (AF_INET
, SOCK_DGRAM
, IPPROTO_IP
)) < 0) {
251 nice_debug ("Error : Cannot open socket to retreive interface list");
258 /* Loop and get each interface the system has, one by one... */
260 size
+= sizeof (struct ifreq
);
261 /* realloc buffer size until no overflow occurs */
262 if (NULL
== (ifc
.ifc_req
= realloc (ifc
.ifc_req
, size
))) {
263 nice_debug ("Error : Out of memory while allocation interface"
264 " configuration structure");
270 if (ioctl (sockfd
, SIOCGIFCONF
, &ifc
)) {
271 perror ("ioctl SIOCFIFCONF");
276 } while (size
<= ifc
.ifc_len
);
279 /* Loop throught the interface list and get the IP address of each IF */
280 for (ifr
= ifc
.ifc_req
;
281 (gchar
*) ifr
< (gchar
*) ifc
.ifc_req
+ ifc
.ifc_len
;
284 if (ioctl (sockfd
, SIOCGIFFLAGS
, ifr
)) {
285 nice_debug ("Error : Unable to get IP information for interface %s."
286 " Skipping...", ifr
->ifr_name
);
287 continue; /* failed to get flags, skip it */
289 sa
= (struct sockaddr_in
*) &ifr
->ifr_addr
;
290 nice_debug ("Interface: %s", ifr
->ifr_name
);
291 nice_debug ("IP Address: %s", inet_ntoa (sa
->sin_addr
));
292 if ((ifr
->ifr_flags
& IFF_LOOPBACK
) == IFF_LOOPBACK
){
293 if (include_loopback
)
294 loopback
= g_strdup (inet_ntoa (sa
->sin_addr
));
296 nice_debug ("Ignoring loopback interface");
298 if (nice_interfaces_is_private_ip (sa
)) {
299 ips
= g_list_append (ips
, g_strdup (inet_ntoa (sa
->sin_addr
)));
301 ips
= g_list_prepend (ips
, g_strdup (inet_ntoa (sa
->sin_addr
)));
310 ips
= g_list_append (ips
, loopback
);
315 #endif /* HAVE_GETIFADDRS */
318 nice_interfaces_get_ip_for_interface (gchar
*interface_name
)
321 struct sockaddr_in
*sa
;
325 ifr
.ifr_addr
.sa_family
= AF_INET
;
326 memset (ifr
.ifr_name
, 0, sizeof (ifr
.ifr_name
));
327 g_strlcpy (ifr
.ifr_name
, interface_name
, sizeof (ifr
.ifr_name
));
329 if ((sockfd
= socket (AF_INET
, SOCK_DGRAM
, IPPROTO_IP
)) < 0) {
330 nice_debug ("Error : Cannot open socket to retreive interface list");
334 if (ioctl (sockfd
, SIOCGIFADDR
, &ifr
) < 0) {
335 nice_debug ("Error : Unable to get IP information for interface %s",
342 sa
= (struct sockaddr_in
*) &ifr
.ifr_addr
;
343 nice_debug ("Address for %s: %s", interface_name
, inet_ntoa (sa
->sin_addr
));
344 return g_strdup (inet_ntoa (sa
->sin_addr
));
347 #else /* G_OS_UNIX */
350 #include <winsock2.h>
351 #include <Iphlpapi.h>
353 static gboolean started_wsa_engine
= FALSE
;
356 * private function that initializes the WinSock engine and
357 * returns a prebuilt socket
359 SOCKET
nice_interfaces_get_WSA_socket ()
361 WORD wVersionRequested
;
366 if (started_wsa_engine
== FALSE
) {
367 wVersionRequested
= MAKEWORD ( 2, 0 );
369 err
= WSAStartup ( wVersionRequested
, &wsaData
);
371 nice_debug ("Error : Could not start the winsocket engine");
372 return INVALID_SOCKET
;
374 started_wsa_engine
= TRUE
;
378 if ((sock
= socket (AF_INET
, SOCK_DGRAM
, 0)) == INVALID_SOCKET
) {
379 nice_debug ("Error : Could not open socket to retreive interface list,"
380 " error no : %d", WSAGetLastError ());
381 return INVALID_SOCKET
;
387 GList
* nice_interfaces_get_local_interfaces ()
390 PMIB_IFTABLE if_table
;
393 GetIfTable(NULL
, &size
, TRUE
);
398 if_table
= (PMIB_IFTABLE
)g_malloc0(size
);
400 if (GetIfTable(if_table
, &size
, TRUE
) == ERROR_SUCCESS
) {
402 for (i
= 0; i
< if_table
->dwNumEntries
; i
++) {
403 ret
= g_list_prepend (ret
, g_strdup ((gchar
*)if_table
->table
[i
].bDescr
));
412 GList
* nice_interfaces_get_local_ips (gboolean include_loopback
)
416 PMIB_IPADDRTABLE ip_table
;
419 GetIpAddrTable (NULL
, &size
, TRUE
);
425 * Get the best interface for transport to 0.0.0.0.
426 * This interface should be first in list!
428 if (GetBestInterface (0, &pref
) != NO_ERROR
)
431 ip_table
= (PMIB_IPADDRTABLE
)g_malloc0 (size
);
433 if (GetIpAddrTable (ip_table
, &size
, TRUE
) == ERROR_SUCCESS
) {
435 for (i
= 0; i
< ip_table
->dwNumEntries
; i
++) {
437 PMIB_IPADDRROW ipaddr
= &ip_table
->table
[i
];
439 if (!(ipaddr
->wType
& (MIB_IPADDR_DISCONNECTED
| MIB_IPADDR_DELETED
)) &&
441 if (!include_loopback
) {
443 PMIB_IFROW ifr
= (PMIB_IFROW
)g_malloc0 (sizeof (MIB_IFROW
));
444 ifr
->dwIndex
= ipaddr
->dwIndex
;
445 if (GetIfEntry (ifr
) == NO_ERROR
)
449 if (type
== IF_TYPE_SOFTWARE_LOOPBACK
)
453 ipstr
= g_strdup_printf ("%d.%d.%d.%d",
454 (ipaddr
->dwAddr
) & 0xFF,
455 (ipaddr
->dwAddr
>> 8) & 0xFF,
456 (ipaddr
->dwAddr
>> 16) & 0xFF,
457 (ipaddr
->dwAddr
>> 24) & 0xFF);
458 if (ipaddr
->dwIndex
== pref
)
459 ret
= g_list_prepend (ret
, ipstr
);
461 ret
= g_list_append (ret
, ipstr
);
472 * returns ip address as an utf8 string
475 win32_get_ip_for_interface (IF_INDEX idx
)
478 PMIB_IPADDRTABLE ip_table
;
481 GetIpAddrTable (NULL
, &size
, TRUE
);
486 ip_table
= (PMIB_IPADDRTABLE
)g_malloc0 (size
);
488 if (GetIpAddrTable (ip_table
, &size
, TRUE
) == ERROR_SUCCESS
) {
490 for (i
= 0; i
< ip_table
->dwNumEntries
; i
++) {
491 PMIB_IPADDRROW ipaddr
= &ip_table
->table
[i
];
492 if (ipaddr
->dwIndex
== idx
&&
493 !(ipaddr
->wType
& (MIB_IPADDR_DISCONNECTED
| MIB_IPADDR_DELETED
))) {
494 ret
= g_strdup_printf ("%d.%d.%d.%d",
495 (ipaddr
->dwAddr
) & 0xFF,
496 (ipaddr
->dwAddr
>> 8) & 0xFF,
497 (ipaddr
->dwAddr
>> 16) & 0xFF,
498 (ipaddr
->dwAddr
>> 24) & 0xFF);
508 gchar
* nice_interfaces_get_ip_for_interface (gchar
*interface_name
)
511 PMIB_IFTABLE if_table
;
514 GetIfTable (NULL
, &size
, TRUE
);
519 if_table
= (PMIB_IFTABLE
)g_malloc0 (size
);
521 if (GetIfTable (if_table
, &size
, TRUE
) == ERROR_SUCCESS
) {
524 for (i
= 0; i
< if_table
->dwNumEntries
; i
++) {
525 tmp_str
= g_utf16_to_utf8 (
526 if_table
->table
[i
].wszName
, MAX_INTERFACE_NAME_LEN
,
529 if (strlen (interface_name
) == strlen (tmp_str
) &&
530 g_ascii_strncasecmp (interface_name
, tmp_str
, strlen (interface_name
)) == 0) {
531 ret
= win32_get_ip_for_interface (if_table
->table
[i
].dwIndex
);
546 #else /* G_OS_WIN32 */
547 #error Can not use this method for retreiving ip list from OS other than unix or windows
548 #endif /* G_OS_WIN32 */
549 #endif /* G_OS_UNIX */