/* Copyright(C) 2007-2016 VoIP objects (voipobjects.com) * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ICENetworkHelper.h" #include "ICEPlatform.h" #include "ICELog.h" #include #include #include #include #include #ifdef TARGET_WIN # include # if defined(WINDOWS_RT) # include "ICEWinRtSupport.h" # endif #else #if defined(TARGET_IOS) # include "ICEIosSupport.h" #endif # include # if defined(TARGET_ANDROID) || defined(TARGET_LINUX) # include # endif #endif #include "ICEError.h" using namespace ice; #define LOG_SUBSYSTEM "ICE" #if defined(TARGET_WIN) && !defined(WINDOWS_RT) class IPHlpApi { public: HMODULE mHandle; DWORD (WINAPI *pGetBestInterfaceEx) (struct sockaddr* pDestAddr, PDWORD pdwBestIfIndex); DWORD (WINAPI *pGetBestInterface) (IPAddr dwDestAddr, PDWORD pdwBestIfIndex); ULONG (WINAPI *pGetAdaptersAddresses) (ULONG Family, ULONG Flags, PVOID Reserved, PIP_ADAPTER_ADDRESSES AdapterAddresses, PULONG SizePointer); void ResolveProc(const char* name, FARPROC& proc) { proc = GetProcAddress(mHandle, name); } public: IPHlpApi() { pGetBestInterfaceEx = NULL; pGetBestInterface = NULL; pGetAdaptersAddresses = NULL; mHandle = ::LoadLibraryW(L"iphlpapi.dll"); if (mHandle) { ResolveProc("GetBestInterfaceEx", (FARPROC&)pGetBestInterfaceEx); ResolveProc("GetBestInterface", (FARPROC&)pGetBestInterface); ResolveProc("GetAdaptersAddresses", (FARPROC&)pGetAdaptersAddresses); } } ~IPHlpApi() { if (mHandle) FreeLibrary(mHandle); } }; IPHlpApi IPHelper; #endif NetworkHelper::NetworkHelper() { reload(NetworkType_None); } NetworkHelper::~NetworkHelper() { } void NetworkHelper::reload(int networkType) { Lock l(mInstanceGuard); // Get list of interfaces #if defined(TARGET_WIN) && !defined(WINDOWS_RT) mInterfaceList.clear(); mIP2IndexList.clear(); DWORD dwRet, dwSize; DWORD flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER; IP_ADAPTER_ADDRESSES* ipAdapters = NULL; dwRet = IPHelper.pGetAdaptersAddresses(AF_INET, flags, NULL, NULL, &dwSize); if (dwRet == ERROR_BUFFER_OVERFLOW) { ipAdapters = (IP_ADAPTER_ADDRESSES*)malloc(dwSize); if (!ipAdapters) return; dwRet = IPHelper.pGetAdaptersAddresses(AF_INET, flags, NULL, ipAdapters, &dwSize); if (dwRet != ERROR_SUCCESS) { free(ipAdapters); throw Exception(CANNOT_FIND_INTERFACES); } processAdaptersList(ipAdapters); free(ipAdapters); } #ifdef ICE_IPV6SUPPORT dwRet = IPHelper.pGetAdaptersAddresses(AF_INET6, flags, NULL, NULL, &dwSize); if (dwRet == ERROR_BUFFER_OVERFLOW) { ipAdapters = (IP_ADAPTER_ADDRESSES*)malloc(dwSize); if (!ipAdapters) return; dwRet = IPHelper.pGetAdaptersAddresses(AF_INET6, flags, NULL, ipAdapters, &dwSize); if (dwRet != ERROR_SUCCESS) { free(ipAdapters); throw NetworkAddress(CANNOT_FIND_INTERFACES); } processAdaptersList(ipAdapters); free(ipAdapters); } #endif for (unsigned i=0; iifa_addr->sa_family) { case AF_INET: // just for debug // printf("%s", inet_ntoa(reinterpret_cast(current->ifa_addr)->sin_addr)); addr.setIp(reinterpret_cast(current->ifa_addr)->sin_addr); #ifndef ICE_LOOPBACK_SUPPORT handleIt = !addr.isLoopback(); #endif #ifdef ICE_SKIP_LINKLOCAL handleIt &= !addr.isLinkLocal(); #endif if (handleIt) mIPList.push_back(addr); break; #ifdef ICE_IPV6SUPPORT case AF_INET6: addr.setIp(reinterpret_cast(current->ifa_addr)->sin6_addr); #ifndef ICE_LOOPBACK_SUPPORT if (!addr.isLoopback()) #endif mIPList.push_back(addr); break; #endif } current = current->ifa_next; } freeifaddrs(il); } #endif #endif } #if defined(TARGET_WIN) && !defined(WINDOWS_RT) void NetworkHelper::processAdaptersList(IP_ADAPTER_ADDRESSES* addresses) { IP_ADAPTER_ADDRESSES *AI; int i; for (i = 0, AI = addresses; AI != NULL; AI = AI->Next, i++) { for (PIP_ADAPTER_UNICAST_ADDRESS unicast = AI->FirstUnicastAddress; unicast; unicast = unicast->Next) { #ifdef ICE_IPV6SUPPORT if (unicast->Address.lpSockaddr->sa_family != AF_INET && unicast->Address.lpSockaddr->sa_family != AF_INET6) continue; #else if (unicast->Address.lpSockaddr->sa_family != AF_INET) continue; #endif IP2Index rec; rec.mIP = NetworkAddress(*unicast->Address.lpSockaddr, unicast->Address.iSockaddrLength); rec.mIndex = AI->IfIndex; mIP2IndexList.push_back(rec); } } } #endif Mutex& NetworkHelper::guard() { return mInstanceGuard; } std::vector& NetworkHelper::interfaceList() { #if defined(TARGET_WIN) && !defined(WINDOWS_RT) return mInterfaceList; #else return mIPList; #endif } NetworkAddress NetworkHelper::sourceInterface(const NetworkAddress& remoteIP) { //Lock l(mInstanceGuard); if (remoteIP.isLoopback()) return remoteIP.family() == AF_INET ? NetworkAddress::LoopbackAddress4 : NetworkAddress::LoopbackAddress6; #if defined(TARGET_WIN) && !defined(WINDOWS_RT) if (IPHelper.pGetBestInterfaceEx) { DWORD index = 0; DWORD rescode = IPHelper.pGetBestInterfaceEx(remoteIP.genericsockaddr(), &index); if (rescode == NO_ERROR) return ipInterfaceByIndex(index); } else if (IPHelper.pGetBestInterface) { DWORD index = 0; DWORD rescode = IPHelper.pGetBestInterface(remoteIP.sockaddr4()->sin_addr.S_un.S_addr, &index); if (rescode == NO_ERROR) return ipInterfaceByIndex(index); } #ifdef ICE_LOOPBACK_SUPPORT return NetworkAddress::LoopbackAddress4; #else return remoteIP; #endif #elif defined(WINDOWS_RT) std::vector& il = interfaceList(); if (il.size()) return il.front(); else return NetworkAddress(); #else if (remoteIP.isLoopback()) return remoteIP; /*#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) // There is only one interface - return it std::vector& il = interfaceList(); if (il.size()) { if (!il.front().isZero()) return il.front(); } #endif*/ // Here magic goes. // 1) Check if remoteIP is IP4 or IP6 // 2) Check if it is LAN or loopback or internet address // 3) For LAN address - try to find interface from the same network // For Loopback address - return loopback address // For internet address - find default interface //printf("remote ip %s\n", remoteIP.GetIP().c_str()); if (remoteIP.isLAN()) { for (unsigned i=0; i