9#pragma comment(lib, "ntdll.lib")
18#define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT
24 if (lpwszStrIn != NULL)
26 int nInputStrLen = (int)wcslen(lpwszStrIn);
29 int nOutputStrLen = WideCharToMultiByte (CP_ACP, 0, lpwszStrIn, nInputStrLen, NULL, 0, 0, 0) + 2;
30 pszOut =
new char [nOutputStrLen];
34 memset (pszOut, 0x00, nOutputStrLen);
35 WideCharToMultiByte(CP_ACP, 0, lpwszStrIn, nInputStrLen, pszOut, nOutputStrLen, 0, 0);
49WinCompat::Exception::Exception(
const Data& msg,
const Data& file,
const int line) :
54extern "C" NTSTATUS NTAPI
RtlGetVersion(PRTL_OSVERSIONINFOW lpVersionInformation);
56WinCompat::getVersion()
59 return WinCompat::WindowsUnknown;
64 OSVERSIONINFOEXW osvi = {
sizeof(osvi) };
67 return WinCompat::WindowsUnknown;
71 if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT)
73 return WinCompat::WindowsUnknown;
76 const DWORD major = osvi.dwMajorVersion;
77 const DWORD minor = osvi.dwMinorVersion;
78 const WORD type = osvi.wProductType;
80 if (major == 10 && minor == 0)
82 if (osvi.dwBuildNumber >= 22000)
84 return (type == VER_NT_WORKSTATION) ? WinCompat::Windows11
85 : WinCompat::WindowsServer2022;
87 return (type == VER_NT_WORKSTATION) ? WinCompat::Windows10
88 : WinCompat::WindowsServer2016;
90 else if (major == 6 && minor == 3)
92 return (type == VER_NT_WORKSTATION) ? WinCompat::Windows81
93 : WinCompat::WindowsServer2012R2;
95 else if (major == 6 && minor == 2)
97 return (type == VER_NT_WORKSTATION) ? WinCompat::Windows8
98 : WinCompat::WindowsServer2012;
100 else if (major == 6 && minor == 1)
102 return (type == VER_NT_WORKSTATION) ? WinCompat::Windows7
103 : WinCompat::WindowsServer2008R2;
105 else if (major == 6 && minor == 0)
107 return (type == VER_NT_WORKSTATION) ? WinCompat::WindowsVista
108 : WinCompat::WindowsServer2008;
110 else if (major == 5 && minor == 2) {
return WinCompat::Windows2003Server; }
111 else if (major == 5 && minor == 1) {
return WinCompat::WindowsXP; }
112 else if (major == 5 && minor == 0) {
return WinCompat::Windows2000; }
113 else if (major <= 4) {
return WinCompat::WindowsNT; }
115 return WinCompat::WindowsUnknown;
119WinCompat* WinCompat::mInstance = 0;
131 mInstance =
new WinCompat();
138WinCompat::WinCompat() :
139 getBestInterfaceEx(0),
140 getAdaptersAddresses(0),
142 loadLibraryWithIPv4Failed(false),
143 loadLibraryWithIPv6Failed(false),
151#if !defined (NO_IPHLPAPI)
153 HINSTANCE hLib = LoadLibrary(TEXT(
"iphlpapi.dll"));
156 loadLibraryWithIPv6Failed =
true;
157 loadLibraryWithIPv4Failed =
true;
161 getBestInterfaceEx = (GetBestInterfaceExProc) GetProcAddress(hLib, TEXT(
"GetBestInterfaceEx"));
162 getAdaptersAddresses = (GetAdaptersAddressesProc) GetProcAddress(hLib, TEXT(
"GetAdaptersAddresses"));
163 getAdaptersInfo = (GetAdaptersInfoProc) GetProcAddress(hLib, TEXT(
"GetAdaptersInfo"));
164 getBestRoute = (GetBestRouteProc) GetProcAddress(hLib, TEXT(
"GetBestRoute"));
165 getIpAddrTable = (GetIpAddrTableProc) GetProcAddress(hLib, TEXT(
"GetIpAddrTable"));
166 if (getAdaptersAddresses == NULL || getBestInterfaceEx == NULL)
168 loadLibraryWithIPv6Failed =
true;
170 if (getAdaptersInfo == NULL || getBestRoute == NULL || getIpAddrTable == NULL)
172 loadLibraryWithIPv4Failed =
true;
175 loadLibraryWithIPv6Failed =
true;
176 loadLibraryWithIPv4Failed =
true;
178 DebugLog(<<
"WinCompat constructor complete!");
181void WinCompat::destroyInstance()
187bool WinCompat::windowsEventLog(WORD type, WORD numStrings, LPCTSTR* strings)
199 ::RegCreateKeyEx(HKEY_LOCAL_MACHINE, _T(
"System\\CurrentControlSet\\Services\\EventLog\\Application\\reSIProcate"),
200 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ, NULL, &key, NULL);
201 if (ERROR_SUCCESS == errorCode)
204 HANDLE eventLogHandle = ::RegisterEventSource(NULL, _T(
"reSIProcate"));
205 if (eventLogHandle != NULL)
207 BOOL retVal = ::ReportEvent(eventLogHandle, type, 0, 0, NULL, numStrings, 0, strings, NULL);
208 ::DeregisterEventSource(eventLogHandle);
209 return (retVal != FALSE);
215WinCompat::~WinCompat()
224#if !defined(NO_IPHLPAPI)
228WinCompat::determineSourceInterfaceWithIPv6(
const GenericIPAddress& destination)
230 if (instance()->loadLibraryWithIPv6Failed)
232 throw Exception(
"Library iphlpapi.dll with IPv6 support not available", __FILE__,__LINE__);
236 IP_ADAPTER_ADDRESSES *pAdapterAddresses;
238 DWORD
flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
239 unsigned short family = destination.
isVersion6() ? AF_INET6 : AF_INET;
240 dwRet = (instance()->getAdaptersAddresses)(family,
flags, NULL, NULL, &dwSize);
241 if (dwRet != ERROR_BUFFER_OVERFLOW)
242 throw Exception(
"Unexpected return code", __FILE__, __LINE__);
246 pAdapterAddresses = (IP_ADAPTER_ADDRESSES *) LocalAlloc(LMEM_ZEROINIT,dwSize);
247 if (pAdapterAddresses == NULL)
249 throw Exception(
"Can't find source address for destination", __FILE__,__LINE__);
253 dwRet = (instance()->getAdaptersAddresses)(family,
flags, NULL, pAdapterAddresses, &dwSize);
254 if (dwRet != ERROR_SUCCESS)
256 LocalFree(pAdapterAddresses);
257 throw Exception(
"Can't find source address for destination", __FILE__,__LINE__);
263 IP_ADAPTER_ADDRESSES *AI;
265 for (i = 0, AI = pAdapterAddresses; AI != NULL; AI = AI->Next, i++)
267 for (PIP_ADAPTER_UNICAST_ADDRESS unicast = AI->FirstUnicastAddress;
268 unicast; unicast = unicast->Next)
270 if (unicast->Address.lpSockaddr->sa_family != family)
273 if (family == AF_INET &&
274 reinterpret_cast<const struct sockaddr_in*
>(unicast->Address.lpSockaddr)->sin_addr.S_un.S_addr ==
275 destination.
v4Address.sin_addr.S_un.S_addr)
280 for (PIP_ADAPTER_UNICAST_ADDRESS unicastRet = AI->FirstUnicastAddress;
281 unicastRet; unicastRet = unicastRet->Next)
283#if defined(AVOID_TRANSIENT_SOURCE_ADDRESSES)
284 if (unicastRet->Flags & IP_ADAPTER_ADDRESS_TRANSIENT)
289 LocalFree(pAdapterAddresses);
294 else if (family == AF_INET6 &&
295 memcmp(&(
reinterpret_cast<const struct sockaddr_in6*
>(unicast->Address.lpSockaddr)->sin6_addr),
296 &(
reinterpret_cast<const struct sockaddr_in6*
>(&destination.
address)->sin6_addr),
297 sizeof(IN6_ADDR)) == 0)
299 for (PIP_ADAPTER_UNICAST_ADDRESS unicastRet = AI->FirstUnicastAddress;
300 unicastRet; unicastRet = unicastRet->Next)
302#if defined(AVOID_TRANSIENT_SOURCE_ADDRESSES)
303 if (unicastRet->Flags & IP_ADAPTER_ADDRESS_TRANSIENT)
309 const struct sockaddr_in6* psa =
reinterpret_cast<const struct sockaddr_in6*
>(unicastRet->Address.lpSockaddr);
315 LocalFree(pAdapterAddresses);
325 const sockaddr* saddr = &destination.
address;
326 if ((instance()->getBestInterfaceEx)((sockaddr *)saddr, &dwBestIfIndex) != NO_ERROR)
328 LocalFree(pAdapterAddresses);
329 throw Exception(
"Can't find source address for destination", __FILE__,__LINE__);
332 for (i = 0, AI = pAdapterAddresses; AI != NULL; AI = AI->Next, i++)
334 for (PIP_ADAPTER_UNICAST_ADDRESS unicast = AI->FirstUnicastAddress;
335 unicast; unicast = unicast->Next)
337 if (unicast->Address.lpSockaddr->sa_family != saddr->sa_family)
340#if defined(AVOID_TRANSIENT_SOURCE_ADDRESSES)
341 if (unicast->Flags & IP_ADAPTER_ADDRESS_TRANSIENT)
345 if (saddr->sa_family == AF_INET && AI->IfIndex == dwBestIfIndex)
348 LocalFree(pAdapterAddresses);
352 else if (saddr->sa_family == AF_INET6 && AI->Ipv6IfIndex == dwBestIfIndex)
356 const struct sockaddr_in6* psa =
reinterpret_cast<const struct sockaddr_in6*
>(unicast->Address.lpSockaddr);
358 LocalFree(pAdapterAddresses);
364 LocalFree(pAdapterAddresses);
365 throw Exception(
"Can't find source address for destination", __FILE__,__LINE__);
372WinCompat::determineSourceInterfaceWithoutIPv6(
const GenericIPAddress& destination)
374 if (instance()->loadLibraryWithIPv4Failed)
376 throw Exception(
"Library iphlpapi.dll not available", __FILE__,__LINE__);
379 struct sockaddr_in sourceIP;
380 memset(&sourceIP, 0,
sizeof(sockaddr_in));
381 sourceIP.sin_family = AF_INET;
385 PMIB_IPADDRTABLE pIpAddrTable = NULL;
389 DWORD ret = instance()->getIpAddrTable(NULL, &addrSize, FALSE);
390 if(ERROR_INSUFFICIENT_BUFFER == ret)
392 pIpAddrTable = (PMIB_IPADDRTABLE)
new char [addrSize];
393 if(pIpAddrTable == 0)
395 throw Exception(
"Can't find source address for destination - unable to new memory", __FILE__,__LINE__);
400 throw Exception(
"Can't find source address for destination (GetIpAddrTable to get buffer space failed), ret=" +
Data((
uint32_t)ret), __FILE__,__LINE__);
403 ret = instance()->getIpAddrTable(pIpAddrTable, &addrSize, FALSE);
406 delete [] (
char *) pIpAddrTable;
407 throw Exception(
"Can't find source address for destination (GetIpAddrTable failed), addrSize=" +
Data((
uint32_t)addrSize) +
", ret=" +
Data((
uint32_t)ret), __FILE__,__LINE__);
412 for(i = 0; i <pIpAddrTable->dwNumEntries; i++)
414 if(pIpAddrTable->table[i].dwAddr ==
415 destination.
v4Address.sin_addr.S_un.S_addr)
422 DWORD dwNicIndex = pIpAddrTable->table[i].dwIndex;
423 for(DWORD j = 0; j <pIpAddrTable->dwNumEntries; j++)
425#if defined(AVOID_TRANSIENT_SOURCE_ADDRESSES)
426 if (pIpAddrTable->table[j].wType & MIB_IPADDR_TRANSIENT)
430 if(pIpAddrTable->table[j].dwIndex == dwNicIndex)
432 DebugLog(<<
"Routing to a local address - returning default address for NIC");
433 sourceIP.sin_addr.s_addr = pIpAddrTable->table[j].dwAddr;
434 delete [] (
char *) pIpAddrTable;
442 MIB_IPFORWARDROW bestRoute;
443 memset(&bestRoute, 0,
sizeof(bestRoute));
444 const sockaddr_in& sin = (
const sockaddr_in&)destination.
address;
445 ret = instance()->getBestRoute(sin.sin_addr.s_addr, 0, &bestRoute);
448 delete [] (
char *) pIpAddrTable;
449 throw Exception(
"Can't find source address for destination, ret=" +
Data((
uint32_t)ret), __FILE__,__LINE__);
453 enum ENICEntryPreference {ENICUnknown = 0, ENextHopNotWithinNICSubnet, ENICSubnetIsAll1s, ENICServicesNextHop};
454 ENICEntryPreference eCurrSelection = ENICUnknown;
457 for (i=0; i<pIpAddrTable->dwNumEntries; i++)
459 MIB_IPADDRROW &entry = pIpAddrTable->table[i];
461 ULONG addr = pIpAddrTable->table[i].dwAddr;
462 ULONG gw = bestRoute.dwForwardNextHop;
464#if defined(AVOID_TRANSIENT_SOURCE_ADDRESSES)
465 if (entry.wType & MIB_IPADDR_TRANSIENT)
469 if(entry.dwIndex == bestRoute.dwForwardIfIndex)
471 if( (entry.dwAddr & entry.dwMask) == (bestRoute.dwForwardNextHop & entry.dwMask) )
473 sourceIP.sin_addr.s_addr = entry.dwAddr;
474 eCurrSelection = ENICServicesNextHop;
477 else if (entry.dwMask == 0xffffffff && eCurrSelection < ENICSubnetIsAll1s)
479 sourceIP.sin_addr.s_addr = entry.dwAddr;
480 eCurrSelection = ENICSubnetIsAll1s;
483 else if (eCurrSelection < ENextHopNotWithinNICSubnet)
485 sourceIP.sin_addr.s_addr = entry.dwAddr;
486 eCurrSelection = ENextHopNotWithinNICSubnet;
491 if (eCurrSelection != ENICServicesNextHop)
494 in_addr subnet, netMask, nextHop;
495 subnet.s_addr = bestRoute.dwForwardDest;
496 netMask.s_addr = bestRoute.dwForwardMask;
497 nextHop.s_addr = bestRoute.dwForwardNextHop;
502 <<
" if-index=" <<bestRoute.dwForwardIfIndex );
504 for (i=0; i<pIpAddrTable->dwNumEntries; i++)
506 MIB_IPADDRROW & entry = pIpAddrTable->table[i];
507 in_addr nicIP, nicMask;
508 nicIP.s_addr = entry.dwAddr;
509 nicMask.s_addr = entry.dwMask;
510 DebugLog(<<
"IP Table entry " <<i+1 <<
'/' <<pIpAddrTable->dwNumEntries <<
" if-index=" <<entry.dwIndex
512 << (entry.wType & MIB_IPADDR_TRANSIENT ?
" (Transient)" :
"")
513 <<
" NIC Mask=" <<
DnsUtil::inet_ntop(nicMask) );
517 delete [] (
char *) pIpAddrTable;
518 if(sourceIP.sin_addr.s_addr == 0)
520 throw Exception(
"Can't find source address for destination", __FILE__,__LINE__);
534#if !defined(NO_IPHLPAPI)
538 return determineSourceInterfaceWithIPv6(destination);
542 return determineSourceInterfaceWithoutIPv6(destination);
552std::list<std::pair<Data,Data> >
553WinCompat::getInterfaces(
const Data& matching)
555 if (instance()->loadLibraryWithIPv6Failed)
557 if (instance()->loadLibraryWithIPv4Failed)
559 throw Exception(
"Library iphlpapi.dll not available", __FILE__,__LINE__);
564 PIP_ADAPTER_INFO pAdaptersInfo=NULL;
565 std::list<std::pair<Data,Data> > results;
566 DWORD dwRet, dwSize=0;
567 dwRet = (instance()->getAdaptersInfo)(pAdaptersInfo, &dwSize);
568 if (dwRet == ERROR_BUFFER_OVERFLOW)
571 pAdaptersInfo = (PIP_ADAPTER_INFO) LocalAlloc(LMEM_ZEROINIT,dwSize);
572 if (pAdaptersInfo == NULL)
574 throw Exception(
"Can't query for adapters info - LocalAlloc error", __FILE__,__LINE__);
576 dwRet = (instance()->getAdaptersInfo)(pAdaptersInfo, &dwSize);
577 if (dwRet != ERROR_SUCCESS)
579 LocalFree(pAdaptersInfo);
580 throw Exception(
"Can't query for adapters info - GetAdaptersInfo", __FILE__,__LINE__);
586 for (i = 0, AI = pAdaptersInfo; AI != NULL; AI = AI->Next, i++)
589 Data name(AI->Description);
592 for (
const IP_ADDR_STRING *addr=&AI->IpAddressList; addr; addr = addr->Next)
594 results.push_back(std::make_pair(name,
Data(addr->IpAddress.String)));
598 LocalFree(pAdaptersInfo);
607 IP_ADAPTER_ADDRESSES *pAdapterAddresses;
608 std::list<std::pair<Data,Data> > results;
609 DWORD dwRet, dwSize=0;
610 DWORD
flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
611 dwRet = (instance()->getAdaptersAddresses)(AF_UNSPEC,
flags, NULL, NULL, &dwSize);
612 if (dwRet == ERROR_BUFFER_OVERFLOW)
615 pAdapterAddresses = (IP_ADAPTER_ADDRESSES *) LocalAlloc(LMEM_ZEROINIT,dwSize);
616 if (pAdapterAddresses == NULL)
618 throw Exception(
"Can't query for adapter addresses - LocalAlloc error", __FILE__,__LINE__);
622 dwRet = (instance()->getAdaptersAddresses)(AF_UNSPEC,
flags, NULL, pAdapterAddresses, &dwSize);
623 if (dwRet != ERROR_SUCCESS)
625 LocalFree(pAdapterAddresses);
626 throw Exception(
"Can't query for adapter addresses - GetAdapterAddresses", __FILE__,__LINE__);
630 IP_ADAPTER_ADDRESSES *AI;
632 for (i = 0, AI = pAdapterAddresses; AI != NULL; AI = AI->Next, i++)
634 if (AI->FirstUnicastAddress != NULL)
637 Data name(pszSimpleCharStringFromLPWSTR);
638 delete [] pszSimpleCharStringFromLPWSTR;
642 for (PIP_ADAPTER_UNICAST_ADDRESS unicast = AI->FirstUnicastAddress;
643 unicast; unicast = unicast->Next)
647 if (unicast->Address.lpSockaddr->sa_family != AF_INET)
continue;
649 results.push_back(std::make_pair(name,
DnsUtil::inet_ntop(*unicast->Address.lpSockaddr)));
654 LocalFree(pAdapterAddresses);
#define resip_assert(x)
This file needs to work for both C and C++ code.
static char * ConvertLPWSTRToLPSTR(LPWSTR lpwszStrIn)
static Mutex WinComaptInstanceMutex
class WinCompatInstanceCleaner winCompatInstanceCleaner
NTSTATUS NTAPI RtlGetVersion(PRTL_OSVERSIONINFOW lpVersionInformation)
static const struct nv flags[]
~WinCompatInstanceCleaner()
The abstract base-class for all exceptions thrown by resip code.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
static const Data Empty
Constant that represents a zero-length data.
Provides a collection of utility functions for manipulating DNS names and IP addresses and discoverin...
static Data inet_ntop(const struct in_addr &addr)
Converts from the network format to presentation format.
dcm! – add UnusedChecking(_enum) below;
std::mutex Mutex
A semaphore that can be locked by only one thread at a time.
std::unique_lock< Mutex > Lock
A convenience class to lock a Lockable (such as a Mutex) on object creation, and unlock on destructio...
Represents an IP-address and port (V4 or V6).