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>
45 #ifdef HAVE_GETIFADDRS
50 #include <net/if_arp.h>
51 #include <arpa/inet.h>
53 #ifdef HAVE_GETIFADDRS
56 nice_interfaces_get_local_interfaces (void)
58 GList
*interfaces
= NULL
;
59 struct ifaddrs
*ifa
, *results
;
61 if (getifaddrs (&results
) < 0) {
65 /* Loop and get each interface the system has, one by one... */
66 for (ifa
= results
; ifa
; ifa
= ifa
->ifa_next
) {
67 /* no ip address from interface that is down */
68 if ((ifa
->ifa_flags
& IFF_UP
) == 0)
71 if (ifa
->ifa_addr
== NULL
|| ifa
->ifa_addr
->sa_family
!= AF_INET
)
74 nice_debug ("Found interface : %s", ifa
->ifa_name
);
75 interfaces
= g_list_prepend (interfaces
, g_strdup (ifa
->ifa_name
));
78 freeifaddrs (results
);
83 #else /* ! HAVE_GETIFADDRS */
86 nice_interfaces_get_local_interfaces (void)
88 GList
*interfaces
= NULL
;
94 if ((sockfd
= socket (AF_INET
, SOCK_DGRAM
, IPPROTO_IP
)) < 0) {
95 nice_debug ("error : Cannot open socket to retreive interface list");
102 /* Loop and get each interface the system has, one by one... */
104 size
+= sizeof (struct ifreq
);
105 /* realloc buffer size until no overflow occurs */
106 if (NULL
== (ifc
.ifc_req
= realloc (ifc
.ifc_req
, size
))) {
107 nice_debug ("Error : Out of memory while allocation interface"
108 "configuration structure");
114 if (ioctl (sockfd
, SIOCGIFCONF
, &ifc
)) {
115 perror ("ioctl SIOCFIFCONF");
120 } while (size
<= ifc
.ifc_len
);
123 /* Loop throught the interface list and get the IP address of each IF */
124 for (ifr
= ifc
.ifc_req
;
125 (gchar
*) ifr
< (gchar
*) ifc
.ifc_req
+ ifc
.ifc_len
;
127 nice_debug ("Found interface : %s", ifr
->ifr_name
);
128 interfaces
= g_list_prepend (interfaces
, g_strdup (ifr
->ifr_name
));
136 #endif /* HAVE_GETIFADDRS */
140 nice_interfaces_is_private_ip (const struct in_addr in
)
143 if (in
.s_addr
>> 24 == 0x0A)
146 /* 172.16.0.0 - 172.31.255.255 = 172.16.0.0/10 */
147 if (in
.s_addr
>> 20 == 0xAC1)
151 if (in
.s_addr
>> 16 == 0xC0A8)
154 /* 169.254.x.x/16 (for APIPA) */
155 if (in
.s_addr
>> 16 == 0xA9FE)
161 #ifdef HAVE_GETIFADDRS
164 nice_interfaces_get_local_ips (gboolean include_loopback
)
167 struct sockaddr_in
*sa
;
168 struct ifaddrs
*ifa
, *results
;
169 gchar
*loopback
= NULL
;
172 if (getifaddrs (&results
) < 0)
175 /* Loop through the interface list and get the IP address of each IF */
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
|| ifa
->ifa_addr
->sa_family
!= AF_INET
)
184 sa
= (struct sockaddr_in
*) ifa
->ifa_addr
;
186 nice_debug ("Interface: %s", ifa
->ifa_name
);
187 nice_debug ("IP Address: %s", inet_ntoa (sa
->sin_addr
));
188 if ((ifa
->ifa_flags
& IFF_LOOPBACK
) == IFF_LOOPBACK
) {
189 if (include_loopback
)
190 loopback
= g_strdup (inet_ntoa (sa
->sin_addr
));
192 nice_debug ("Ignoring loopback interface");
194 if (nice_interfaces_is_private_ip (sa
->sin_addr
))
195 ips
= g_list_append (ips
, g_strdup (inet_ntoa (sa
->sin_addr
)));
197 ips
= g_list_prepend (ips
, g_strdup (inet_ntoa (sa
->sin_addr
)));
201 freeifaddrs (results
);
204 ips
= g_list_append (ips
, loopback
);
209 #else /* ! HAVE_GETIFADDRS */
212 nice_interfaces_get_local_ips (gboolean include_loopback
)
219 struct sockaddr_in
*sa
;
220 gchar
*loopback
= NULL
;
222 if ((sockfd
= socket (AF_INET
, SOCK_DGRAM
, IPPROTO_IP
)) < 0) {
223 nice_debug ("Error : Cannot open socket to retreive interface list");
230 /* Loop and get each interface the system has, one by one... */
232 size
+= sizeof (struct ifreq
);
233 /* realloc buffer size until no overflow occurs */
234 if (NULL
== (ifc
.ifc_req
= realloc (ifc
.ifc_req
, size
))) {
235 nice_debug ("Error : Out of memory while allocation interface"
236 " configuration structure");
242 if (ioctl (sockfd
, SIOCGIFCONF
, &ifc
)) {
243 perror ("ioctl SIOCFIFCONF");
248 } while (size
<= ifc
.ifc_len
);
251 /* Loop throught the interface list and get the IP address of each IF */
252 for (ifr
= ifc
.ifc_req
;
253 (gchar
*) ifr
< (gchar
*) ifc
.ifc_req
+ ifc
.ifc_len
;
256 if (ioctl (sockfd
, SIOCGIFFLAGS
, ifr
)) {
257 nice_debug ("Error : Unable to get IP information for interface %s."
258 " Skipping...", ifr
->ifr_name
);
259 continue; /* failed to get flags, skip it */
261 sa
= (struct sockaddr_in
*) &ifr
->ifr_addr
;
262 nice_debug ("Interface: %s", ifr
->ifr_name
);
263 nice_debug ("IP Address: %s", inet_ntoa (sa
->sin_addr
));
264 if ((ifr
->ifr_flags
& IFF_LOOPBACK
) == IFF_LOOPBACK
){
265 if (include_loopback
)
266 loopback
= g_strdup (inet_ntoa (sa
->sin_addr
));
268 nice_debug ("Ignoring loopback interface");
270 if (nice_interfaces_is_private_ip (sa
->sin_addr
)) {
271 ips
= g_list_append (ips
, g_strdup (inet_ntoa (sa
->sin_addr
)));
273 ips
= g_list_prepend (ips
, g_strdup (inet_ntoa (sa
->sin_addr
)));
282 ips
= g_list_append (ips
, loopback
);
287 #endif /* HAVE_GETIFADDRS */
290 nice_interfaces_get_ip_for_interface (gchar
*interface_name
)
293 struct sockaddr_in
*sa
;
297 ifr
.ifr_addr
.sa_family
= AF_INET
;
298 memset (ifr
.ifr_name
, 0, sizeof (ifr
.ifr_name
));
299 g_strlcpy (ifr
.ifr_name
, interface_name
, sizeof (ifr
.ifr_name
));
301 if ((sockfd
= socket (AF_INET
, SOCK_DGRAM
, IPPROTO_IP
)) < 0) {
302 nice_debug ("Error : Cannot open socket to retreive interface list");
306 if (ioctl (sockfd
, SIOCGIFADDR
, &ifr
) < 0) {
307 nice_debug ("Error : Unable to get IP information for interface %s",
314 sa
= (struct sockaddr_in
*) &ifr
.ifr_addr
;
315 nice_debug ("Address for %s: %s", interface_name
, inet_ntoa (sa
->sin_addr
));
316 return g_strdup (inet_ntoa (sa
->sin_addr
));
319 #else /* G_OS_UNIX */
322 #include <winsock2.h>
323 #include <Iphlpapi.h>
325 static gboolean started_wsa_engine
= FALSE
;
328 * private function that initializes the WinSock engine and
329 * returns a prebuilt socket
331 SOCKET
nice_interfaces_get_WSA_socket ()
333 WORD wVersionRequested
;
338 if (started_wsa_engine
== FALSE
) {
339 wVersionRequested
= MAKEWORD ( 2, 0 );
341 err
= WSAStartup ( wVersionRequested
, &wsaData
);
343 nice_debug ("Error : Could not start the winsocket engine");
344 return INVALID_SOCKET
;
346 started_wsa_engine
= TRUE
;
350 if ((sock
= socket (AF_INET
, SOCK_DGRAM
, 0)) == INVALID_SOCKET
) {
351 nice_debug ("Error : Could not open socket to retreive interface list,"
352 " error no : %d", WSAGetLastError ());
353 return INVALID_SOCKET
;
359 GList
* nice_interfaces_get_local_interfaces ()
362 PMIB_IFTABLE if_table
;
365 GetIfTable(NULL
, &size
, TRUE
);
370 if_table
= (PMIB_IFTABLE
)g_malloc0(size
);
372 if (GetIfTable(if_table
, &size
, TRUE
) == ERROR_SUCCESS
) {
374 for (i
= 0; i
< if_table
->dwNumEntries
; i
++) {
375 ret
= g_list_prepend (ret
, g_strdup ((gchar
*)if_table
->table
[i
].bDescr
));
384 GList
* nice_interfaces_get_local_ips (gboolean include_loopback
)
388 PMIB_IPADDRTABLE ip_table
;
391 GetIpAddrTable (NULL
, &size
, TRUE
);
397 * Get the best interface for transport to 0.0.0.0.
398 * This interface should be first in list!
400 if (GetBestInterface (0, &pref
) != NO_ERROR
)
403 ip_table
= (PMIB_IPADDRTABLE
)g_malloc0 (size
);
405 if (GetIpAddrTable (ip_table
, &size
, TRUE
) == ERROR_SUCCESS
) {
407 for (i
= 0; i
< ip_table
->dwNumEntries
; i
++) {
409 PMIB_IPADDRROW ipaddr
= &ip_table
->table
[i
];
411 if (!(ipaddr
->wType
& (MIB_IPADDR_DISCONNECTED
| MIB_IPADDR_DELETED
)) &&
413 if (!include_loopback
) {
415 PMIB_IFROW ifr
= (PMIB_IFROW
)g_malloc0 (sizeof (MIB_IFROW
));
416 ifr
->dwIndex
= ipaddr
->dwIndex
;
417 if (GetIfEntry (ifr
) == NO_ERROR
)
421 if (type
== IF_TYPE_SOFTWARE_LOOPBACK
)
425 ipstr
= g_strdup_printf ("%d.%d.%d.%d",
426 (ipaddr
->dwAddr
) & 0xFF,
427 (ipaddr
->dwAddr
>> 8) & 0xFF,
428 (ipaddr
->dwAddr
>> 16) & 0xFF,
429 (ipaddr
->dwAddr
>> 24) & 0xFF);
430 if (ipaddr
->dwIndex
== pref
)
431 ret
= g_list_prepend (ret
, ipstr
);
433 ret
= g_list_append (ret
, ipstr
);
444 * returns ip address as an utf8 string
447 win32_get_ip_for_interface (IF_INDEX idx
)
450 PMIB_IPADDRTABLE ip_table
;
453 GetIpAddrTable (NULL
, &size
, TRUE
);
458 ip_table
= (PMIB_IPADDRTABLE
)g_malloc0 (size
);
460 if (GetIpAddrTable (ip_table
, &size
, TRUE
) == ERROR_SUCCESS
) {
462 for (i
= 0; i
< ip_table
->dwNumEntries
; i
++) {
463 PMIB_IPADDRROW ipaddr
= &ip_table
->table
[i
];
464 if (ipaddr
->dwIndex
== idx
&&
465 !(ipaddr
->wType
& (MIB_IPADDR_DISCONNECTED
| MIB_IPADDR_DELETED
))) {
466 ret
= g_strdup_printf ("%d.%d.%d.%d",
467 (ipaddr
->dwAddr
) & 0xFF,
468 (ipaddr
->dwAddr
>> 8) & 0xFF,
469 (ipaddr
->dwAddr
>> 16) & 0xFF,
470 (ipaddr
->dwAddr
>> 24) & 0xFF);
480 gchar
* nice_interfaces_get_ip_for_interface (gchar
*interface_name
)
483 PMIB_IFTABLE if_table
;
486 GetIfTable (NULL
, &size
, TRUE
);
491 if_table
= (PMIB_IFTABLE
)g_malloc0 (size
);
493 if (GetIfTable (if_table
, &size
, TRUE
) == ERROR_SUCCESS
) {
496 for (i
= 0; i
< if_table
->dwNumEntries
; i
++) {
497 tmp_str
= g_utf16_to_utf8 (
498 if_table
->table
[i
].wszName
, MAX_INTERFACE_NAME_LEN
,
501 if (strlen (interface_name
) == strlen (tmp_str
) &&
502 g_ascii_strncasecmp (interface_name
, tmp_str
, strlen (interface_name
)) == 0) {
503 ret
= win32_get_ip_for_interface (if_table
->table
[i
].dwIndex
);
518 #else /* G_OS_WIN32 */
519 #error Can not use this method for retreiving ip list from OS other than unix or windows
520 #endif /* G_OS_WIN32 */
521 #endif /* G_OS_UNIX */