X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Futil%2Fos_network.c;h=5e4546d0877ca95083b54cb8a268be4774084af1;hb=1ac9ef013b0e9c737d6909ab41a38b45a3d36e43;hp=2835e61938f77a5e0814d0d473a6865631d38375;hpb=9089e3e35eb5e391da26401346a7a9277cd5e780;p=oweals%2Fgnunet.git diff --git a/src/util/os_network.c b/src/util/os_network.c index 2835e6193..5e4546d08 100644 --- a/src/util/os_network.c +++ b/src/util/os_network.c @@ -1,10 +1,10 @@ /* This file is part of GNUnet. - (C) 2004, 2005, 2006 Christian Grothoff (and other contributing authors) + Copyright (C) 2004, 2005, 2006, 2015 GNUnet e.V. GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2, or (at your + by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but @@ -14,283 +14,413 @@ You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ - /** * @file util/os_network.c * @brief function to determine available network interfaces * @author Nils Durner * @author Heikki Lindholm * @author Jake Dust + * @author LRN + * @author Christian Grothoff */ - #include "platform.h" -#include "gnunet_common.h" -#include "gnunet_os_lib.h" +#include "gnunet_util_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) + +#if ! (HAVE_GETIFADDRS && HAVE_FREEIFADDRS) /** - * @brief Enumerate all network interfaces + * Try to enumerate all network interfaces using 'ifconfig'. * * @param proc the callback function - * @param proc_cls closure for proc + * @param proc_cls closure for @a proc + * @return #GNUNET_OK if it worked */ -void -GNUNET_OS_network_interfaces_list (GNUNET_OS_NetworkInterfaceProcessor proc, - void *proc_cls) +static int +try_ifconfig (GNUNET_OS_NetworkInterfaceProcessor proc, + void *proc_cls) { -#ifdef MINGW - PMIB_IFTABLE pTable; - PMIB_IPADDRTABLE pAddrTable; - DWORD dwIfIdx, dwExternalNIC; - IPAddr theIP; - - /* Determine our external NIC */ - theIP = inet_addr ("192.0.34.166"); /* www.example.com */ - if ((!GNGetBestInterface) || - (GNGetBestInterface (theIP, &dwExternalNIC) != NO_ERROR)) - { - dwExternalNIC = 0; - } - - /* Enumerate NICs */ - EnumNICs (&pTable, &pAddrTable); - - if (pTable) - { - for (dwIfIdx = 0; dwIfIdx <= pTable->dwNumEntries; dwIfIdx++) - { - char szEntry[1001]; - DWORD dwIP = 0; - PIP_ADAPTER_INFO pAdapterInfo; - PIP_ADAPTER_INFO pAdapter = NULL; - DWORD dwRetVal = 0; - - /* Get IP-Address */ - int i; - - for (i = 0; i < pAddrTable->dwNumEntries; i++) - { - if (pAddrTable->table[i].dwIndex == - pTable->table[dwIfIdx].dwIndex) - { - dwIP = pAddrTable->table[i].dwAddr; - break; - } - } - - if (dwIP) - { - BYTE bPhysAddr[MAXLEN_PHYSADDR]; - char *pszIfName = NULL; - char dst[INET_ADDRSTRLEN]; - struct sockaddr_in sa; - - /* Get friendly interface name */ - pAdapterInfo = - (IP_ADAPTER_INFO *) malloc (sizeof (IP_ADAPTER_INFO)); - ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO); - - /* Make an initial call to GetAdaptersInfo to get - * the necessary size into the ulOutBufLen variable */ - if (GGetAdaptersInfo (pAdapterInfo, &ulOutBufLen) == - ERROR_BUFFER_OVERFLOW) - { - free (pAdapterInfo); - pAdapterInfo = (IP_ADAPTER_INFO *) malloc (ulOutBufLen); - } - - if ((dwRetVal = - GGetAdaptersInfo (pAdapterInfo, &ulOutBufLen)) == NO_ERROR) - { - pAdapter = pAdapterInfo; - while (pAdapter) - { - if (pTable->table[dwIfIdx].dwIndex == pAdapter->Index) - { - char szKey[251]; - long lLen = 250; - - sprintf (szKey, - "SYSTEM\\CurrentControlSet\\Control\\Network\\" - "{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", - pAdapter->AdapterName); - pszIfName = (char *) malloc (251); - if (QueryRegistry - (HKEY_LOCAL_MACHINE, szKey, "Name", pszIfName, - &lLen) != ERROR_SUCCESS) - { - free (pszIfName); - pszIfName = NULL; - } - } - pAdapter = pAdapter->Next; - } - } - free (pAdapterInfo); - - /* Set entry */ - memset (bPhysAddr, 0, MAXLEN_PHYSADDR); - memcpy (bPhysAddr, pTable->table[dwIfIdx].bPhysAddr, - pTable->table[dwIfIdx].dwPhysAddrLen); - - snprintf (szEntry, 1000, "%s (%s - %I64u)", - pszIfName ? pszIfName : (char *) - pTable->table[dwIfIdx].bDescr, inet_ntop (AF_INET, - &dwIP, dst, - INET_ADDRSTRLEN), - *((unsigned long long *) bPhysAddr)); - szEntry[1000] = 0; - - if (pszIfName) - free (pszIfName); - - sa.sin_family = AF_INET; -#if HAVE_SOCKADDR_IN_SIN_LEN - sa.sin_len = (u_char) sizeof (struct sockaddr_in); -#endif - sa.sin_addr.S_un.S_addr = dwIP; - - if (GNUNET_OK != - proc (proc_cls, szEntry, - pTable->table[dwIfIdx].dwIndex == dwExternalNIC, - (const struct sockaddr *) &sa, sizeof (sa))) - break; - } - } - GlobalFree (pAddrTable); - GlobalFree (pTable); - } - - return; - -#elif HAVE_GETIFADDRS && HAVE_FREEIFADDRS - - struct ifaddrs *ifa_first; - struct ifaddrs *ifa_ptr; - socklen_t alen; - - if (getifaddrs (&ifa_first) == 0) - { - for (ifa_ptr = ifa_first; ifa_ptr != NULL; ifa_ptr = ifa_ptr->ifa_next) - { - if (ifa_ptr->ifa_name != NULL && ifa_ptr->ifa_addr != NULL && - (ifa_ptr->ifa_flags & IFF_UP) != 0) - { - if ((ifa_ptr->ifa_addr->sa_family != AF_INET) && - (ifa_ptr->ifa_addr->sa_family != AF_INET6)) - continue; - if (ifa_ptr->ifa_addr->sa_family == AF_INET) - alen = sizeof (struct sockaddr_in); - else - alen = sizeof (struct sockaddr_in6); - if (GNUNET_OK != - proc (proc_cls, ifa_ptr->ifa_name, - 0 == strcmp (ifa_ptr->ifa_name, - GNUNET_DEFAULT_INTERFACE), - ifa_ptr->ifa_addr, alen)) - break; - } - } - freeifaddrs (ifa_first); - } -#else + int i; char line[1024]; + char *replace; const char *start; char ifc[12]; char addrstr[128]; + char bcstr[128]; + char netmaskstr[128]; FILE *f; int have_ifc; struct sockaddr_in a4; struct sockaddr_in6 a6; struct in_addr v4; struct in6_addr v6; + struct sockaddr_in bcaddr; + struct sockaddr_in netmask; + struct sockaddr_in6 netmask6; + struct sockaddr *pass_bcaddr; + struct sockaddr *pass_netmask; + int prefixlen; if (system ("ifconfig -a > /dev/null 2> /dev/null")) - if (system ("/sbin/ifconfig -a > /dev/null 2> /dev/null") == 0) + if (0 == system ("/sbin/ifconfig -a > /dev/null 2> /dev/null")) f = popen ("/sbin/ifconfig -a 2> /dev/null", "r"); else f = NULL; else f = popen ("ifconfig -a 2> /dev/null", "r"); - if (!f) - { - LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING | - GNUNET_ERROR_TYPE_BULK, "popen", "ifconfig"); - return; - } + if (! f) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, + "popen", + "ifconfig"); + + return GNUNET_SYSERR; + } have_ifc = GNUNET_NO; ifc[11] = '\0'; while (NULL != fgets (line, sizeof (line), f)) + { + if (strlen (line) == 0) + { + have_ifc = GNUNET_NO; + continue; + } + if (!isspace (line[0])) { - if (strlen (line) == 0) - { - have_ifc = GNUNET_NO; - continue; - } - if (!isspace (line[0])) - { - have_ifc = - (1 == SSCANF (line, "%11s", ifc)) ? GNUNET_YES : GNUNET_NO; - /* would end with ':' on OSX, fix it! */ - if (ifc[strlen (ifc) - 1] == ':') - ifc[strlen (ifc) - 1] = '\0'; - continue; - } - if (!have_ifc) - continue; /* strange input, hope for the best */ - start = line; - while (('\0' != *start) && (isspace (*start))) - start++; - if ( /* Linux */ - (1 == SSCANF (start, "inet addr:%127s", addrstr)) || - (1 == SSCANF (start, "inet6 addr:%127s", addrstr)) || - /* Solaris, OS X */ - (1 == SSCANF (start, "inet %127s", addrstr)) || - (1 == SSCANF (start, "inet6 %127s", addrstr))) - { - /* IPv4 */ - if (1 == inet_pton (AF_INET, addrstr, &v4)) - { - memset (&a4, 0, sizeof (a4)); - a4.sin_family = AF_INET; + have_ifc = (1 == SSCANF (line, "%11s", ifc)) ? GNUNET_YES : GNUNET_NO; + /* would end with ':' on OSX, fix it! */ + if (ifc[strlen (ifc) - 1] == ':') + ifc[strlen (ifc) - 1] = '\0'; + continue; + } + if (!have_ifc) + continue; /* strange input, hope for the best */ + + /* make parsing of ipv6 addresses easier */ + for (replace = line; *replace != '\0'; replace++) + { + if (*replace == '/') + *replace = ' '; + } + prefixlen = -1; + + start = line; + while (('\0' != *start) && (isspace (*start))) + start++; + + /* Zero-out stack allocated values */ + memset (addrstr, 0, 128); + memset (netmaskstr, 0, 128); + memset (bcstr, 0, 128); + prefixlen = 0; + + if ( /* Linux */ + (3 == SSCANF (start, "inet addr:%127s Bcast:%127s Mask:%127s", addrstr, bcstr, netmaskstr)) || + (2 == SSCANF (start, "inet addr:%127s Mask:%127s", addrstr, netmaskstr)) || + (2 == SSCANF (start, "inet6 addr:%127s %d", addrstr, &prefixlen)) || + /* Solaris, OS X */ + (1 == SSCANF (start, "inet %127s", addrstr)) || + (1 == SSCANF (start, "inet6 %127s", addrstr))) + { + /* IPv4 */ + if (1 == inet_pton (AF_INET, addrstr, &v4)) + { + memset (&a4, 0, sizeof (a4)); + a4.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + a4.sin_len = (u_char) sizeof (struct sockaddr_in); +#endif + a4.sin_addr = v4; + + pass_bcaddr = NULL; + pass_netmask = NULL; + if (1 == inet_pton (AF_INET, bcstr, &v4)) + { + memset (&bcaddr, 0, sizeof (bcaddr)); + bcaddr.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + bcaddr.sin_len = (u_char) sizeof (struct sockaddr_in); +#endif + bcaddr.sin_addr = v4; + pass_bcaddr = (struct sockaddr *) &bcaddr; + } + if (1 == inet_pton (AF_INET, netmaskstr, &v4)) + { + memset (&netmask, 0, sizeof (netmask)); + netmask.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN - a4.sin_len = (u_char) sizeof (struct sockaddr_in); + netmask.sin_len = (u_char) sizeof (struct sockaddr_in); #endif - a4.sin_addr = v4; - if (GNUNET_OK != - proc (proc_cls, ifc, - 0 == strcmp (ifc, GNUNET_DEFAULT_INTERFACE), - (const struct sockaddr *) &a4, sizeof (a4))) - break; - continue; - } - /* IPv6 */ - if (1 == inet_pton (AF_INET6, addrstr, &v6)) - { - memset (&a6, 0, sizeof (a6)); - a6.sin6_family = AF_INET6; + netmask.sin_addr = v4; + pass_netmask = (struct sockaddr *) &netmask; + } + + + if (GNUNET_OK != + proc (proc_cls, ifc, 0 == strcmp (ifc, GNUNET_DEFAULT_INTERFACE), + (const struct sockaddr *) &a4, + pass_bcaddr, pass_netmask, sizeof (a4))) + break; + continue; + } + /* IPv6 */ + if (1 == inet_pton (AF_INET6, addrstr, &v6)) + { + memset (&a6, 0, sizeof (a6)); + a6.sin6_family = AF_INET6; #if HAVE_SOCKADDR_IN_SIN_LEN - a6.sin6_len = (u_char) sizeof (struct sockaddr_in6); + a6.sin6_len = (u_char) sizeof (struct sockaddr_in6); #endif - a6.sin6_addr = v6; - if (GNUNET_OK != - proc (proc_cls, ifc, - 0 == strcmp (ifc, GNUNET_DEFAULT_INTERFACE), - (const struct sockaddr *) &a6, sizeof (a6))) - break; - continue; - } - } + a6.sin6_addr = v6; + + pass_netmask = NULL; + if (prefixlen != -1) + { + memset (v6.s6_addr, 0, sizeof (v6.s6_addr)); + for (i = 0; i < prefixlen; i++) + { + v6.s6_addr[i >> 3] |= 1 << (i & 7); + } + memset (&netmask6, 0, sizeof (netmask6)); + netmask6.sin6_family = AF_INET6; +#if HAVE_SOCKADDR_IN_SIN_LEN + netmask6.sin6_len = (u_char) sizeof (struct sockaddr_in6); +#endif + netmask6.sin6_addr = v6; + + pass_netmask = (struct sockaddr *) &netmask6; + } + + if (GNUNET_OK != + proc (proc_cls, ifc, 0 == strcmp (ifc, GNUNET_DEFAULT_INTERFACE), + (const struct sockaddr *) &a6, + NULL, pass_netmask, sizeof (a6))) + break; + continue; + } } + } pclose (f); + return GNUNET_OK; +} + + +/** + * Try to enumerate all network interfaces using 'ip'. + * + * @param proc the callback function + * @param proc_cls closure for @a proc + * @return #GNUNET_OK if it worked + */ +static int +try_ip (GNUNET_OS_NetworkInterfaceProcessor proc, + void *proc_cls) +{ + char line[1024]; + char *replace; + char ifname[64]; + char afstr[6]; + char addrstr[128]; + FILE *f; + struct sockaddr_in a4; + struct sockaddr_in6 a6; + struct in_addr v4; + struct in6_addr v6; + struct sockaddr_in netmask; + struct sockaddr_in6 netmask6; + unsigned int i; + unsigned int prefixlen; + + f = popen ("ip -o add 2> /dev/null", "r"); + if (! f) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, + "popen", + "ip"); + return GNUNET_SYSERR; + } + + while (NULL != fgets (line, sizeof (line), f)) + { + /* make parsing easier */ + for (replace = line; *replace != '\0'; replace++) + { + if (*replace == '/') + *replace = ' '; + } + /* Zero-out stack allocated values */ + memset (ifname, 0, 64); + memset (afstr, 0, 6); + memset (addrstr, 0, 128); + if (4 != SSCANF (line, + "%*u: %63s %5s %127s %6u", + ifname, + afstr, + addrstr, + &prefixlen)) + continue; + /* IPv4 */ + if ( (0 == strcasecmp ("inet", + afstr)) && + (1 == inet_pton (AF_INET, + addrstr, + &v4)) ) + { + memset (&a4, 0, sizeof (a4)); + a4.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + a4.sin_len = (u_char) sizeof (struct sockaddr_in); +#endif + a4.sin_addr = v4; + + memset (&v4.s_addr, 0, sizeof (v4.s_addr)); + for (i = 0; i < prefixlen; i++) + v4.s_addr |= 1 << (i & 7); + memset (&netmask, 0, sizeof (netmask)); + netmask.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + netmask.sin_len = (u_char) sizeof (struct sockaddr_in); +#endif + netmask.sin_addr = v4; + + if (GNUNET_OK != + proc (proc_cls, + ifname, + (0 == strcmp (ifname, + GNUNET_DEFAULT_INTERFACE)), + (const struct sockaddr *) &a4, + NULL, + (const struct sockaddr *) &netmask, + sizeof (a4))) + break; + } + /* IPv6 */ + if ( (0 == strcasecmp ("inet6", + afstr)) && + (1 == inet_pton (AF_INET6, + addrstr, + &v6)) ) + { + memset (&a6, 0, sizeof (a6)); + a6.sin6_family = AF_INET6; +#if HAVE_SOCKADDR_IN_SIN_LEN + a6.sin6_len = (u_char) sizeof (struct sockaddr_in6); +#endif + a6.sin6_addr = v6; + + memset (v6.s6_addr, 0, sizeof (v6.s6_addr)); + for (i = 0; i < prefixlen; i++) + v6.s6_addr[i >> 3] |= 1 << (i & 7); + memset (&netmask6, 0, sizeof (netmask6)); + netmask6.sin6_family = AF_INET6; +#if HAVE_SOCKADDR_IN_SIN_LEN + netmask6.sin6_len = (u_char) sizeof (struct sockaddr_in6); +#endif + netmask6.sin6_addr = v6; + + if (GNUNET_OK != + proc (proc_cls, + ifname, + (0 == strcmp (ifname, + GNUNET_DEFAULT_INTERFACE)), + (const struct sockaddr *) &a6, + NULL, + (const struct sockaddr *) &netmask6, + sizeof (a6))) + break; + } + } + pclose (f); + return GNUNET_OK; +} +#endif + + +/** + * @brief Enumerate all network interfaces + * + * @param proc the callback function + * @param proc_cls closure for @a proc + */ +void +GNUNET_OS_network_interfaces_list (GNUNET_OS_NetworkInterfaceProcessor proc, + void *proc_cls) +{ +#ifdef MINGW + int r; + int i; + struct EnumNICs3_results *results = NULL; + int results_count; + + r = EnumNICs3 (&results, &results_count); + if (r != GNUNET_OK) + return; + + for (i = 0; i < results_count; i++) + { + if (GNUNET_OK != + proc (proc_cls, results[i].pretty_name, results[i].is_default, + (const struct sockaddr *) &results[i].address, + results[i]. + flags & ENUMNICS3_BCAST_OK ? + (const struct sockaddr *) &results[i].broadcast : NULL, + results[i].flags & ENUMNICS3_MASK_OK ? + (const struct sockaddr *) &results[i].mask : NULL, + results[i].addr_size)) + break; + } + EnumNICs3_free (results); + return; + +#elif HAVE_GETIFADDRS && HAVE_FREEIFADDRS + + struct ifaddrs *ifa_first; + struct ifaddrs *ifa_ptr; + socklen_t alen; + + if (getifaddrs (&ifa_first) == 0) + { + for (ifa_ptr = ifa_first; ifa_ptr != NULL; ifa_ptr = ifa_ptr->ifa_next) + { + if (ifa_ptr->ifa_name != NULL && ifa_ptr->ifa_addr != NULL && + (ifa_ptr->ifa_flags & IFF_UP) != 0) + { + if ((ifa_ptr->ifa_addr->sa_family != AF_INET) && + (ifa_ptr->ifa_addr->sa_family != AF_INET6)) + continue; + if (ifa_ptr->ifa_addr->sa_family == AF_INET) + alen = sizeof (struct sockaddr_in); + else + alen = sizeof (struct sockaddr_in6); + if (GNUNET_OK != + proc (proc_cls, ifa_ptr->ifa_name, + 0 == strcmp (ifa_ptr->ifa_name, GNUNET_DEFAULT_INTERFACE), + ifa_ptr->ifa_addr, ifa_ptr->ifa_broadaddr, + ifa_ptr->ifa_netmask, alen)) + break; + } + } + freeifaddrs (ifa_first); + } +#else + if (GNUNET_OK == + try_ip (proc, + proc_cls)) + return; + if (GNUNET_OK == + try_ifconfig (proc, + proc_cls)) + return; + LOG (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, + "Failed to enumerate network interfaces\n"); #endif }