Don't pass the agent to the socket layer
[sipe-libnice.git] / agent / interfaces.c
blob01046d1922734e3a5628fa3dd592b1b5a214e85c
1 /*
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
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
29 #include "interfaces.h"
30 #include "debug.h"
32 #ifdef G_OS_UNIX
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <sys/ioctl.h>
40 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
45 #ifdef __sun
46 #include <sys/sockio.h>
47 #endif
49 #ifdef HAVE_GETIFADDRS
50 #include <ifaddrs.h>
51 #endif
53 #include <net/if.h>
54 #include <net/if_arp.h>
55 #include <arpa/inet.h>
57 #ifdef HAVE_GETIFADDRS
59 GList *
60 nice_interfaces_get_local_interfaces (void)
62 GList *interfaces = NULL;
63 struct ifaddrs *ifa, *results;
65 if (getifaddrs (&results) < 0) {
66 return NULL;
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)
73 continue;
75 if (ifa->ifa_addr == NULL)
76 continue;
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);
86 return interfaces;
89 #else /* ! HAVE_GETIFADDRS */
91 GList *
92 nice_interfaces_get_local_interfaces (void)
94 GList *interfaces = NULL;
95 gint sockfd;
96 gint size = 0;
97 struct ifreq *ifr;
98 struct ifconf ifc;
100 if ((sockfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
101 nice_debug ("error : Cannot open socket to retreive interface list");
102 return NULL;
105 ifc.ifc_len = 0;
106 ifc.ifc_req = NULL;
108 /* Loop and get each interface the system has, one by one... */
109 do {
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");
115 close (sockfd);
116 return NULL;
118 ifc.ifc_len = size;
120 if (ioctl (sockfd, SIOCGIFCONF, &ifc)) {
121 perror ("ioctl SIOCFIFCONF");
122 close (sockfd);
123 free (ifc.ifc_req);
124 return NULL;
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;
132 ++ifr) {
133 nice_debug ("Found interface : %s", ifr->ifr_name);
134 interfaces = g_list_prepend (interfaces, g_strdup (ifr->ifr_name));
137 free (ifc.ifc_req);
138 close (sockfd);
140 return interfaces;
142 #endif /* HAVE_GETIFADDRS */
145 static gboolean
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;
151 /* 10.x.x.x/8 */
152 if (sa4->sin_addr.s_addr >> 24 == 0x0A)
153 return TRUE;
155 /* 172.16.0.0 - 172.31.255.255 = 172.16.0.0/10 */
156 if (sa4->sin_addr.s_addr >> 20 == 0xAC1)
157 return TRUE;
159 /* 192.168.x.x/16 */
160 if (sa4->sin_addr.s_addr >> 16 == 0xC0A8)
161 return TRUE;
163 /* 169.254.x.x/16 (for APIPA) */
164 if (sa4->sin_addr.s_addr >> 16 == 0xA9FE)
165 return TRUE;
168 return FALSE;
171 #ifdef HAVE_GETIFADDRS
173 GList *
174 nice_interfaces_get_local_ips (gboolean include_loopback)
176 GList *ips = NULL;
177 struct ifaddrs *ifa, *results;
178 GList *loopbacks = NULL;
181 if (getifaddrs (&results) < 0)
182 return NULL;
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)
190 continue;
192 if (ifa->ifa_addr == NULL) {
193 continue;
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)
199 continue;
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))
205 continue;
207 if (inet_ntop (AF_INET6, &sa6->sin6_addr, addr_as_string,
208 INET6_ADDRSTRLEN) == NULL)
209 continue;
210 } else
211 continue;
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));
219 else
220 nice_debug ("Ignoring loopback interface");
221 } else {
222 if (nice_interfaces_is_private_ip (ifa->ifa_addr))
223 ips = g_list_append (ips, g_strdup (addr_as_string));
224 else
225 ips = g_list_prepend (ips, g_strdup (addr_as_string));
229 freeifaddrs (results);
231 if (loopbacks)
232 ips = g_list_concat (ips, loopbacks);
234 return ips;
237 #else /* ! HAVE_GETIFADDRS */
239 GList *
240 nice_interfaces_get_local_ips (gboolean include_loopback)
242 GList *ips = NULL;
243 gint sockfd;
244 gint size = 0;
245 struct ifreq *ifr;
246 struct ifconf ifc;
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");
252 return NULL;
255 ifc.ifc_len = 0;
256 ifc.ifc_req = NULL;
258 /* Loop and get each interface the system has, one by one... */
259 do {
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");
265 close (sockfd);
266 return NULL;
268 ifc.ifc_len = size;
270 if (ioctl (sockfd, SIOCGIFCONF, &ifc)) {
271 perror ("ioctl SIOCFIFCONF");
272 close (sockfd);
273 free (ifc.ifc_req);
274 return NULL;
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;
282 ++ifr) {
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));
295 else
296 nice_debug ("Ignoring loopback interface");
297 } else {
298 if (nice_interfaces_is_private_ip (sa)) {
299 ips = g_list_append (ips, g_strdup (inet_ntoa (sa->sin_addr)));
300 } else {
301 ips = g_list_prepend (ips, g_strdup (inet_ntoa (sa->sin_addr)));
306 close (sockfd);
307 free (ifc.ifc_req);
309 if (loopback)
310 ips = g_list_append (ips, loopback);
312 return ips;
315 #endif /* HAVE_GETIFADDRS */
317 gchar *
318 nice_interfaces_get_ip_for_interface (gchar *interface_name)
320 struct ifreq ifr;
321 struct sockaddr_in *sa;
322 gint sockfd;
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");
331 return NULL;
334 if (ioctl (sockfd, SIOCGIFADDR, &ifr) < 0) {
335 nice_debug ("Error : Unable to get IP information for interface %s",
336 interface_name);
337 close (sockfd);
338 return NULL;
341 close (sockfd);
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 */
348 #ifdef G_OS_WIN32
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;
362 WSADATA wsaData;
363 int err;
364 SOCKET sock;
366 if (started_wsa_engine == FALSE) {
367 wVersionRequested = MAKEWORD ( 2, 0 );
369 err = WSAStartup ( wVersionRequested, &wsaData );
370 if ( err != 0 ) {
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;
384 return sock;
387 GList * nice_interfaces_get_local_interfaces ()
389 ULONG size = 0;
390 PMIB_IFTABLE if_table;
391 GList * ret = NULL;
393 GetIfTable(NULL, &size, TRUE);
395 if (!size)
396 return NULL;
398 if_table = (PMIB_IFTABLE)g_malloc0(size);
400 if (GetIfTable(if_table, &size, TRUE) == ERROR_SUCCESS) {
401 DWORD i;
402 for (i = 0; i < if_table->dwNumEntries; i++) {
403 ret = g_list_prepend (ret, g_strdup ((gchar*)if_table->table[i].bDescr));
407 g_free(if_table);
409 return ret;
412 GList * nice_interfaces_get_local_ips (gboolean include_loopback)
414 ULONG size = 0;
415 DWORD pref = 0;
416 PMIB_IPADDRTABLE ip_table;
417 GList * ret = NULL;
419 GetIpAddrTable (NULL, &size, TRUE);
421 if (!size)
422 return NULL;
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)
429 pref = 0;
431 ip_table = (PMIB_IPADDRTABLE)g_malloc0 (size);
433 if (GetIpAddrTable (ip_table, &size, TRUE) == ERROR_SUCCESS) {
434 DWORD i;
435 for (i = 0; i < ip_table->dwNumEntries; i++) {
436 gchar * ipstr;
437 PMIB_IPADDRROW ipaddr = &ip_table->table[i];
439 if (!(ipaddr->wType & (MIB_IPADDR_DISCONNECTED | MIB_IPADDR_DELETED)) &&
440 ipaddr->dwAddr) {
441 if (!include_loopback) {
442 DWORD type = 0;
443 PMIB_IFROW ifr = (PMIB_IFROW)g_malloc0 (sizeof (MIB_IFROW));
444 ifr->dwIndex = ipaddr->dwIndex;
445 if (GetIfEntry (ifr) == NO_ERROR)
446 type = ifr->dwType;
447 g_free (ifr);
449 if (type == IF_TYPE_SOFTWARE_LOOPBACK)
450 continue;
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);
460 else
461 ret = g_list_append (ret, ipstr);
466 g_free(ip_table);
468 return ret;
472 * returns ip address as an utf8 string
474 static gchar *
475 win32_get_ip_for_interface (IF_INDEX idx)
477 ULONG size = 0;
478 PMIB_IPADDRTABLE ip_table;
479 gchar * ret = NULL;
481 GetIpAddrTable (NULL, &size, TRUE);
483 if (!size)
484 return NULL;
486 ip_table = (PMIB_IPADDRTABLE)g_malloc0 (size);
488 if (GetIpAddrTable (ip_table, &size, TRUE) == ERROR_SUCCESS) {
489 DWORD i;
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);
499 break;
504 g_free (ip_table);
505 return ret;
508 gchar * nice_interfaces_get_ip_for_interface (gchar *interface_name)
510 ULONG size = 0;
511 PMIB_IFTABLE if_table;
512 gchar * ret = NULL;
514 GetIfTable (NULL, &size, TRUE);
516 if (!size)
517 return NULL;
519 if_table = (PMIB_IFTABLE)g_malloc0 (size);
521 if (GetIfTable (if_table, &size, TRUE) == ERROR_SUCCESS) {
522 DWORD i;
523 gchar * tmp_str;
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,
527 NULL, NULL, NULL);
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);
532 g_free (tmp_str);
533 break;
536 g_free (tmp_str);
540 g_free (if_table);
542 return ret;
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 */