//+---------------------------------------------------------------------------- // // 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; dwCntdwDnsTunnelAddrCount; 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; iGetTunnelAddress(), dwCount); for (i=0; ipucDnsTunnelIpAddr_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; iGetTunnelAddress(), dwCount); for (i=0; ipucDnsTunnelIpAddr_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; }