Leaked source code of windows server 2003
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.

581 lines
18 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 2001 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: internet.cpp
  6. //
  7. // Creator: PeterWi
  8. //
  9. // Purpose: internet functions.
  10. //
  11. //=======================================================================
  12. #pragma hdrstop
  13. #include <tchar.h>
  14. #include <winsock2.h> // for LPWSADATA, struct hostent
  15. #include <wininet.h> // for InternetGetConnectedState(), InternetQueryOptionA()
  16. #include <iphlpapi.h> // for IPAddr
  17. #include <sensapi.h> // for NETWORK_ALIVE_*
  18. #include <logging.h> // for LOG_Block, LOG_Error and LOG_Internet
  19. #include <MemUtil.h> // USES_IU_CONVERSION, T2A(), MemAlloc
  20. #include <wusafefn.h>
  21. #include <shlwapi.h> // UrlGetPart
  22. #include <MISTSafe.h>
  23. #include <URLLogging.h>
  24. #define ARRAYSIZE(a) (sizeof(a)/sizeof((a)[0]))
  25. typedef BOOL (WINAPI * ISNETWORKALIVE)(LPDWORD);
  26. //typedef BOOL (WINAPI * INETCONNECTSTATE)(LPDWORD, DWORD);
  27. //typedef BOOL (WINAPI * INETQUERYOPTION)(HINTERNET, DWORD, LPVOID, LPDWORD);
  28. typedef DWORD (WINAPI * GETBESTINTERFACE)(IPAddr, DWORD *);
  29. typedef ULONG (WINAPI * INET_ADDR)(const char FAR *);
  30. typedef struct hostent FAR * (WINAPI * GETHOSTBYNAME)(const char FAR *name);
  31. typedef int (WINAPI * WSASTARTUP)(WORD, LPWSADATA);
  32. typedef int (WINAPI * WSACLEANUP)(void);
  33. #ifdef DBG
  34. typedef int (WINAPI * WSAGETLASTERROR)(void);
  35. #endif
  36. const char c_szWU_PING_URL[] = "207.46.226.17"; // current ip addr for windowsupdate.microsoft.com
  37. // forward declarations
  38. BOOL IsConnected_2_0(void);
  39. // HKLM\Software\Microsoft\Windows\CurrentVersion\WindowsUpdate\IsConnected DWORD reg value
  40. #define ISCONNECTEDMODE_Unknown -1 // static variable not initialized yet
  41. #define ISCONNECTEDMODE_Default 0
  42. // live: use AU 2.0 logic
  43. // test = InternetGetConnectedState + InternetQueryOption + GetBestInterface on static IP
  44. // CorpWU: same as ISCONNECTEDMODE_IsNetworkAliveAndGetBestInterface
  45. #define ISCONNECTEDMODE_AlwaysConnected 1
  46. // live/CorpWU: Assume the destination is always reachable. e.g. via D-tap connection.
  47. #define ISCONNECTEDMODE_IsNetworkAliveOnly 2
  48. // live/CorpWU: test = IsNetworkAlive.
  49. #define ISCONNECTEDMODE_IsNetworkAliveAndGetBestInterface 3
  50. // live: test = IsNetworkAlive + GetBestInterface on static IP
  51. // CorpWU: test = IsNetworkAlive + gethostbyname + GetBestInterface
  52. #define ISCONNECTEDMODE_MinValue 0
  53. #define ISCONNECTEDMODE_MaxValue 3
  54. inline DWORD GetIsConnectedMode(void)
  55. {
  56. static DWORD s_dwIsConnectedMode = ISCONNECTEDMODE_Unknown;
  57. if (ISCONNECTEDMODE_Unknown == s_dwIsConnectedMode)
  58. {
  59. // Assume using default connection detection mechanism
  60. s_dwIsConnectedMode = ISCONNECTEDMODE_Default;
  61. const TCHAR c_tszRegKeyWU[] = _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate");
  62. const TCHAR c_tszRegUrlLogIsConnectedMode[] = _T("IsConnectedMode");
  63. HKEY hkey;
  64. if (NO_ERROR == RegOpenKeyEx(
  65. HKEY_LOCAL_MACHINE,
  66. c_tszRegKeyWU,
  67. 0,
  68. KEY_QUERY_VALUE,
  69. &hkey))
  70. {
  71. DWORD dwSize = sizeof(s_dwIsConnectedMode);
  72. DWORD dwType;
  73. if (NO_ERROR != RegQueryValueEx(
  74. hkey,
  75. c_tszRegUrlLogIsConnectedMode,
  76. 0,
  77. &dwType,
  78. (LPBYTE) &s_dwIsConnectedMode,
  79. &dwSize) ||
  80. REG_DWORD != dwType ||
  81. sizeof(s_dwIsConnectedMode) != dwSize ||
  82. // comment out the next line to avoid error C4296: '>' : expression is always false
  83. // ISCONNECTEDMODE_MinValue > s_dwIsConnectedMode ||
  84. ISCONNECTEDMODE_MaxValue < s_dwIsConnectedMode)
  85. {
  86. s_dwIsConnectedMode = ISCONNECTEDMODE_Default;
  87. }
  88. RegCloseKey(hkey);
  89. }
  90. }
  91. return s_dwIsConnectedMode;
  92. }
  93. // ----------------------------------------------------------------------------------
  94. // IsConnected()
  95. // detect if there is a connection currently that can be used to
  96. // connect to Windows Update site.
  97. // If yes, we activate the shedule DLL
  98. //
  99. // Input : ptszUrl - Url containing host name to check for connection
  100. // fLive - whether the destination is the live site
  101. // Output: None
  102. // Return: TRUE if we are connected and we can reach the web site.
  103. // FALSE if we cannot reach the site or we are not connected.
  104. // ----------------------------------------------------------------------------------
  105. BOOL IsConnected(LPCTSTR ptszUrl, BOOL fLive)
  106. {
  107. BOOL bRet = FALSE;
  108. DWORD dwFlags = 0;
  109. ISNETWORKALIVE pIsNetworkAlive = NULL;
  110. HMODULE hIphlp = NULL, hSock = NULL, hSens = NULL;
  111. DWORD dwIsConnectedMode = GetIsConnectedMode();
  112. LOG_Block("IsConnected");
  113. if (ISCONNECTEDMODE_AlwaysConnected == dwIsConnectedMode)
  114. {
  115. LOG_Internet(_T("AlwaysConnected"));
  116. bRet = TRUE;
  117. goto lFinish;
  118. }
  119. if (fLive && ISCONNECTEDMODE_Default == dwIsConnectedMode)
  120. {
  121. LOG_Internet(_T("Use 2.0 algorithm"));
  122. bRet = IsConnected_2_0();
  123. goto lFinish;
  124. }
  125. // InternetGetConnectedState() returns FALSE if Wininet/IE AutoDial is configured.
  126. // Thus we can't rely on it to see if we have network connectivity.
  127. #if 0
  128. DWORD dwConnMethod = 0, dwState = 0, dwSize = sizeof(DWORD);
  129. bRet = InternetGetConnectedState(&dwConnMethod, 0);
  130. #ifdef DBG
  131. LOG_Internet(_T("Connection Method is %#lx"), dwConnMethod);
  132. LOG_Internet(_T("InternetGetConnectedState() return value %d"), bRet);
  133. if (dwConnMethod & INTERNET_CONNECTION_MODEM)
  134. {
  135. LOG_Internet(_T("\t%s"), _T("INTERNET_CONNECTION_MODEM"));
  136. }
  137. if (dwConnMethod & INTERNET_CONNECTION_LAN )
  138. {
  139. LOG_Internet(_T("\t%s"), _T("INTERNET_CONNECTION_LAN"));
  140. }
  141. if (dwConnMethod & INTERNET_CONNECTION_PROXY )
  142. {
  143. LOG_Internet(_T("\t%s"), _T("INTERNET_CONNECTION_PROXY"));
  144. }
  145. if (dwConnMethod & INTERNET_CONNECTION_MODEM_BUSY )
  146. {
  147. LOG_Internet(_T("\t%s"), _T("INTERNET_CONNECTION_MODEM_BUSY"));
  148. }
  149. #endif
  150. if (bRet)
  151. {
  152. // modem is dialing
  153. if (dwConnMethod & INTERNET_CONNECTION_MODEM_BUSY)
  154. {
  155. bRet = FALSE;
  156. goto lFinish;
  157. }
  158. // check if there is a proxy but currently user is offline
  159. if (dwConnMethod & INTERNET_CONNECTION_PROXY)
  160. {
  161. if (InternetQueryOptionA(NULL, INTERNET_OPTION_CONNECTED_STATE, &dwState, &dwSize))
  162. {
  163. if (dwState & (INTERNET_STATE_DISCONNECTED_BY_USER | INTERNET_STATE_DISCONNECTED))
  164. {
  165. bRet = FALSE;
  166. goto lFinish;
  167. }
  168. }
  169. else
  170. {
  171. LOG_Error(_T("IsConnected() fail to get InternetQueryOption (%#lx)"), GetLastError());
  172. }
  173. }
  174. }
  175. else
  176. {
  177. //
  178. // further test the case that user didn't run icw but is using a modem connection
  179. //
  180. const DWORD dwModemConn = (INTERNET_CONNECTION_MODEM | INTERNET_CONNECTION_MODEM_BUSY);
  181. if ((dwConnMethod & dwModemConn) == dwModemConn)
  182. {
  183. bRet = TRUE;
  184. }
  185. }
  186. //one final check for connectivity by pinging microsoft.com
  187. //if (bRet)
  188. //{
  189. // bRet = CheckByPing(szURL);
  190. //}
  191. //bugfix for InternetGetConnectedState API - if LAN card is disabled it still returns LAN connection
  192. //use GetBestInterface and see if there is any error trying to reach an outside IP address
  193. //this may fix scenarios in homelan case where there is no actual connection to internet??
  194. if (!bRet || (dwConnMethod & INTERNET_CONNECTION_LAN)) //LAN card present
  195. //bug 299338
  196. {
  197. // do gethostbyname and GetBestInterface
  198. }
  199. #endif
  200. if (NULL == (hSens = LoadLibraryFromSystemDir(TEXT("sensapi.dll"))) ||
  201. NULL == (pIsNetworkAlive = (ISNETWORKALIVE)::GetProcAddress(hSens, "IsNetworkAlive")))
  202. {
  203. LOG_Error(_T("failed to load IsNetworkAlive() from sensapi.dll"));
  204. goto lFinish;
  205. }
  206. if (pIsNetworkAlive(&dwFlags))
  207. {
  208. #ifdef DBG
  209. if (NETWORK_ALIVE_LAN & dwFlags)
  210. {
  211. LOG_Internet(_T("active LAN card(s) detected"));
  212. }
  213. if (NETWORK_ALIVE_WAN & dwFlags)
  214. {
  215. LOG_Internet(_T("active RAS connection(s) detected"));
  216. }
  217. if (NETWORK_ALIVE_AOL & dwFlags)
  218. {
  219. LOG_Internet(_T("AOL connection detected"));
  220. }
  221. #endif
  222. if (ISCONNECTEDMODE_IsNetworkAliveOnly == dwIsConnectedMode)
  223. {
  224. LOG_Internet(_T("IsNetworkAliveOnly ok"));
  225. bRet = TRUE;
  226. goto lFinish;
  227. }
  228. // can't be moved into where ptszHostName and pszHostName are
  229. // MemAlloc'ed since pszHostName will be used outside that block.
  230. USES_IU_CONVERSION;
  231. GETBESTINTERFACE pGetBestInterface = NULL;
  232. INET_ADDR pInetAddr = NULL;
  233. LPCSTR pszHostName = NULL;
  234. if (fLive && ISCONNECTEDMODE_IsNetworkAliveAndGetBestInterface == dwIsConnectedMode)
  235. {
  236. pszHostName = c_szWU_PING_URL;
  237. }
  238. else
  239. {
  240. // !fLive && (ISCONNECTEDMODE_Default == dwIsConnectedMode ||
  241. // ISCONNECTEDMODE_IsNetworkAliveAndGetBestInterface == dwIsConnectedMode)
  242. if (NULL == ptszUrl || _T('\0') == ptszUrl[0])
  243. {
  244. LOG_Error(_T("IsConnected() invalid parameter"));
  245. }
  246. else
  247. {
  248. TCHAR tszHostName[40]; // arbitrary buffer size that should work with most domain names
  249. DWORD dwCchHostName = ARRAYSIZE(tszHostName);
  250. LPTSTR ptszHostName = tszHostName;
  251. HRESULT hr = UrlGetPart(ptszUrl, tszHostName, &dwCchHostName, URL_PART_HOSTNAME, 0);
  252. if (E_POINTER == hr)
  253. {
  254. if (NULL != (ptszHostName = (LPTSTR) MemAlloc(sizeof(TCHAR) * dwCchHostName)))
  255. {
  256. hr = UrlGetPart(ptszUrl, ptszHostName, &dwCchHostName, URL_PART_HOSTNAME, 0);
  257. }
  258. else
  259. {
  260. hr = E_OUTOFMEMORY;
  261. }
  262. }
  263. if (FAILED(hr))
  264. {
  265. LOG_Error(_T("failed to extract hostname (error %#lx)"), hr);
  266. }
  267. else
  268. {
  269. pszHostName = T2A(ptszHostName);
  270. }
  271. }
  272. }
  273. if (NULL == pszHostName)
  274. {
  275. LOG_Error(_T("call to T2A (IU version) failed"));
  276. }
  277. else if (
  278. NULL != (hIphlp = LoadLibraryFromSystemDir(TEXT("iphlpapi.dll"))) &&
  279. NULL != (hSock = LoadLibraryFromSystemDir(TEXT("ws2_32.dll"))) &&
  280. NULL != (pGetBestInterface = (GETBESTINTERFACE)::GetProcAddress(hIphlp, "GetBestInterface")) &&
  281. NULL != (pInetAddr = (INET_ADDR)::GetProcAddress(hSock, "inet_addr")))
  282. {
  283. IPAddr dest;
  284. LOG_Internet(_T("checking connection to %hs..."), pszHostName);
  285. //fixcode: should check against broadcasting IP addresses
  286. if (INADDR_NONE == (dest = pInetAddr(pszHostName)))
  287. {
  288. GETHOSTBYNAME pGetHostByName = NULL;
  289. WSASTARTUP pWSAStartup = NULL;
  290. WSACLEANUP pWSACleanup = NULL;
  291. #ifdef DBG
  292. WSAGETLASTERROR pWSAGetLastError = NULL;
  293. #endif
  294. WSADATA wsaData;
  295. int iErr = 0;
  296. if (NULL != (pGetHostByName = (GETHOSTBYNAME)::GetProcAddress(hSock, "gethostbyname")) &&
  297. #ifdef DBG
  298. NULL != (pWSAGetLastError = (WSAGETLASTERROR)::GetProcAddress(hSock, "WSAGetLastError")) &&
  299. #endif
  300. NULL != (pWSAStartup = (WSASTARTUP)::GetProcAddress(hSock, "WSAStartup")) &&
  301. NULL != (pWSACleanup = (WSACLEANUP)::GetProcAddress(hSock, "WSACleanup")) &&
  302. //fixcode: should be called at the constructor of CUrlLog and when IU (when online) or AU starts.
  303. 0 == pWSAStartup(MAKEWORD(1, 1), &wsaData))
  304. {
  305. #ifdef DBG
  306. DWORD dwStartTime = GetTickCount();
  307. #endif
  308. struct hostent *ptHost = pGetHostByName(pszHostName);
  309. if (NULL != ptHost &&
  310. AF_INET == ptHost->h_addrtype &&
  311. sizeof(IPAddr) == ptHost->h_length &&
  312. NULL != ptHost->h_addr_list &&
  313. NULL != ptHost->h_addr)
  314. {
  315. // take the first IP address
  316. dest = *((IPAddr FAR *) ptHost->h_addr);
  317. #ifdef DBG
  318. LOG_Internet(
  319. _T("Host name %hs resolved to be %d.%d.%d.%d, took %d msecs"),
  320. pszHostName,
  321. (BYTE) ((ptHost->h_addr)[0]),
  322. (BYTE) ((ptHost->h_addr)[1]),
  323. (BYTE) ((ptHost->h_addr)[2]),
  324. (BYTE) ((ptHost->h_addr)[3]),
  325. GetTickCount() - dwStartTime);
  326. #endif
  327. }
  328. #ifdef DBG
  329. else
  330. {
  331. LOG_Internet(_T("Host name %hs couldn't be resolved (error %d), took %d msecs"), pszHostName, pWSAGetLastError(), GetTickCount() - dwStartTime);
  332. }
  333. #endif
  334. //fixcode: should be called at the destructor of CUrlLog and when IU (when online) or AU ends.
  335. if (iErr = pWSACleanup())
  336. {
  337. LOG_Error(_T("failed to clean up winsock (error %d)"), iErr);
  338. }
  339. }
  340. else
  341. {
  342. LOG_Error(_T("failed to load winsock procs or WSAStartup() failed"));
  343. }
  344. }
  345. if (INADDR_NONE != dest)
  346. {
  347. DWORD dwErr, dwIndex;
  348. if (bRet = (NO_ERROR == (dwErr = pGetBestInterface(dest, &dwIndex))))
  349. {
  350. LOG_Internet(_T("route found on interface #%d"), dwIndex);
  351. }
  352. else
  353. {
  354. LOG_Internet(_T("GetBestInterface() failed w/ error %d"), dwErr);
  355. }
  356. }
  357. }
  358. else
  359. {
  360. LOG_Error(_T("failed to load procs from winsock/ip helper (error %d)"), GetLastError());
  361. }
  362. }
  363. else
  364. {
  365. LOG_Internet(_T("no active connection detected"));
  366. }
  367. lFinish:
  368. if (hIphlp != NULL)
  369. {
  370. FreeLibrary(hIphlp);
  371. }
  372. if (hSock != NULL)
  373. {
  374. FreeLibrary(hSock);
  375. }
  376. if (hSens != NULL)
  377. {
  378. FreeLibrary(hSens);
  379. }
  380. return (bRet);
  381. }
  382. // ----------------------------------------------------------------------------------
  383. //
  384. // Function IsConnected_2_0()
  385. // detect if there is a cunection currently can be used to
  386. // connect to live Windows Update site.
  387. // If yes, we activate the shedule DLL
  388. //
  389. // Input : None
  390. // Output: None
  391. // Return: TRUE if we are connected and we can reach the web site.
  392. // FALSE if we cannot reach the live site or we are not connected.
  393. //
  394. //
  395. // ----------------------------------------------------------------------------------
  396. BOOL IsConnected_2_0()
  397. {
  398. BOOL bRet = FALSE;
  399. DWORD dwConnMethod, dwState = 0, dwSize = sizeof(DWORD), dwErr, dwIndex;
  400. GETBESTINTERFACE pGetBestInterface = NULL;
  401. INET_ADDR pInet_addr = NULL;
  402. HMODULE hIphlp = NULL, hSock = NULL;
  403. LOG_Block("IsConnected");
  404. bRet = InternetGetConnectedState(&dwConnMethod, 0);
  405. /*
  406. #ifdef DBG
  407. LOG_Internet(_T("Connection Method is %#lx"), dwConnMethod);
  408. LOG_Internet(_T("InternetGetConnectedState() return value %d"), bRet);
  409. if (dwConnMethod & INTERNET_CONNECTION_MODEM)
  410. {
  411. LOG_Internet(_T("\t%s"), _T("INTERNET_CONNECTION_MODEM"));
  412. }
  413. if (dwConnMethod & INTERNET_CONNECTION_LAN )
  414. {
  415. LOG_Internet(_T("\t%s"), _T("INTERNET_CONNECTION_LAN"));
  416. }
  417. if (dwConnMethod & INTERNET_CONNECTION_PROXY )
  418. {
  419. LOG_Internet(_T("\t%s"), _T("INTERNET_CONNECTION_PROXY"));
  420. }
  421. if (dwConnMethod & INTERNET_CONNECTION_MODEM_BUSY )
  422. {
  423. LOG_Internet(_T("\t%s"), _T("INTERNET_CONNECTION_MODEM_BUSY"));
  424. }
  425. #endif
  426. */
  427. if (bRet)
  428. {
  429. // modem is dialing
  430. if (dwConnMethod & INTERNET_CONNECTION_MODEM_BUSY)
  431. {
  432. bRet = FALSE;
  433. goto lFinish;
  434. }
  435. // check if there is a proxy but currently user is offline
  436. if (dwConnMethod & INTERNET_CONNECTION_PROXY)
  437. {
  438. if (InternetQueryOptionA(NULL, INTERNET_OPTION_CONNECTED_STATE, &dwState, &dwSize))
  439. {
  440. if (dwState & (INTERNET_STATE_DISCONNECTED_BY_USER | INTERNET_STATE_DISCONNECTED))
  441. {
  442. bRet = FALSE;
  443. goto lFinish;
  444. }
  445. }
  446. else
  447. {
  448. LOG_Error(_T("IsConnected() fail to get InternetQueryOption (%#lx)"), GetLastError());
  449. }
  450. }
  451. }
  452. else
  453. {
  454. //
  455. // further test the case that user didn't run icw but is using a modem connection
  456. //
  457. const DWORD dwModemConn = (INTERNET_CONNECTION_MODEM | INTERNET_CONNECTION_MODEM_BUSY);
  458. if ((dwConnMethod & dwModemConn) == dwModemConn)
  459. {
  460. bRet = TRUE;
  461. }
  462. }
  463. //one final check for connectivity by pinging microsoft.com
  464. //if (bRet)
  465. //{
  466. // bRet = CheckByPing(szURL);
  467. //}
  468. //bugfix for InternetGetConnectedState API - if LAN card is disabled it still returns LAN connection
  469. //use GetBestInterface and see if there is any error trying to reach an outside IP address
  470. //this may fix scenarios in homelan case where there is no actual connection to internet??
  471. if ((bRet && (dwConnMethod & INTERNET_CONNECTION_LAN)) || //LAN card present
  472. (!bRet)) //bug 299338
  473. {
  474. struct sockaddr_in dest;
  475. hSock = LoadLibraryFromSystemDir(TEXT("ws2_32.dll"));
  476. hIphlp = LoadLibraryFromSystemDir(TEXT("iphlpapi.dll"));
  477. if ((hIphlp == NULL) || (hSock == NULL))
  478. {
  479. goto lFinish;
  480. }
  481. pGetBestInterface = (GETBESTINTERFACE)::GetProcAddress(hIphlp, "GetBestInterface");
  482. pInet_addr = (INET_ADDR)::GetProcAddress(hSock, "inet_addr");
  483. if ((pGetBestInterface == NULL) || (pInet_addr == NULL))
  484. {
  485. goto lFinish;
  486. }
  487. if ((dest.sin_addr.s_addr = pInet_addr(c_szWU_PING_URL)) == INADDR_ANY)
  488. {
  489. goto lFinish;
  490. }
  491. if (NO_ERROR != (dwErr = pGetBestInterface(dest.sin_addr.s_addr, &dwIndex)))
  492. {
  493. LOG_ErrorMsg(dwErr);
  494. bRet = FALSE;
  495. //any error bail out for now
  496. /*
  497. if (dwErr == ERROR_NETWORK_UNREACHABLE) //winerror.h
  498. {
  499. bRet = FALSE;
  500. }
  501. */
  502. }
  503. else
  504. {
  505. bRet = TRUE;
  506. }
  507. }
  508. lFinish:
  509. if (hIphlp != NULL)
  510. {
  511. FreeLibrary(hIphlp);
  512. }
  513. if (hSock != NULL)
  514. {
  515. FreeLibrary(hSock);
  516. }
  517. LOG_Internet(_T("%s"), bRet ? _T("Connected") : _T("Not connected"));
  518. return (bRet);
  519. }