📄 proxydetect.cc
字号:
// TODO: Abstract this better for cross-platformability#ifdef _WINDOWS#include "win32.h"#include <shlobj.h>#endif#include "httpcommon.h"#include "httpcommon-inl.h"#include "proxydetect.h"#include "stringutils.h"#include "basicdefs.h"#if _WINDOWS#define _TRY_FIREFOX 1#define _TRY_WINHTTP 1#define _TRY_JSPROXY 0#define _TRY_WM_FINDPROXY 0#define _TRY_IE_LAN_SETTINGS 1#endif // _WINDOWS#if _TRY_WINHTTP//#include <winhttp.h>// Note: From winhttp.hconst char WINHTTP[] = "winhttp";typedef LPVOID HINTERNET;typedef struct { DWORD dwAccessType; // see WINHTTP_ACCESS_* types below LPWSTR lpszProxy; // proxy server list LPWSTR lpszProxyBypass; // proxy bypass list} WINHTTP_PROXY_INFO, * LPWINHTTP_PROXY_INFO;typedef struct { DWORD dwFlags; DWORD dwAutoDetectFlags; LPCWSTR lpszAutoConfigUrl; LPVOID lpvReserved; DWORD dwReserved; BOOL fAutoLogonIfChallenged;} WINHTTP_AUTOPROXY_OPTIONS;typedef struct { BOOL fAutoDetect; LPWSTR lpszAutoConfigUrl; LPWSTR lpszProxy; LPWSTR lpszProxyBypass;} WINHTTP_CURRENT_USER_IE_PROXY_CONFIG;extern "C" {typedef HINTERNET (WINAPI * pfnWinHttpOpen)( IN LPCWSTR pwszUserAgent, IN DWORD dwAccessType, IN LPCWSTR pwszProxyName OPTIONAL, IN LPCWSTR pwszProxyBypass OPTIONAL, IN DWORD dwFlags);typedef BOOL (STDAPICALLTYPE * pfnWinHttpCloseHandle)( IN HINTERNET hInternet);typedef BOOL (STDAPICALLTYPE * pfnWinHttpGetProxyForUrl)( IN HINTERNET hSession, IN LPCWSTR lpcwszUrl, IN WINHTTP_AUTOPROXY_OPTIONS * pAutoProxyOptions, OUT WINHTTP_PROXY_INFO * pProxyInfo );typedef BOOL (STDAPICALLTYPE * pfnWinHttpGetIEProxyConfig)( IN OUT WINHTTP_CURRENT_USER_IE_PROXY_CONFIG * pProxyConfig);} // extern "C"#define WINHTTP_AUTOPROXY_AUTO_DETECT 0x00000001#define WINHTTP_AUTOPROXY_CONFIG_URL 0x00000002#define WINHTTP_AUTOPROXY_RUN_INPROCESS 0x00010000#define WINHTTP_AUTOPROXY_RUN_OUTPROCESS_ONLY 0x00020000#define WINHTTP_AUTO_DETECT_TYPE_DHCP 0x00000001#define WINHTTP_AUTO_DETECT_TYPE_DNS_A 0x00000002#define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY 0#define WINHTTP_ACCESS_TYPE_NO_PROXY 1#define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3#define WINHTTP_NO_PROXY_NAME NULL#define WINHTTP_NO_PROXY_BYPASS NULL#endif // _TRY_WINHTTP#if _TRY_JSPROXYextern "C" {typedef BOOL (STDAPICALLTYPE * pfnInternetGetProxyInfo)( LPCSTR lpszUrl, DWORD dwUrlLength, LPSTR lpszUrlHostName, DWORD dwUrlHostNameLength, LPSTR * lplpszProxyHostName, LPDWORD lpdwProxyHostNameLength );} // extern "C"#endif // _TRY_JSPROXY#if _TRY_WM_FINDPROXY#include <comutil.h>#include <wmnetsourcecreator.h>#include <wmsinternaladminnetsource.h>#endif // _TRY_WM_FINDPROXY#if _TRY_IE_LAN_SETTINGS#include <wininet.h>#include <string>#endif // _TRY_IE_LAN_SETTINGSusing namespace utils_base;//////////////////////////////////////////////////////////////////////// Utility Functions//////////////////////////////////////////////////////////////////////#ifdef _WINDOWS#ifdef _UNICODEtypedef std::wstring tstring;std::string Utf8String(const tstring& str) { return ToUtf8(str); }#else // !_UNICODEtypedef std::string tstring;std::string Utf8String(const tstring& str) { return str; }#endif // !_UNICODE#endif // _WINDOWS//////////////////////////////////////////////////////////////////////// GetProxySettingsForUrl//////////////////////////////////////////////////////////////////////bool WildMatch(const char * target, const char * pattern) { while (*pattern) { if (*pattern == '*') { if (!*++pattern) { return true; } while (*target) { if ((toupper(*pattern) == toupper(*target)) && WildMatch(target + 1, pattern + 1)) { return true; } ++target; } return false; } else { if (toupper(*pattern) != toupper(*target)) { return false; } ++target; ++pattern; } } return !*target;}bool ProxyItemMatch(const Url<char>& url, char * item, size_t len) { // hostname:443 if (char * port = strchr(item, ':')) { *port++ = '\0'; if (url.port() != atol(port)) { return false; } } // A.B.C.D or A.B.C.D/24 int a, b, c, d, m; int match = sscanf(item, "%d.%d.%d.%d/%d", &a, &b, &c, &d, &m); if (match >= 4) { uint32 ip = ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | (d & 0xFF); if ((match < 5) || (m > 32)) m = 32; else if (m < 0) m = 0; uint32 mask = (m == 0) ? 0 : (~0UL) << (32 - m); SocketAddress addr(url.server()); return !addr.IsUnresolved() && ((addr.ip() & mask) == (ip & mask)); } // .foo.com if (*item == '.') { size_t hostlen = url.server().length(); return (hostlen > len) && (stricmp(url.server().c_str() + (hostlen - len), item) == 0); } // localhost or www.*.com if (!WildMatch(url.server().c_str(), item)) return false; return true;}bool ProxyListMatch(const Url<char>& url, const std::string& slist, char sep) { const size_t BUFSIZE = 256; char buffer[BUFSIZE]; const char* list = slist.c_str(); while (*list) { // Remove leading space if (isspace(*list)) { ++list; continue; } // Break on separator size_t len; const char * start = list; if (const char * end = strchr(list, sep)) { len = (end - list); list += len + 1; } else { len = strlen(list); list += len; } // Remove trailing space while ((len > 0) && isspace(start[len-1])) --len; // Check for oversized entry if (len >= BUFSIZE) continue; memcpy(buffer, start, len); buffer[len] = 0; if (!ProxyItemMatch(url, buffer, len)) continue; return true; } return false;}bool Better(ProxyType lhs, const ProxyType rhs) { // PROXY_NONE, PROXY_HTTPS, PROXY_SOCKS5, PROXY_UNKNOWN const int PROXY_VALUE[4] = { 0, 2, 3, 1 }; return (PROXY_VALUE[lhs] > PROXY_VALUE[rhs]);}bool ParseProxy(const std::string& saddress, ProxyInfo& proxy) { const size_t kMaxAddressLength = 1024; // Allow semicolon, space, or tab as an address separator const char* const kAddressSeparator = " ;\t"; ProxyType ptype; std::string host; uint16 port; const char* address = saddress.c_str(); while (*address) { size_t len; const char * start = address; if (const char * sep = strchr(address, kAddressSeparator)) { len = (sep - address); address += len + 1; while (strchr(kAddressSeparator, *address)) { address += 1; } } else { len = strlen(address); address += len; } if (len > kMaxAddressLength - 1) { LOG(LS_WARNING) << "Proxy address too long [" << start << "]"; continue; } char buffer[kMaxAddressLength]; memcpy(buffer, start, len); buffer[len] = 0; char * colon = strchr(buffer, ':'); if (!colon) { LOG(LS_WARNING) << "Proxy address without port [" << buffer << "]"; continue; } *colon = 0; char * endptr; port = static_cast<uint16>(strtol(colon + 1, &endptr, 0)); if (*endptr != 0) { LOG(LS_WARNING) << "Proxy address with invalid port [" << buffer << "]"; continue; } if (char * equals = strchr(buffer, '=')) { *equals = 0; host = equals + 1; if (_stricmp(buffer, "socks") == 0) { ptype = PROXY_SOCKS5; } else if (_stricmp(buffer, "https") == 0) { ptype = PROXY_HTTPS; } else { LOG(LS_WARNING) << "Proxy address with unknown protocol [" << buffer << "]"; ptype = PROXY_UNKNOWN; } } else { host = buffer; ptype = PROXY_UNKNOWN; } if (Better(ptype, proxy.type)) { proxy.type = ptype; proxy.address.SetIP(host); proxy.address.SetPort((int)port); } } return (proxy.type != PROXY_NONE);}#if _WINDOWSbool IsDefaultBrowserFirefox() { HKEY key; LONG result = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"http\\shell\\open\\command", 0, KEY_READ, &key); if (ERROR_SUCCESS != result) return false; wchar_t* value = NULL; DWORD size, type; result = RegQueryValueEx(key, L"", 0, &type, NULL, &size); if (REG_SZ != type) { result = ERROR_ACCESS_DENIED; // Any error is fine } else if (ERROR_SUCCESS == result) { value = new wchar_t[size+1]; BYTE* buffer = reinterpret_cast<BYTE*>(value); result = RegQueryValueEx(key, L"", 0, &type, buffer, &size); } RegCloseKey(key); bool success = false; if (ERROR_SUCCESS == result) { value[size] = L'\0'; for (size_t i=0; i<size; ++i) { value[i] = tolowercase(value[i]); } success = (NULL != strstr(value, L"firefox.exe")); } delete [] value; return success;}#endif#if _TRY_FIREFOX#define USE_FIREFOX_PROFILES_INI 1bool GetDefaultFirefoxProfile(std::wstring* profile) { ASSERT(NULL != profile); wchar_t path[MAX_PATH]; if (SHGetFolderPath(0, CSIDL_APPDATA, 0, SHGFP_TYPE_CURRENT, path) != S_OK) return false; std::wstring profile_root(path); profile_root.append(L"\\Mozilla\\Firefox\\");#if USE_FIREFOX_PROFILES_INI std::wstring tmp(profile_root); tmp.append(L"profiles.ini"); FILE * fp = _wfopen(tmp.c_str(), L"rb"); if (!fp) return false; // [Profile0] // Name=default // IsRelative=1 // Path=Profiles/2de53ejb.default // Default=1 // Note: we are looking for the first entry with "Default=1", or the last entry in the file std::wstring candidate; bool relative = true; char buffer[1024]; while (fgets(buffer, sizeof(buffer), fp)) { size_t len = strlen(buffer); while ((len > 0) && isspace(buffer[len-1])) buffer[--len] = 0; if (buffer[0] == '[') { relative = true; candidate.clear(); } else if (strnicmp(buffer, "IsRelative=", 11) == 0) { relative = (buffer[11] != '0'); } else if (strnicmp(buffer, "Path=", 5) == 0) { if (relative) { candidate = profile_root; } else { candidate.clear(); } candidate.append(ToUtf16(buffer + 5)); candidate.append(L"\\"); } else if (strnicmp(buffer, "Default=", 8) == 0) { if ((buffer[8] != '0') && !candidate.empty()) { break; } } } fclose(fp); if (candidate.empty()) return false; *profile = candidate;#else // !USE_FIREFOX_PROFILES_INI std::wstring tmp(profile_root); tmp.append(L"Profiles\\*.default");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -