comparison libpurple/network.c @ 29372:529233281dfe

network: Use getifaddrs() to enumerate local interfaces/IPs if available. On Linux, it seems SIOCGIFCONF just doesn't support IPv6, and various systems have getifaddrs(), so here we are. Fixes #10160.
author Paul Aurich <paul@darkrain42.org>
date Tue, 16 Feb 2010 02:21:33 +0000
parents ecd1aa92fd57
children ce3f4bd8939b
comparison
equal deleted inserted replaced
29371:667806b1f359 29372:529233281dfe
30 #include <arpa/nameser.h> 30 #include <arpa/nameser.h>
31 #include <resolv.h> 31 #include <resolv.h>
32 #include <netinet/in.h> 32 #include <netinet/in.h>
33 #include <net/if.h> 33 #include <net/if.h>
34 #include <sys/ioctl.h> 34 #include <sys/ioctl.h>
35 #ifdef HAVE_GETIFADDRS
36 #include <ifaddrs.h>
37 #endif
35 #else 38 #else
36 #include <nspapi.h> 39 #include <nspapi.h>
37 #endif 40 #endif
38 41
39 /* Solaris */ 42 /* Solaris */
201 } 204 }
202 205
203 GList * 206 GList *
204 purple_network_get_all_local_system_ips(void) 207 purple_network_get_all_local_system_ips(void)
205 { 208 {
209 #ifdef HAVE_GETIFADDRS
210 GList *result = NULL;
211 struct ifaddrs *start, *ifa;
212 int ret;
213
214 ret = getifaddrs(&start);
215 if (ret < 0) {
216 purple_debug_warning("network",
217 "getifaddrs() failed: %s\n", g_strerror(errno));
218 return NULL;
219 }
220
221 for (ifa = start; ifa; ifa = ifa->ifa_next) {
222 int family = ifa->ifa_addr ? ifa->ifa_addr->sa_family : AF_UNSPEC;
223 char host[INET6_ADDRSTRLEN];
224 const char *tmp = NULL;
225
226 if ((family != AF_INET && family != AF_INET6) || ifa->ifa_flags & IFF_LOOPBACK)
227 continue;
228
229 if (family == AF_INET)
230 tmp = inet_ntop(family, &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr, host, sizeof(host));
231 else {
232 struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)ifa->ifa_addr;
233 /* Peer-peer link-local communication is a big TODO. I am not sure
234 * how communicating link-local addresses is supposed to work, and
235 * it seems like it would require attempting the cartesian product
236 * of the local and remote interfaces to see if any match (eww).
237 */
238 if (!IN6_IS_ADDR_LINKLOCAL(&sockaddr->sin6_addr))
239 tmp = inet_ntop(family, &sockaddr->sin6_addr, host, sizeof(host));
240 }
241 if (tmp != NULL)
242 result = g_list_prepend(result, g_strdup(tmp));
243 }
244
245 freeifaddrs(start);
246
247 return g_list_reverse(result);
248 #else /* HAVE_GETIFADDRS */
206 GList *result = NULL; 249 GList *result = NULL;
207 int source = socket(PF_INET,SOCK_STREAM, 0); 250 int source = socket(PF_INET,SOCK_STREAM, 0);
208 char buffer[1024]; 251 char buffer[1024];
209 char *tmp; 252 char *tmp;
210 struct ifconf ifc; 253 struct ifconf ifc;
220 char dst[INET_ADDRSTRLEN]; 263 char dst[INET_ADDRSTRLEN];
221 264
222 ifr = (struct ifreq *)tmp; 265 ifr = (struct ifreq *)tmp;
223 tmp += HX_SIZE_OF_IFREQ(*ifr); 266 tmp += HX_SIZE_OF_IFREQ(*ifr);
224 267
225 /* TODO: handle IPv6 */
226 if (ifr->ifr_addr.sa_family == AF_INET) { 268 if (ifr->ifr_addr.sa_family == AF_INET) {
227 struct sockaddr_in *sinptr = (struct sockaddr_in *)&ifr->ifr_addr; 269 struct sockaddr_in *sinptr = (struct sockaddr_in *)&ifr->ifr_addr;
228 270
229 inet_ntop(AF_INET, &sinptr->sin_addr, dst, 271 inet_ntop(AF_INET, &sinptr->sin_addr, dst,
230 sizeof(dst)); 272 sizeof(dst));
235 } 277 }
236 } 278 }
237 } 279 }
238 280
239 return result; 281 return result;
282 #endif /* HAVE_GETIFADDRS */
240 } 283 }
241 284
242 const char * 285 const char *
243 purple_network_get_my_ip(int fd) 286 purple_network_get_my_ip(int fd)
244 { 287 {