Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

445 lines
11 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: wsock.cpp
  4. //
  5. // Module: CMDIAL32.DLL
  6. //
  7. // Synopsis: This module contains the winsock related CM code.
  8. //
  9. // Copyright (c) 1996-1999 Microsoft Corporation
  10. //
  11. // Author: henryt created 03/??/98
  12. // quintinb created Header 08/16/99
  13. //
  14. //+----------------------------------------------------------------------------
  15. #include "cmmaster.h"
  16. #include "winsock.h"
  17. #include "tunl_str.h"
  18. ///////////////////////////////////////////////////////////////////////////////////
  19. // define's
  20. ///////////////////////////////////////////////////////////////////////////////////
  21. ///////////////////////////////////////////////////////////////////////////////////
  22. // typedef's
  23. ///////////////////////////////////////////////////////////////////////////////////
  24. typedef int (PASCAL FAR *PFN_WSAStartup)(WORD, LPWSADATA);
  25. typedef int (PASCAL FAR *PFN_WSACleanup)(void);
  26. typedef struct hostent FAR * (PASCAL FAR *PFN_gethostbyname)(const char FAR * name);
  27. ///////////////////////////////////////////////////////////////////////////////////
  28. // func prototypes
  29. ///////////////////////////////////////////////////////////////////////////////////
  30. BOOL InvokeGetHostByName(
  31. ArgsStruct *pArgs
  32. );
  33. BOOL BuildDnsTunnelList(
  34. ArgsStruct *pArgs,
  35. struct hostent *pHe
  36. );
  37. BOOL BuildRandomTunnelIndex(
  38. ArgsStruct *pArgs,
  39. DWORD dwCount
  40. );
  41. ///////////////////////////////////////////////////////////////////////////////////
  42. // Implementation
  43. ///////////////////////////////////////////////////////////////////////////////////
  44. //+---------------------------------------------------------------------------
  45. //
  46. // Function: TryAnotherTunnelDnsAddress
  47. //
  48. // Synopsis: see if there's another dns address associated with the current
  49. // tunnel name. if so, set that address in primary or extended
  50. // tunnel ip properly.
  51. //
  52. // Arguments: pArgs ptr to ArgsStruct
  53. //
  54. // Returns: TRUE if SUCCESS
  55. // FALSE otherwise.
  56. //
  57. //----------------------------------------------------------------------------
  58. BOOL TryAnotherTunnelDnsAddress(
  59. ArgsStruct *pArgs
  60. )
  61. {
  62. MYDBGASSERT(pArgs);
  63. //
  64. // RAS does all this for us on NT5, so bail out now.
  65. //
  66. if (NULL == pArgs || OS_NT5)
  67. {
  68. return FALSE;
  69. }
  70. //
  71. // if the list of tunnel ip addrs is empty, let's resolve the dns name
  72. // and see if there are other addrs behind the dns name.
  73. //
  74. if (!pArgs->pucDnsTunnelIpAddr_list)
  75. {
  76. if (!InvokeGetHostByName(pArgs))
  77. {
  78. return FALSE;
  79. }
  80. }
  81. MYDBGASSERT(pArgs->pucDnsTunnelIpAddr_list);
  82. if (pArgs->uiCurrentDnsTunnelAddr == pArgs->dwDnsTunnelAddrCount - 1)
  83. {
  84. //
  85. // we've run out of addrs in the list.
  86. //
  87. //
  88. // we need to destroy the list
  89. //
  90. CmFree(pArgs->pucDnsTunnelIpAddr_list);
  91. pArgs->pucDnsTunnelIpAddr_list = NULL;
  92. CmFree(pArgs->rgwRandomDnsIndex);
  93. pArgs->rgwRandomDnsIndex = NULL;
  94. pArgs->uiCurrentDnsTunnelAddr = 0;
  95. pArgs->dwDnsTunnelAddrCount = 0;
  96. //
  97. // If we're currently using the primary tunnel server, we need to
  98. // restore it since we overwrote it.
  99. //
  100. LPTSTR pszTunnelIp = pArgs->piniBothNonFav->GPPS(c_pszCmSection, c_pszCmEntryTunnelAddress);
  101. if (lstrlenU(pszTunnelIp) > RAS_MaxPhoneNumber)
  102. {
  103. pszTunnelIp[0] = TEXT('\0');
  104. }
  105. pArgs->SetPrimaryTunnel(pszTunnelIp);
  106. CmFree(pszTunnelIp);
  107. return FALSE;
  108. }
  109. //
  110. // try the next ip addr in the list
  111. //
  112. TCHAR szAddr[16]; // xxx.xxx.xxx.xxx
  113. unsigned char *puc;
  114. pArgs->uiCurrentDnsTunnelAddr++;
  115. puc = pArgs->pucDnsTunnelIpAddr_list + pArgs->rgwRandomDnsIndex[pArgs->uiCurrentDnsTunnelAddr]*4;
  116. wsprintfU(szAddr, TEXT("%hu.%hu.%hu.%hu"),
  117. *puc,
  118. *(puc+1),
  119. *(puc+2),
  120. *(puc+3));
  121. CMTRACE1(TEXT("TryAnotherTunnelDnsAddress: found ip addr %s for the tunnel server"), szAddr);
  122. pArgs->SetPrimaryTunnel(szAddr);
  123. return TRUE;
  124. }
  125. //+---------------------------------------------------------------------------
  126. //
  127. // Function: InvokeGetHostByName
  128. //
  129. // Synopsis: call gethostbyname and sets up internal ipaddr list.
  130. //
  131. // Arguments: pArgs ptr to ArgsStruct
  132. //
  133. // Returns: TRUE if SUCCESS
  134. // FALSE otherwise.
  135. //
  136. //----------------------------------------------------------------------------
  137. BOOL InvokeGetHostByName(
  138. ArgsStruct *pArgs
  139. )
  140. {
  141. HINSTANCE hInst;
  142. PFN_WSAStartup pfnWSAStartup;
  143. PFN_WSACleanup pfnWSACleanup = NULL;
  144. PFN_gethostbyname pfngethostbyname;
  145. WSADATA wsaData;
  146. struct hostent *pHe;
  147. BOOL fOk = FALSE;
  148. #ifdef UNICODE
  149. LPSTR pszHostName;
  150. DWORD dwSize;
  151. #endif
  152. //
  153. // the list's gotta be empty
  154. //
  155. MYDBGASSERT(!pArgs->pucDnsTunnelIpAddr_list);
  156. MYVERIFY(hInst = LoadLibraryExA("wsock32.dll", NULL, 0));
  157. if (!hInst)
  158. {
  159. return FALSE;
  160. }
  161. if (!(pfnWSAStartup = (PFN_WSAStartup)GetProcAddress(hInst, "WSAStartup")))
  162. {
  163. goto exit;
  164. }
  165. if (pfnWSAStartup(MAKEWORD(1, 1), &wsaData))
  166. {
  167. goto exit;
  168. }
  169. pfnWSACleanup = (PFN_WSACleanup)GetProcAddress(hInst, "WSACleanup");
  170. if (!(pfngethostbyname = (PFN_gethostbyname)GetProcAddress(hInst, "gethostbyname")))
  171. {
  172. goto exit;
  173. }
  174. #ifdef UNICODE
  175. pszHostName = WzToSzWithAlloc(pArgs->GetTunnelAddress());
  176. if (pszHostName)
  177. {
  178. pHe = pfngethostbyname(pszHostName);
  179. CmFree(pszHostName);
  180. if (!pHe)
  181. {
  182. goto exit;
  183. }
  184. }
  185. else
  186. {
  187. goto exit;
  188. }
  189. #else
  190. if (!(pHe = pfngethostbyname(pArgs->GetTunnelAddress())))
  191. {
  192. goto exit;
  193. }
  194. #endif
  195. if (BuildDnsTunnelList(pArgs, pHe))
  196. {
  197. fOk = TRUE;
  198. }
  199. exit:
  200. if (pfnWSACleanup)
  201. {
  202. pfnWSACleanup();
  203. }
  204. if (hInst)
  205. {
  206. FreeLibrary(hInst);
  207. }
  208. return fOk;
  209. }
  210. //+---------------------------------------------------------------------------
  211. //
  212. // Function: BuildDnsTunnelList
  213. //
  214. // Synopsis: Build a tunnel address list.
  215. //
  216. // Arguments: pArgs ptr to ArgsStruct
  217. // pHe a ptr to hostent(returned by gethostbyname()).
  218. //
  219. // Returns: TRUE if SUCCESS
  220. // FALSE otherwise.
  221. //
  222. //----------------------------------------------------------------------------
  223. BOOL BuildDnsTunnelList(
  224. ArgsStruct *pArgs,
  225. struct hostent *pHe
  226. )
  227. {
  228. DWORD dwCnt;
  229. //
  230. // see how many addrs we have
  231. //
  232. for (dwCnt=0; pHe->h_addr_list[dwCnt]; dwCnt++)
  233. ;
  234. if (dwCnt < 2)
  235. {
  236. return FALSE;
  237. }
  238. //
  239. // if we have more than one addrs, save the list.
  240. //
  241. pArgs->dwDnsTunnelAddrCount = dwCnt;
  242. if (!(pArgs->pucDnsTunnelIpAddr_list = (unsigned char *)CmMalloc(dwCnt*pHe->h_length)))
  243. {
  244. CMTRACE(TEXT("InvokeGetHostByName: failed to alloc tunnel addr list"));
  245. return FALSE;
  246. }
  247. for (dwCnt=0; dwCnt<pArgs->dwDnsTunnelAddrCount; dwCnt++)
  248. {
  249. CopyMemory(pArgs->pucDnsTunnelIpAddr_list + dwCnt*pHe->h_length,
  250. pHe->h_addr_list[dwCnt],
  251. pHe->h_length);
  252. }
  253. pArgs->uiCurrentDnsTunnelAddr = 0;
  254. //
  255. // we need a random list. With this, we can get a random addr in constant
  256. // time(and fast). see cmtools\getips.
  257. //
  258. if (!BuildRandomTunnelIndex(pArgs, dwCnt))
  259. {
  260. CmFree(pArgs->pucDnsTunnelIpAddr_list);
  261. pArgs->pucDnsTunnelIpAddr_list = NULL;
  262. return FALSE;
  263. }
  264. return TRUE;
  265. }
  266. //+---------------------------------------------------------------------------
  267. //
  268. // Function: BuildRandomTunnelIndex
  269. //
  270. // Synopsis: Build a list random indices. With this, we can get a random
  271. // addr in constant time(and fast). see cmtools\getips.
  272. //
  273. // Arguments: pArgs ptr to ArgsStruct
  274. // dwCount # of of indices
  275. //
  276. // Returns: TRUE if SUCCESS
  277. // FALSE otherwise.
  278. //
  279. //----------------------------------------------------------------------------
  280. BOOL BuildRandomTunnelIndex(
  281. ArgsStruct *pArgs,
  282. DWORD dwCount
  283. )
  284. {
  285. DWORD i, j;
  286. PWORD rgwIndex;
  287. WORD wTmp;
  288. //
  289. // we can only have at most 65536 ip addrs(the max. range of a WORD), which is plenty.
  290. //
  291. MYDBGASSERT((dwCount > 1) && (dwCount <= 65536));
  292. if (!(pArgs->rgwRandomDnsIndex = (PWORD)CmMalloc(sizeof(WORD)*dwCount)))
  293. {
  294. return FALSE;
  295. }
  296. //
  297. // now start build the random indices...
  298. //
  299. for (i=0, rgwIndex=pArgs->rgwRandomDnsIndex; i<dwCount; i++)
  300. {
  301. rgwIndex[i] = (WORD)i;
  302. }
  303. #ifdef DEBUG
  304. {
  305. unsigned char *puc;
  306. TCHAR szAddr[16]; // xxx.xxx.xxx.xxx
  307. CMTRACE2(TEXT("BuildRandomTunnelIndex: BEFORE randomization(server=%s, count=%u):"),
  308. pArgs->GetTunnelAddress(), dwCount);
  309. for (i=0; i<dwCount; i++)
  310. {
  311. puc = pArgs->pucDnsTunnelIpAddr_list + i*4;
  312. wsprintfU(szAddr, TEXT("%hu.%hu.%hu.%hu"),
  313. *puc,
  314. *(puc+1),
  315. *(puc+2),
  316. *(puc+3));
  317. CMTRACE2(TEXT("%u: %s"), i, szAddr);
  318. }
  319. }
  320. #endif
  321. //
  322. // If we only have 2 addrs, the first address has already been used by RAS,
  323. // there's no need to randomize the list. We'll just use the 2nd addr.
  324. //
  325. if (dwCount == 2)
  326. {
  327. return TRUE;
  328. }
  329. CRandom r;
  330. //
  331. // randomize the indices. skip the first entry.
  332. //
  333. for (i=1; i<dwCount; i++)
  334. {
  335. do
  336. {
  337. //
  338. // j has to be non-zero(to leave the 0-th entry untouhced).
  339. //
  340. j = r.Generate() % dwCount;
  341. } while (!j);
  342. if (i != j)
  343. {
  344. wTmp = rgwIndex[i];
  345. rgwIndex[i] = rgwIndex[j];
  346. rgwIndex[j] = wTmp;
  347. }
  348. }
  349. #ifdef DEBUG
  350. {
  351. unsigned char *puc;
  352. TCHAR szAddr[16]; // xxx.xxx.xxx.xxx
  353. CMTRACE2(TEXT("BuildRandomTunnelIndex: AFTER randomization(server=%s, count=%u):"),
  354. pArgs->GetTunnelAddress(), dwCount);
  355. for (i=0; i<dwCount; i++)
  356. {
  357. puc = pArgs->pucDnsTunnelIpAddr_list + rgwIndex[i]*4;
  358. wsprintfU(szAddr, TEXT("%hu.%hu.%hu.%hu"),
  359. *puc,
  360. *(puc+1),
  361. *(puc+2),
  362. *(puc+3));
  363. CMTRACE2(TEXT("%u: %s"), i, szAddr);
  364. }
  365. }
  366. #endif
  367. return TRUE;
  368. }