I have the following code:
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0A00
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <winhttp.h>
#include <string>
#include <iostream>
#pragma comment(lib, "winhttp.lib")
int wmain(int argc, wchar_t* argv[]) {
if (argc != 2) {
std::wcerr << L"Parameters: <Domain>" << std::endl;
return 1;
}
// Get proxy settings
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ProxyConfig;
ZeroMemory(&ProxyConfig, sizeof(ProxyConfig));
if (!WinHttpGetIEProxyConfigForCurrentUser(&ProxyConfig)) {
std::wcerr << L"WinHttpGetIEProxyConfigForCurrentUser failed, error: "
<< GetLastError() << std::endl;
return 1;
}
if (ProxyConfig.lpszProxy != NULL) {
// Check bypass list
if (ProxyConfig.lpszProxyBypass != NULL) {
wchar_t* domain = wcstok(ProxyConfig.lpszProxyBypass, L";");
while (domain != NULL) {
if (wcscmp(domain, argv[1]) == 0) {
std::wcout << L"Proxy Bypass" << std::endl;
GlobalFree(ProxyConfig.lpszProxy);
GlobalFree(ProxyConfig.lpszProxyBypass);
return 0;
}
domain = wcstok(NULL, L";");
}
GlobalFree(ProxyConfig.lpszProxyBypass);
}
std::wcout << L"Proxy: " << ProxyConfig.lpszProxy << std::endl;
GlobalFree(ProxyConfig.lpszProxy);
return 0;
}
// Set AUTOPROXY options
WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions;
ZeroMemory(&AutoProxyOptions, sizeof(AutoProxyOptions));
if (ProxyConfig.fAutoDetect) {
AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
AutoProxyOptions.dwAutoDetectFlags =
WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
}
if (ProxyConfig.lpszAutoConfigUrl != NULL) {
AutoProxyOptions.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL;
AutoProxyOptions.lpszAutoConfigUrl = ProxyConfig.lpszAutoConfigUrl;
}
if (AutoProxyOptions.dwFlags == NULL) {
std::wcout << L"No Proxy" << std::endl;
return 0;
}
AutoProxyOptions.fAutoLogonIfChallenged = TRUE;
// Create WinHTTP session
HINTERNET hSession = WinHttpOpen(
L"Windows",
WINHTTP_ACCESS_TYPE_NO_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
0
);
if (hSession == NULL) {
std::wcerr << L"WinHttpOpen failed, error: "
<< GetLastError() << std::endl;
return 1;
}
// Get proxy info from PAC
std::wstring wurl = L"http://" + (std::wstring)argv[1] + L"/";
WINHTTP_PROXY_INFO ProxyInfo;
ZeroMemory(&ProxyInfo, sizeof(ProxyInfo));
if (!WinHttpGetProxyForUrl(
hSession,
wurl.c_str(),
&AutoProxyOptions,
&ProxyInfo
)) {
std::wcerr << L"WinHttpGetProxyForUrl failed, error: "
<< GetLastError() << std::endl;
WinHttpCloseHandle(hSession);
return 1;
}
// ProxyInfo.lpszProxy contains the address of the proxy server
if (ProxyInfo.lpszProxy != NULL) {
std::wcout << L"Proxy: " << ProxyInfo.lpszProxy << std::endl;
GlobalFree(ProxyInfo.lpszProxy);
} else {
std::wcout << L"Proxy: NULL" << std::endl;
}
// Cleanup
if (ProxyConfig.lpszAutoConfigUrl != NULL) {
GlobalFree(ProxyConfig.lpszAutoConfigUrl);
}
WinHttpCloseHandle(hSession);
return 0;
}
It uses the WinHttpGetProxyForUrl
function to retrieve the proxy server address specified in the PAC file based on system settings.
The WinHttpGetProxyForUrl
function executed successfully without returning an error, but the given ProxyInfo.lpszProxy
variable value is always null.
The following is the content of the original PAC file I used:
var pHost = "Proxy.local";
var pPort = "1080";
var Socks5 = "SOCKS5 " + pHost + ":" + pPort + "; ";
var Socks = "SOCKS " + pHost + ":" + pPort + "; ";
var Direct = "DIRECT; ";
function FindProxyForURL(url, host) {
if (shExpMatch(dnsResolveEx(host), "*.*.*.*")) {
return Socks5 + Socks + Direct;
} else {
return Direct;
}
}
The following is a simplified version of the PAC file that always returns a proxy server:
function FindProxyForURL(url, host) {
return "SOCKS Proxy.local:1080";
}
I have tried both, but the ProxyInfo.lpszProxy
variable still gets null.
Is there an issue with my code or is the WinHttpGetProxyForUrl
function exhibiting unexpected behavior?
The reason for the error result is that the WinHttpGetProxyForUrl
function only recognizes "PROXY" and does not recognize "SOCKS" or "SOCKS5". If you observe the content of the PAC file I mentioned in the question, you will find that I am using either "SOCKS" or "SOCKS5" instead of "PROXY", and these two are ignored by the WinHttpGetProxyForUrl
function, which is why I always got NULL.
This is an undocumented and unexpected behavior. For the unexpected behavior I mentioned, on the one hand, it refers to the behavior that was not described in the document, and on the other hand, I believe that ignoring "SOCKS" and "SOCKS5" does not match the results I expected after the function is executed.
Anyway, thank him @Torrecto-MSFT for inspiring me to find the real problem.