#include "stdafx.h" #if !defined(BITS_V12_ON_NT4) #include "proxy.tmh" #endif HRESULT CACHED_AUTOPROXY::Generate( const TCHAR Host[] ) { if (GetTickCount() - m_TimeStamp > CACHED_PROXY_LIFETIME_IN_MSEC) { m_HostName = L""; } if (0 == _tcscmp( Host, m_HostName )) { LogInfo("using existing proxy info for '%S'", Host ); return S_OK; } LogInfo( "detecting proxy for '%S'", Host ); // // Detect IE settings and look up proxy if necessary. // Boilerplate from Stephen Sulzer. // WINHTTP_PROXY_INFO ProxyInfo; WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions; WINHTTP_CURRENT_USER_IE_PROXY_CONFIG IEProxyConfig; LPWSTR AutoConfigUrl = 0; BOOL fTryAutoProxy = FALSE; BOOL fSuccess = FALSE; ZeroMemory(&ProxyInfo, sizeof(ProxyInfo)); ZeroMemory(&AutoProxyOptions, sizeof(AutoProxyOptions)); ZeroMemory(&IEProxyConfig, sizeof(IEProxyConfig)); if (WinHttpGetIEProxyConfigForCurrentUser(&IEProxyConfig)) { LogInfo("got user's IE info"); if (IEProxyConfig.fAutoDetect) { LogInfo("IE specifies auto-detect"); AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; AutoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; fTryAutoProxy = TRUE; } if (IEProxyConfig.lpszAutoConfigUrl) { LogInfo("IE specifies auto-config URL '%S'", IEProxyConfig.lpszAutoConfigUrl ? IEProxyConfig.lpszAutoConfigUrl : NullString ); AutoProxyOptions.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL; AutoProxyOptions.lpszAutoConfigUrl = IEProxyConfig.lpszAutoConfigUrl; AutoConfigUrl = IEProxyConfig.lpszAutoConfigUrl; fTryAutoProxy = TRUE; } AutoProxyOptions.fAutoLogonIfChallenged = TRUE; } else { LogInfo("no user IE info: %d", GetLastError()); // WinHttpGetIEProxyForCurrentUser failed, try autodetection anyway... AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; AutoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; fTryAutoProxy = TRUE; } if (fTryAutoProxy) { LogInfo("trying auto-detect..."); fSuccess = WinHttpGetProxyForUrl( m_hInternet, Host, &AutoProxyOptions, &ProxyInfo ); LogInfo("auto-detect returned %d (%d)", fSuccess, fSuccess ? 0 : GetLastError() ); } // If we didn't do autoproxy or if it failed, see // if there's an explicit proxy server in the IE // proxy configuration... // // This is where the WinHttpGetIEProxyConfigForCurrentUser API // really comes in handy: in environments in which autoproxy is // not supported and so the user's IE browser must be // configured with an explicit proxy server. // if (!fTryAutoProxy || !fSuccess) { LogInfo("looking for backup ideas"); if (IEProxyConfig.lpszProxy) { LogInfo("using named proxy '%S'", IEProxyConfig.lpszProxy ? IEProxyConfig.lpszProxy : NullString ); ProxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; ProxyInfo.lpszProxy = IEProxyConfig.lpszProxy; ProxyInfo.lpszProxyBypass = IEProxyConfig.lpszProxyBypass; } } // // Sometimes the registry contains a single or double colon for the proxy or, oddly, bypass list. // SetRequestProxy rejects them. Both cases should be treated like a NULL string. // static wchar_t SingleColon[] = L":"; static wchar_t DoubleColon[] = L"::"; if (ProxyInfo.lpszProxy) { if (0 == wcscmp( ProxyInfo.lpszProxy, SingleColon ) || 0 == wcscmp( ProxyInfo.lpszProxy, DoubleColon )) { LogWarning("suppressing invalid proxy string %S", ProxyInfo.lpszProxy ); GlobalFree( ProxyInfo.lpszProxy ); ProxyInfo.lpszProxy = NULL; } } if (ProxyInfo.lpszProxyBypass) { if (0 == wcscmp( ProxyInfo.lpszProxyBypass, SingleColon ) || 0 == wcscmp( ProxyInfo.lpszProxyBypass, DoubleColon )) { LogWarning("suppressing invalid bypass string %S", ProxyInfo.lpszProxyBypass ); GlobalFree( ProxyInfo.lpszProxyBypass ); ProxyInfo.lpszProxyBypass = NULL; } } LogInfo("proxy '%S'", ProxyInfo.lpszProxy ? ProxyInfo.lpszProxy : NullString ); LogInfo("bypass list '%S'", ProxyInfo.lpszProxyBypass ? ProxyInfo.lpszProxyBypass : NullString ); LogInfo("access type %d", ProxyInfo.dwAccessType ); if (AutoConfigUrl) { GlobalFree( AutoConfigUrl ); } Clear(); m_ProxyInfo = ProxyInfo; m_HostName = Host; m_fValid = true; m_TimeStamp = GetTickCount(); // // We don't have to release the proxy server and proxy bypass strings // because Clear() will do that. // return S_OK; } void CACHED_AUTOPROXY::Clear() { if (m_fValid) { m_fValid = false; if (m_ProxyInfo.lpszProxy) GlobalFree(m_ProxyInfo.lpszProxy); if (m_ProxyInfo.lpszProxyBypass) GlobalFree(m_ProxyInfo.lpszProxyBypass); } ZeroMemory(&m_ProxyInfo, sizeof(m_ProxyInfo)); m_HostName = NULL; } PROXY_SETTINGS_CONTAINER::PROXY_SETTINGS_CONTAINER( LPCWSTR Url, const PROXY_SETTINGS * ProxySettings ) : m_ProxyUsage( ProxyUsageFromJobProxyUsage( ProxySettings->ProxyUsage )), m_ProxyList( NULL ), m_BypassList( NULL ), m_TokenCursor( NULL ) { // // Set up the list of proxy servers. // switch (m_ProxyUsage) { case INTERNET_OPEN_TYPE_DIRECT: break; case INTERNET_OPEN_TYPE_PROXY: { m_MasterProxyList = ProxySettings->ProxyList; m_BypassList = ProxySettings->ProxyBypassList; break; } case INTERNET_OPEN_TYPE_PRECONFIG: { THROW_HRESULT( g_ProxyCache->Generate( Url )); m_MasterProxyList = g_ProxyCache->GetProxyList(); m_BypassList = g_ProxyCache->GetBypassList(); m_AccessType = g_ProxyCache->GetAccessType(); break; } default: ASSERT( 0 ); break; } ResetCurrentProxy(); } HRESULT SetRequestProxy( HINTERNET hRequest, PROXY_SETTINGS_CONTAINER * ProxySettings ) { WINHTTP_PROXY_INFO ProxyInfo; ProxyInfo.dwAccessType = ProxySettings->GetProxyUsage(); ProxyInfo.lpszProxy = const_cast( ProxySettings->GetCurrentProxy() ); ProxyInfo.lpszProxyBypass = const_cast( ProxySettings->GetBypassList() ); LogInfo("proxy info:"); LogInfo("access: %d", ProxyInfo.dwAccessType ); LogInfo("server '%S'", ProxyInfo.lpszProxy ? ProxyInfo.lpszProxy : NullString ); LogInfo("bypass '%S'", ProxyInfo.lpszProxyBypass ? ProxyInfo.lpszProxyBypass : NullString ); if (ProxyInfo.dwAccessType == INTERNET_OPEN_TYPE_DIRECT) { LogInfo("proxy usage disabled"); return S_OK; } if (ProxyInfo.lpszProxy == NULL) { LogInfo("null proxy"); return S_OK; } if (ProxyInfo.dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG) { LogInfo("mapping PRECONFIG to named proxy"); ProxyInfo.dwAccessType = INTERNET_OPEN_TYPE_PROXY; } if (!WinHttpSetOption( hRequest, WINHTTP_OPTION_PROXY, &ProxyInfo, sizeof(ProxyInfo) )) { DWORD err = GetLastError(); LogWarning( "can't set proxy option: %!winerr!", err ); return HRESULT_FROM_WIN32( err ); } return S_OK; } bool IsPossibleProxyFailure( DWORD err ) { switch (err) { case ERROR_WINHTTP_NAME_NOT_RESOLVED: case ERROR_WINHTTP_CANNOT_CONNECT: case ERROR_WINHTTP_CONNECTION_ERROR: case ERROR_WINHTTP_TIMEOUT: return true; default: return false; } }