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 * Copyright (C) 2008 Haakon Sporsheim <haakon.sporsheim@tandberg.com>
7 * @author: Youness Alaoui <kakaroto@kakaroto.homelinux.net>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 #include "interfaces.h"
38 #include <sys/ioctl.h>
39 #include <sys/types.h>
41 #include <sys/socket.h>
43 #ifdef HAVE_GETIFADDRS
48 #include <net/if_arp.h>
49 #include <arpa/inet.h>
51 #ifdef HAVE_GETIFADDRS
54 nice_interfaces_get_local_interfaces (void)
56 GList
*interfaces
= NULL
;
57 struct ifaddrs
*ifa
, *results
;
59 if (getifaddrs (&results
) < 0) {
63 /* Loop and get each interface the system has, one by one... */
64 for (ifa
= results
; ifa
; ifa
= ifa
->ifa_next
) {
65 /* no ip address from interface that is down */
66 if ((ifa
->ifa_flags
& IFF_UP
) == 0)
69 if (ifa
->ifa_addr
== NULL
|| ifa
->ifa_addr
->sa_family
!= AF_INET
)
72 nice_debug ("Found interface : %s", ifa
->ifa_name
);
73 interfaces
= g_list_prepend (interfaces
, g_strdup (ifa
->ifa_name
));
76 freeifaddrs (results
);
81 #else /* ! HAVE_GETIFADDRS */
84 nice_interfaces_get_local_interfaces (void)
86 GList
*interfaces
= NULL
;
92 if ((sockfd
= socket (AF_INET
, SOCK_DGRAM
, IPPROTO_IP
)) < 0) {
93 nice_debug ("error : Cannot open socket to retreive interface list");
100 /* Loop and get each interface the system has, one by one... */
102 size
+= sizeof (struct ifreq
);
103 /* realloc buffer size until no overflow occurs */
104 if (NULL
== (ifc
.ifc_req
= realloc (ifc
.ifc_req
, size
))) {
105 nice_debug ("Error : Out of memory while allocation interface"
106 "configuration structure");
112 if (ioctl (sockfd
, SIOCGIFCONF
, &ifc
)) {
113 perror ("ioctl SIOCFIFCONF");
118 } while (size
<= ifc
.ifc_len
);
121 /* Loop throught the interface list and get the IP address of each IF */
122 for (ifr
= ifc
.ifc_req
;
123 (gchar
*) ifr
< (gchar
*) ifc
.ifc_req
+ ifc
.ifc_len
;
125 nice_debug ("Found interface : %s", ifr
->ifr_name
);
126 interfaces
= g_list_prepend (interfaces
, g_strdup (ifr
->ifr_name
));
134 #endif /* HAVE_GETIFADDRS */
138 nice_interfaces_is_private_ip (const struct in_addr in
)
141 if (in
.s_addr
>> 24 == 0x0A)
144 /* 172.16.0.0 - 172.31.255.255 = 172.16.0.0/10 */
145 if (in
.s_addr
>> 20 == 0xAC1)
149 if (in
.s_addr
>> 16 == 0xC0A8)
152 /* 169.254.x.x/16 (for APIPA) */
153 if (in
.s_addr
>> 16 == 0xA9FE)
159 #ifdef HAVE_GETIFADDRS
162 nice_interfaces_get_local_ips (gboolean include_loopback
)
165 struct sockaddr_in
*sa
;
166 struct ifaddrs
*ifa
, *results
;
167 gchar
*loopback
= NULL
;
170 if (getifaddrs (&results
) < 0)
173 /* Loop through the interface list and get the IP address of each IF */
174 for (ifa
= results
; ifa
; ifa
= ifa
->ifa_next
) {
175 /* no ip address from interface that is down */
176 if ((ifa
->ifa_flags
& IFF_UP
) == 0)
179 if (ifa
->ifa_addr
== NULL
|| ifa
->ifa_addr
->sa_family
!= AF_INET
)
182 sa
= (struct sockaddr_in
*) ifa
->ifa_addr
;
184 nice_debug ("Interface: %s", ifa
->ifa_name
);
185 nice_debug ("IP Address: %s", inet_ntoa (sa
->sin_addr
));
186 if ((ifa
->ifa_flags
& IFF_LOOPBACK
) == IFF_LOOPBACK
) {
187 if (include_loopback
)
188 loopback
= g_strdup (inet_ntoa (sa
->sin_addr
));
190 nice_debug ("Ignoring loopback interface");
192 if (nice_interfaces_is_private_ip (sa
->sin_addr
))
193 ips
= g_list_append (ips
, g_strdup (inet_ntoa (sa
->sin_addr
)));
195 ips
= g_list_prepend (ips
, g_strdup (inet_ntoa (sa
->sin_addr
)));
199 freeifaddrs (results
);
202 ips
= g_list_append (ips
, loopback
);
207 #else /* ! HAVE_GETIFADDRS */
210 nice_interfaces_get_local_ips (gboolean include_loopback
)
217 struct sockaddr_in
*sa
;
218 gchar
*loopback
= NULL
;
220 if ((sockfd
= socket (AF_INET
, SOCK_DGRAM
, IPPROTO_IP
)) < 0) {
221 nice_debug ("Error : Cannot open socket to retreive interface list");
228 /* Loop and get each interface the system has, one by one... */
230 size
+= sizeof (struct ifreq
);
231 /* realloc buffer size until no overflow occurs */
232 if (NULL
== (ifc
.ifc_req
= realloc (ifc
.ifc_req
, size
))) {
233 nice_debug ("Error : Out of memory while allocation interface"
234 " configuration structure");
240 if (ioctl (sockfd
, SIOCGIFCONF
, &ifc
)) {
241 perror ("ioctl SIOCFIFCONF");
246 } while (size
<= ifc
.ifc_len
);
249 /* Loop throught the interface list and get the IP address of each IF */
250 for (ifr
= ifc
.ifc_req
;
251 (gchar
*) ifr
< (gchar
*) ifc
.ifc_req
+ ifc
.ifc_len
;
254 if (ioctl (sockfd
, SIOCGIFFLAGS
, ifr
)) {
255 nice_debug ("Error : Unable to get IP information for interface %s."
256 " Skipping...", ifr
->ifr_name
);
257 continue; /* failed to get flags, skip it */
259 sa
= (struct sockaddr_in
*) &ifr
->ifr_addr
;
260 nice_debug ("Interface: %s", ifr
->ifr_name
);
261 nice_debug ("IP Address: %s", inet_ntoa (sa
->sin_addr
));
262 if ((ifr
->ifr_flags
& IFF_LOOPBACK
) == IFF_LOOPBACK
){
263 if (include_loopback
)
264 loopback
= g_strdup (inet_ntoa (sa
->sin_addr
));
266 nice_debug ("Ignoring loopback interface");
268 if (nice_interfaces_is_private_ip (sa
->sin_addr
)) {
269 ips
= g_list_append (ips
, g_strdup (inet_ntoa (sa
->sin_addr
)));
271 ips
= g_list_prepend (ips
, g_strdup (inet_ntoa (sa
->sin_addr
)));
280 ips
= g_list_append (ips
, loopback
);
285 #endif /* HAVE_GETIFADDRS */
288 nice_interfaces_get_ip_for_interface (gchar
*interface_name
)
291 struct sockaddr_in
*sa
;
295 ifr
.ifr_addr
.sa_family
= AF_INET
;
296 memset (ifr
.ifr_name
, 0, sizeof (ifr
.ifr_name
));
297 g_strlcpy (ifr
.ifr_name
, interface_name
, sizeof (ifr
.ifr_name
));
299 if ((sockfd
= socket (AF_INET
, SOCK_DGRAM
, IPPROTO_IP
)) < 0) {
300 nice_debug ("Error : Cannot open socket to retreive interface list");
304 if (ioctl (sockfd
, SIOCGIFADDR
, &ifr
) < 0) {
305 nice_debug ("Error : Unable to get IP information for interface %s",
312 sa
= (struct sockaddr_in
*) &ifr
.ifr_addr
;
313 nice_debug ("Address for %s: %s", interface_name
, inet_ntoa (sa
->sin_addr
));
314 return g_strdup (inet_ntoa (sa
->sin_addr
));
317 #else /* G_OS_UNIX */
320 #include <winsock2.h>
321 #include <Iphlpapi.h>
323 static gboolean started_wsa_engine
= FALSE
;
326 * private function that initializes the WinSock engine and
327 * returns a prebuilt socket
329 SOCKET
nice_interfaces_get_WSA_socket ()
331 WORD wVersionRequested
;
336 if (started_wsa_engine
== FALSE
) {
337 wVersionRequested
= MAKEWORD ( 2, 0 );
339 err
= WSAStartup ( wVersionRequested
, &wsaData
);
341 nice_debug ("Error : Could not start the winsocket engine");
342 return INVALID_SOCKET
;
344 started_wsa_engine
= TRUE
;
348 if ((sock
= socket (AF_INET
, SOCK_DGRAM
, 0)) == INVALID_SOCKET
) {
349 nice_debug ("Error : Could not open socket to retreive interface list,"
350 " error no : %d", WSAGetLastError ());
351 return INVALID_SOCKET
;
357 GList
* nice_interfaces_get_local_interfaces ()
360 PMIB_IFTABLE if_table
;
363 GetIfTable(NULL
, &size
, TRUE
);
368 if_table
= (PMIB_IFTABLE
)g_malloc0(size
);
370 if (GetIfTable(if_table
, &size
, TRUE
) == ERROR_SUCCESS
) {
372 for (i
= 0; i
< if_table
->dwNumEntries
; i
++) {
373 ret
= g_list_prepend (ret
, g_strdup ((gchar
*)if_table
->table
[i
].bDescr
));
382 GList
* nice_interfaces_get_local_ips (gboolean include_loopback
)
386 PMIB_IPADDRTABLE ip_table
;
389 GetIpAddrTable (NULL
, &size
, TRUE
);
395 * Get the best interface for transport to 0.0.0.0.
396 * This interface should be first in list!
398 if (GetBestInterface (0, &pref
) != NO_ERROR
)
401 ip_table
= (PMIB_IPADDRTABLE
)g_malloc0 (size
);
403 if (GetIpAddrTable (ip_table
, &size
, TRUE
) == ERROR_SUCCESS
) {
405 for (i
= 0; i
< ip_table
->dwNumEntries
; i
++) {
407 PMIB_IPADDRROW ipaddr
= &ip_table
->table
[i
];
409 if (!(ipaddr
->wType
& (MIB_IPADDR_DISCONNECTED
| MIB_IPADDR_DELETED
)) &&
411 if (!include_loopback
) {
413 PMIB_IFROW ifr
= (PMIB_IFROW
)g_malloc0 (sizeof (MIB_IFROW
));
414 ifr
->dwIndex
= ipaddr
->dwIndex
;
415 if (GetIfEntry (ifr
) == NO_ERROR
)
419 if (type
== IF_TYPE_SOFTWARE_LOOPBACK
)
423 ipstr
= g_strdup_printf ("%d.%d.%d.%d",
424 (ipaddr
->dwAddr
) & 0xFF,
425 (ipaddr
->dwAddr
>> 8) & 0xFF,
426 (ipaddr
->dwAddr
>> 16) & 0xFF,
427 (ipaddr
->dwAddr
>> 24) & 0xFF);
428 if (ipaddr
->dwIndex
== pref
)
429 ret
= g_list_prepend (ret
, ipstr
);
431 ret
= g_list_append (ret
, ipstr
);
442 * returns ip address as an utf8 string
445 win32_get_ip_for_interface (IF_INDEX idx
)
448 PMIB_IPADDRTABLE ip_table
;
451 GetIpAddrTable (NULL
, &size
, TRUE
);
456 ip_table
= (PMIB_IPADDRTABLE
)g_malloc0 (size
);
458 if (GetIpAddrTable (ip_table
, &size
, TRUE
) == ERROR_SUCCESS
) {
460 for (i
= 0; i
< ip_table
->dwNumEntries
; i
++) {
461 PMIB_IPADDRROW ipaddr
= &ip_table
->table
[i
];
462 if (ipaddr
->dwIndex
== idx
&&
463 !(ipaddr
->wType
& (MIB_IPADDR_DISCONNECTED
| MIB_IPADDR_DELETED
))) {
464 ret
= g_strdup_printf ("%d.%d.%d.%d",
465 (ipaddr
->dwAddr
) & 0xFF,
466 (ipaddr
->dwAddr
>> 8) & 0xFF,
467 (ipaddr
->dwAddr
>> 16) & 0xFF,
468 (ipaddr
->dwAddr
>> 24) & 0xFF);
478 gchar
* nice_interfaces_get_ip_for_interface (gchar
*interface_name
)
481 PMIB_IFTABLE if_table
;
484 GetIfTable (NULL
, &size
, TRUE
);
489 if_table
= (PMIB_IFTABLE
)g_malloc0 (size
);
491 if (GetIfTable (if_table
, &size
, TRUE
) == ERROR_SUCCESS
) {
494 for (i
= 0; i
< if_table
->dwNumEntries
; i
++) {
495 tmp_str
= g_utf16_to_utf8 (
496 if_table
->table
[i
].wszName
, MAX_INTERFACE_NAME_LEN
,
499 if (strlen (interface_name
) == strlen (tmp_str
) &&
500 g_ascii_strncasecmp (interface_name
, tmp_str
, strlen (interface_name
)) == 0) {
501 ret
= win32_get_ip_for_interface (if_table
->table
[i
].dwIndex
);
516 #else /* G_OS_WIN32 */
517 #error Can not use this method for retreiving ip list from OS other than unix or windows
518 #endif /* G_OS_WIN32 */
519 #endif /* G_OS_UNIX */