use g_strlcpy instead of strncpy for nice_interfaces_get_ip_for_interface too
[sipe-libnice.git] / agent / interfaces.c
blob431263a8844a96de78f5f3e705f555417a01cca3
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 * 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
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
28 #include "interfaces.h"
29 #include "debug.h"
31 #ifdef G_OS_UNIX
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <sys/ioctl.h>
39 #include <sys/types.h>
41 #include <sys/socket.h>
43 #ifdef HAVE_GETIFADDRS
44 #include <ifaddrs.h>
45 #endif
47 #include <net/if.h>
48 #include <net/if_arp.h>
49 #include <arpa/inet.h>
51 #ifdef HAVE_GETIFADDRS
53 GList *
54 nice_interfaces_get_local_interfaces (void)
56 GList *interfaces = NULL;
57 struct ifaddrs *ifa, *results;
59 if (getifaddrs (&results) < 0) {
60 return NULL;
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)
67 continue;
69 if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET)
70 continue;
72 nice_debug ("Found interface : %s", ifa->ifa_name);
73 interfaces = g_list_prepend (interfaces, g_strdup (ifa->ifa_name));
76 freeifaddrs (results);
78 return interfaces;
81 #else /* ! HAVE_GETIFADDRS */
83 GList *
84 nice_interfaces_get_local_interfaces (void)
86 GList *interfaces = NULL;
87 gint sockfd;
88 gint size = 0;
89 struct ifreq *ifr;
90 struct ifconf ifc;
92 if ((sockfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
93 nice_debug ("error : Cannot open socket to retreive interface list");
94 return NULL;
97 ifc.ifc_len = 0;
98 ifc.ifc_req = NULL;
100 /* Loop and get each interface the system has, one by one... */
101 do {
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");
107 close (sockfd);
108 return NULL;
110 ifc.ifc_len = size;
112 if (ioctl (sockfd, SIOCGIFCONF, &ifc)) {
113 perror ("ioctl SIOCFIFCONF");
114 close (sockfd);
115 free (ifc.ifc_req);
116 return NULL;
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;
124 ++ifr) {
125 nice_debug ("Found interface : %s", ifr->ifr_name);
126 interfaces = g_list_prepend (interfaces, g_strdup (ifr->ifr_name));
129 free (ifc.ifc_req);
130 close (sockfd);
132 return interfaces;
134 #endif /* HAVE_GETIFADDRS */
137 static gboolean
138 nice_interfaces_is_private_ip (const struct in_addr in)
140 /* 10.x.x.x/8 */
141 if (in.s_addr >> 24 == 0x0A)
142 return TRUE;
144 /* 172.16.0.0 - 172.31.255.255 = 172.16.0.0/10 */
145 if (in.s_addr >> 20 == 0xAC1)
146 return TRUE;
148 /* 192.168.x.x/16 */
149 if (in.s_addr >> 16 == 0xC0A8)
150 return TRUE;
152 /* 169.254.x.x/16 (for APIPA) */
153 if (in.s_addr >> 16 == 0xA9FE)
154 return TRUE;
156 return FALSE;
159 #ifdef HAVE_GETIFADDRS
161 GList *
162 nice_interfaces_get_local_ips (gboolean include_loopback)
164 GList *ips = NULL;
165 struct sockaddr_in *sa;
166 struct ifaddrs *ifa, *results;
167 gchar *loopback = NULL;
170 if (getifaddrs (&results) < 0)
171 return NULL;
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)
177 continue;
179 if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET)
180 continue;
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));
189 else
190 nice_debug ("Ignoring loopback interface");
191 } else {
192 if (nice_interfaces_is_private_ip (sa->sin_addr))
193 ips = g_list_append (ips, g_strdup (inet_ntoa (sa->sin_addr)));
194 else
195 ips = g_list_prepend (ips, g_strdup (inet_ntoa (sa->sin_addr)));
199 freeifaddrs (results);
201 if (loopback)
202 ips = g_list_append (ips, loopback);
204 return ips;
207 #else /* ! HAVE_GETIFADDRS */
209 GList *
210 nice_interfaces_get_local_ips (gboolean include_loopback)
212 GList *ips = NULL;
213 gint sockfd;
214 gint size = 0;
215 struct ifreq *ifr;
216 struct ifconf ifc;
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");
222 return NULL;
225 ifc.ifc_len = 0;
226 ifc.ifc_req = NULL;
228 /* Loop and get each interface the system has, one by one... */
229 do {
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");
235 close (sockfd);
236 return NULL;
238 ifc.ifc_len = size;
240 if (ioctl (sockfd, SIOCGIFCONF, &ifc)) {
241 perror ("ioctl SIOCFIFCONF");
242 close (sockfd);
243 free (ifc.ifc_req);
244 return NULL;
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;
252 ++ifr) {
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));
265 else
266 nice_debug ("Ignoring loopback interface");
267 } else {
268 if (nice_interfaces_is_private_ip (sa->sin_addr)) {
269 ips = g_list_append (ips, g_strdup (inet_ntoa (sa->sin_addr)));
270 } else {
271 ips = g_list_prepend (ips, g_strdup (inet_ntoa (sa->sin_addr)));
276 close (sockfd);
277 free (ifc.ifc_req);
279 if (loopback)
280 ips = g_list_append (ips, loopback);
282 return ips;
285 #endif /* HAVE_GETIFADDRS */
287 gchar *
288 nice_interfaces_get_ip_for_interface (gchar *interface_name)
290 struct ifreq ifr;
291 struct sockaddr_in *sa;
292 gint sockfd;
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");
301 return NULL;
304 if (ioctl (sockfd, SIOCGIFADDR, &ifr) < 0) {
305 nice_debug ("Error : Unable to get IP information for interface %s",
306 interface_name);
307 close (sockfd);
308 return NULL;
311 close (sockfd);
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 */
318 #ifdef G_OS_WIN32
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;
332 WSADATA wsaData;
333 int err;
334 SOCKET sock;
336 if (started_wsa_engine == FALSE) {
337 wVersionRequested = MAKEWORD ( 2, 0 );
339 err = WSAStartup ( wVersionRequested, &wsaData );
340 if ( err != 0 ) {
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;
354 return sock;
357 GList * nice_interfaces_get_local_interfaces ()
359 ULONG size = 0;
360 PMIB_IFTABLE if_table;
361 GList * ret = NULL;
363 GetIfTable(NULL, &size, TRUE);
365 if (!size)
366 return NULL;
368 if_table = (PMIB_IFTABLE)g_malloc0(size);
370 if (GetIfTable(if_table, &size, TRUE) == ERROR_SUCCESS) {
371 DWORD i;
372 for (i = 0; i < if_table->dwNumEntries; i++) {
373 ret = g_list_prepend (ret, g_strdup ((gchar*)if_table->table[i].bDescr));
377 g_free(if_table);
379 return ret;
382 GList * nice_interfaces_get_local_ips (gboolean include_loopback)
384 ULONG size = 0;
385 DWORD pref = 0;
386 PMIB_IPADDRTABLE ip_table;
387 GList * ret = NULL;
389 GetIpAddrTable (NULL, &size, TRUE);
391 if (!size)
392 return NULL;
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)
399 pref = 0;
401 ip_table = (PMIB_IPADDRTABLE)g_malloc0 (size);
403 if (GetIpAddrTable (ip_table, &size, TRUE) == ERROR_SUCCESS) {
404 DWORD i;
405 for (i = 0; i < ip_table->dwNumEntries; i++) {
406 gchar * ipstr;
407 PMIB_IPADDRROW ipaddr = &ip_table->table[i];
409 if (!(ipaddr->wType & (MIB_IPADDR_DISCONNECTED | MIB_IPADDR_DELETED)) &&
410 ipaddr->dwAddr) {
411 if (!include_loopback) {
412 DWORD type = 0;
413 PMIB_IFROW ifr = (PMIB_IFROW)g_malloc0 (sizeof (MIB_IFROW));
414 ifr->dwIndex = ipaddr->dwIndex;
415 if (GetIfEntry (ifr) == NO_ERROR)
416 type = ifr->dwType;
417 g_free (ifr);
419 if (type == IF_TYPE_SOFTWARE_LOOPBACK)
420 continue;
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);
430 else
431 ret = g_list_append (ret, ipstr);
436 g_free(ip_table);
438 return ret;
442 * returns ip address as an utf8 string
444 static gchar *
445 win32_get_ip_for_interface (IF_INDEX idx)
447 ULONG size = 0;
448 PMIB_IPADDRTABLE ip_table;
449 gchar * ret = NULL;
451 GetIpAddrTable (NULL, &size, TRUE);
453 if (!size)
454 return NULL;
456 ip_table = (PMIB_IPADDRTABLE)g_malloc0 (size);
458 if (GetIpAddrTable (ip_table, &size, TRUE) == ERROR_SUCCESS) {
459 DWORD i;
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);
469 break;
474 g_free (ip_table);
475 return ret;
478 gchar * nice_interfaces_get_ip_for_interface (gchar *interface_name)
480 ULONG size = 0;
481 PMIB_IFTABLE if_table;
482 gchar * ret = NULL;
484 GetIfTable (NULL, &size, TRUE);
486 if (!size)
487 return NULL;
489 if_table = (PMIB_IFTABLE)g_malloc0 (size);
491 if (GetIfTable (if_table, &size, TRUE) == ERROR_SUCCESS) {
492 DWORD i;
493 gchar * tmp_str;
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,
497 NULL, NULL, NULL);
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);
502 g_free (tmp_str);
503 break;
506 g_free (tmp_str);
510 g_free (if_table);
512 return ret;
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 */