446 lines
11 KiB
C++
446 lines
11 KiB
C++
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// File: wsock.cpp
|
||
|
//
|
||
|
// Module: CMDIAL32.DLL
|
||
|
//
|
||
|
// Synopsis: This module contains the winsock related CM code.
|
||
|
//
|
||
|
// Copyright (c) 1996-1999 Microsoft Corporation
|
||
|
//
|
||
|
// Author: henryt created 03/??/98
|
||
|
// quintinb created Header 08/16/99
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
|
||
|
#include "cmmaster.h"
|
||
|
#include "winsock.h"
|
||
|
#include "tunl_str.h"
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////
|
||
|
// define's
|
||
|
///////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////
|
||
|
// typedef's
|
||
|
///////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
typedef int (PASCAL FAR *PFN_WSAStartup)(WORD, LPWSADATA);
|
||
|
typedef int (PASCAL FAR *PFN_WSACleanup)(void);
|
||
|
typedef struct hostent FAR * (PASCAL FAR *PFN_gethostbyname)(const char FAR * name);
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////
|
||
|
// func prototypes
|
||
|
///////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
BOOL InvokeGetHostByName(
|
||
|
ArgsStruct *pArgs
|
||
|
);
|
||
|
|
||
|
BOOL BuildDnsTunnelList(
|
||
|
ArgsStruct *pArgs,
|
||
|
struct hostent *pHe
|
||
|
);
|
||
|
|
||
|
BOOL BuildRandomTunnelIndex(
|
||
|
ArgsStruct *pArgs,
|
||
|
DWORD dwCount
|
||
|
);
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////
|
||
|
// Implementation
|
||
|
///////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: TryAnotherTunnelDnsAddress
|
||
|
//
|
||
|
// Synopsis: see if there's another dns address associated with the current
|
||
|
// tunnel name. if so, set that address in primary or extended
|
||
|
// tunnel ip properly.
|
||
|
//
|
||
|
// Arguments: pArgs ptr to ArgsStruct
|
||
|
//
|
||
|
// Returns: TRUE if SUCCESS
|
||
|
// FALSE otherwise.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL TryAnotherTunnelDnsAddress(
|
||
|
ArgsStruct *pArgs
|
||
|
)
|
||
|
{
|
||
|
MYDBGASSERT(pArgs);
|
||
|
|
||
|
//
|
||
|
// RAS does all this for us on NT5, so bail out now.
|
||
|
//
|
||
|
|
||
|
if (NULL == pArgs || OS_NT5)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// if the list of tunnel ip addrs is empty, let's resolve the dns name
|
||
|
// and see if there are other addrs behind the dns name.
|
||
|
//
|
||
|
if (!pArgs->pucDnsTunnelIpAddr_list)
|
||
|
{
|
||
|
if (!InvokeGetHostByName(pArgs))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
MYDBGASSERT(pArgs->pucDnsTunnelIpAddr_list);
|
||
|
|
||
|
if (pArgs->uiCurrentDnsTunnelAddr == pArgs->dwDnsTunnelAddrCount - 1)
|
||
|
{
|
||
|
//
|
||
|
// we've run out of addrs in the list.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// we need to destroy the list
|
||
|
//
|
||
|
CmFree(pArgs->pucDnsTunnelIpAddr_list);
|
||
|
pArgs->pucDnsTunnelIpAddr_list = NULL;
|
||
|
|
||
|
CmFree(pArgs->rgwRandomDnsIndex);
|
||
|
pArgs->rgwRandomDnsIndex = NULL;
|
||
|
|
||
|
pArgs->uiCurrentDnsTunnelAddr = 0;
|
||
|
pArgs->dwDnsTunnelAddrCount = 0;
|
||
|
|
||
|
//
|
||
|
// If we're currently using the primary tunnel server, we need to
|
||
|
// restore it since we overwrote it.
|
||
|
//
|
||
|
|
||
|
LPTSTR pszTunnelIp = pArgs->piniBothNonFav->GPPS(c_pszCmSection, c_pszCmEntryTunnelAddress);
|
||
|
|
||
|
if (lstrlenU(pszTunnelIp) > RAS_MaxPhoneNumber)
|
||
|
{
|
||
|
pszTunnelIp[0] = TEXT('\0');
|
||
|
}
|
||
|
|
||
|
pArgs->SetPrimaryTunnel(pszTunnelIp);
|
||
|
CmFree(pszTunnelIp);
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// try the next ip addr in the list
|
||
|
//
|
||
|
TCHAR szAddr[16]; // xxx.xxx.xxx.xxx
|
||
|
unsigned char *puc;
|
||
|
|
||
|
pArgs->uiCurrentDnsTunnelAddr++;
|
||
|
|
||
|
puc = pArgs->pucDnsTunnelIpAddr_list + pArgs->rgwRandomDnsIndex[pArgs->uiCurrentDnsTunnelAddr]*4;
|
||
|
|
||
|
wsprintfU(szAddr, TEXT("%hu.%hu.%hu.%hu"),
|
||
|
*puc,
|
||
|
*(puc+1),
|
||
|
*(puc+2),
|
||
|
*(puc+3));
|
||
|
|
||
|
CMTRACE1(TEXT("TryAnotherTunnelDnsAddress: found ip addr %s for the tunnel server"), szAddr);
|
||
|
|
||
|
pArgs->SetPrimaryTunnel(szAddr);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: InvokeGetHostByName
|
||
|
//
|
||
|
// Synopsis: call gethostbyname and sets up internal ipaddr list.
|
||
|
//
|
||
|
// Arguments: pArgs ptr to ArgsStruct
|
||
|
//
|
||
|
// Returns: TRUE if SUCCESS
|
||
|
// FALSE otherwise.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
BOOL InvokeGetHostByName(
|
||
|
ArgsStruct *pArgs
|
||
|
)
|
||
|
{
|
||
|
HINSTANCE hInst;
|
||
|
PFN_WSAStartup pfnWSAStartup;
|
||
|
PFN_WSACleanup pfnWSACleanup = NULL;
|
||
|
PFN_gethostbyname pfngethostbyname;
|
||
|
WSADATA wsaData;
|
||
|
struct hostent *pHe;
|
||
|
BOOL fOk = FALSE;
|
||
|
#ifdef UNICODE
|
||
|
LPSTR pszHostName;
|
||
|
DWORD dwSize;
|
||
|
#endif
|
||
|
//
|
||
|
// the list's gotta be empty
|
||
|
//
|
||
|
MYDBGASSERT(!pArgs->pucDnsTunnelIpAddr_list);
|
||
|
|
||
|
MYVERIFY(hInst = LoadLibraryExA("wsock32.dll", NULL, 0));
|
||
|
|
||
|
if (!hInst)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (!(pfnWSAStartup = (PFN_WSAStartup)GetProcAddress(hInst, "WSAStartup")))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
if (pfnWSAStartup(MAKEWORD(1, 1), &wsaData))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
pfnWSACleanup = (PFN_WSACleanup)GetProcAddress(hInst, "WSACleanup");
|
||
|
|
||
|
if (!(pfngethostbyname = (PFN_gethostbyname)GetProcAddress(hInst, "gethostbyname")))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
#ifdef UNICODE
|
||
|
|
||
|
pszHostName = WzToSzWithAlloc(pArgs->GetTunnelAddress());
|
||
|
|
||
|
if (pszHostName)
|
||
|
{
|
||
|
pHe = pfngethostbyname(pszHostName);
|
||
|
CmFree(pszHostName);
|
||
|
|
||
|
if (!pHe)
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
if (!(pHe = pfngethostbyname(pArgs->GetTunnelAddress())))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (BuildDnsTunnelList(pArgs, pHe))
|
||
|
{
|
||
|
fOk = TRUE;
|
||
|
}
|
||
|
|
||
|
exit:
|
||
|
|
||
|
if (pfnWSACleanup)
|
||
|
{
|
||
|
pfnWSACleanup();
|
||
|
}
|
||
|
|
||
|
if (hInst)
|
||
|
{
|
||
|
FreeLibrary(hInst);
|
||
|
}
|
||
|
|
||
|
return fOk;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: BuildDnsTunnelList
|
||
|
//
|
||
|
// Synopsis: Build a tunnel address list.
|
||
|
//
|
||
|
// Arguments: pArgs ptr to ArgsStruct
|
||
|
// pHe a ptr to hostent(returned by gethostbyname()).
|
||
|
//
|
||
|
// Returns: TRUE if SUCCESS
|
||
|
// FALSE otherwise.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
BOOL BuildDnsTunnelList(
|
||
|
ArgsStruct *pArgs,
|
||
|
struct hostent *pHe
|
||
|
)
|
||
|
{
|
||
|
DWORD dwCnt;
|
||
|
|
||
|
//
|
||
|
// see how many addrs we have
|
||
|
//
|
||
|
for (dwCnt=0; pHe->h_addr_list[dwCnt]; dwCnt++)
|
||
|
;
|
||
|
|
||
|
if (dwCnt < 2)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// if we have more than one addrs, save the list.
|
||
|
//
|
||
|
pArgs->dwDnsTunnelAddrCount = dwCnt;
|
||
|
|
||
|
if (!(pArgs->pucDnsTunnelIpAddr_list = (unsigned char *)CmMalloc(dwCnt*pHe->h_length)))
|
||
|
{
|
||
|
CMTRACE(TEXT("InvokeGetHostByName: failed to alloc tunnel addr list"));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
for (dwCnt=0; dwCnt<pArgs->dwDnsTunnelAddrCount; dwCnt++)
|
||
|
{
|
||
|
CopyMemory(pArgs->pucDnsTunnelIpAddr_list + dwCnt*pHe->h_length,
|
||
|
pHe->h_addr_list[dwCnt],
|
||
|
pHe->h_length);
|
||
|
}
|
||
|
|
||
|
pArgs->uiCurrentDnsTunnelAddr = 0;
|
||
|
|
||
|
//
|
||
|
// we need a random list. With this, we can get a random addr in constant
|
||
|
// time(and fast). see cmtools\getips.
|
||
|
//
|
||
|
if (!BuildRandomTunnelIndex(pArgs, dwCnt))
|
||
|
{
|
||
|
CmFree(pArgs->pucDnsTunnelIpAddr_list);
|
||
|
pArgs->pucDnsTunnelIpAddr_list = NULL;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: BuildRandomTunnelIndex
|
||
|
//
|
||
|
// Synopsis: Build a list random indices. With this, we can get a random
|
||
|
// addr in constant time(and fast). see cmtools\getips.
|
||
|
//
|
||
|
// Arguments: pArgs ptr to ArgsStruct
|
||
|
// dwCount # of of indices
|
||
|
//
|
||
|
// Returns: TRUE if SUCCESS
|
||
|
// FALSE otherwise.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL BuildRandomTunnelIndex(
|
||
|
ArgsStruct *pArgs,
|
||
|
DWORD dwCount
|
||
|
)
|
||
|
{
|
||
|
DWORD i, j;
|
||
|
PWORD rgwIndex;
|
||
|
WORD wTmp;
|
||
|
|
||
|
//
|
||
|
// we can only have at most 65536 ip addrs(the max. range of a WORD), which is plenty.
|
||
|
//
|
||
|
MYDBGASSERT((dwCount > 1) && (dwCount <= 65536));
|
||
|
|
||
|
if (!(pArgs->rgwRandomDnsIndex = (PWORD)CmMalloc(sizeof(WORD)*dwCount)))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// now start build the random indices...
|
||
|
//
|
||
|
for (i=0, rgwIndex=pArgs->rgwRandomDnsIndex; i<dwCount; i++)
|
||
|
{
|
||
|
rgwIndex[i] = (WORD)i;
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
{
|
||
|
unsigned char *puc;
|
||
|
TCHAR szAddr[16]; // xxx.xxx.xxx.xxx
|
||
|
|
||
|
CMTRACE2(TEXT("BuildRandomTunnelIndex: BEFORE randomization(server=%s, count=%u):"),
|
||
|
pArgs->GetTunnelAddress(), dwCount);
|
||
|
|
||
|
for (i=0; i<dwCount; i++)
|
||
|
{
|
||
|
puc = pArgs->pucDnsTunnelIpAddr_list + i*4;
|
||
|
wsprintfU(szAddr, TEXT("%hu.%hu.%hu.%hu"),
|
||
|
*puc,
|
||
|
*(puc+1),
|
||
|
*(puc+2),
|
||
|
*(puc+3));
|
||
|
CMTRACE2(TEXT("%u: %s"), i, szAddr);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// If we only have 2 addrs, the first address has already been used by RAS,
|
||
|
// there's no need to randomize the list. We'll just use the 2nd addr.
|
||
|
//
|
||
|
if (dwCount == 2)
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
CRandom r;
|
||
|
|
||
|
//
|
||
|
// randomize the indices. skip the first entry.
|
||
|
//
|
||
|
for (i=1; i<dwCount; i++)
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
//
|
||
|
// j has to be non-zero(to leave the 0-th entry untouhced).
|
||
|
//
|
||
|
j = r.Generate() % dwCount;
|
||
|
} while (!j);
|
||
|
|
||
|
if (i != j)
|
||
|
{
|
||
|
wTmp = rgwIndex[i];
|
||
|
rgwIndex[i] = rgwIndex[j];
|
||
|
rgwIndex[j] = wTmp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
{
|
||
|
unsigned char *puc;
|
||
|
TCHAR szAddr[16]; // xxx.xxx.xxx.xxx
|
||
|
|
||
|
CMTRACE2(TEXT("BuildRandomTunnelIndex: AFTER randomization(server=%s, count=%u):"),
|
||
|
pArgs->GetTunnelAddress(), dwCount);
|
||
|
|
||
|
for (i=0; i<dwCount; i++)
|
||
|
{
|
||
|
puc = pArgs->pucDnsTunnelIpAddr_list + rgwIndex[i]*4;
|
||
|
wsprintfU(szAddr, TEXT("%hu.%hu.%hu.%hu"),
|
||
|
*puc,
|
||
|
*(puc+1),
|
||
|
*(puc+2),
|
||
|
*(puc+3));
|
||
|
CMTRACE2(TEXT("%u: %s"), i, szAddr);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|