wininet: Add support for detecting the proxy config URL.

Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Hans Leidekker 2019-11-22 16:32:25 +01:00 committed by Alexandre Julliard
parent 5bf055a62d
commit a4357043ff
2 changed files with 177 additions and 36 deletions

View File

@ -2,9 +2,9 @@ EXTRADEFS = -D_WINX32_
MODULE = wininet.dll
IMPORTLIB = wininet
IMPORTS = mpr shlwapi shell32 user32 ws2_32 advapi32
DELAYIMPORTS = secur32 crypt32 cryptui
DELAYIMPORTS = secur32 crypt32 cryptui dhcpcsvc iphlpapi
EXTRAINCL = $(Z_CFLAGS)
EXTRALIBS = $(CORESERVICES_LIBS) $(Z_LIBS)
EXTRALIBS = $(Z_LIBS)
C_SRCS = \
cookie.c \

View File

@ -28,14 +28,6 @@
#include "config.h"
#ifdef HAVE_CORESERVICES_CORESERVICES_H
#define GetCurrentThread MacGetCurrentThread
#define LoadResource MacLoadResource
#include <CoreServices/CoreServices.h>
#undef GetCurrentThread
#undef LoadResource
#endif
#include "winsock2.h"
#include "ws2ipdef.h"
@ -56,6 +48,10 @@
#include "winerror.h"
#define NO_SHLWAPI_STREAM
#include "shlwapi.h"
#include "ws2tcpip.h"
#include "winternl.h"
#include "iphlpapi.h"
#include "dhcpcsdk.h"
#include "wine/exception.h"
@ -2295,38 +2291,183 @@ BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
return res == ERROR_SUCCESS;
}
static WCHAR *get_proxy_autoconfig_url(void)
static IP_ADAPTER_ADDRESSES *get_adapters(void)
{
#if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
ULONG err, size = 1024, flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
IP_ADAPTER_ADDRESSES *tmp, *ret;
CFDictionaryRef settings = CFNetworkCopySystemProxySettings();
WCHAR *ret = NULL;
SIZE_T len;
const void *ref;
if (!settings) return NULL;
if (!(ref = CFDictionaryGetValue( settings, kCFNetworkProxiesProxyAutoConfigURLString )))
if (!(ret = heap_alloc( size ))) return NULL;
err = GetAdaptersAddresses( AF_UNSPEC, flags, NULL, ret, &size );
while (err == ERROR_BUFFER_OVERFLOW)
{
CFRelease( settings );
if (!(tmp = heap_realloc( ret, size ))) break;
ret = tmp;
err = GetAdaptersAddresses( AF_UNSPEC, flags, NULL, ret, &size );
}
if (err == ERROR_SUCCESS) return ret;
heap_free( ret );
return NULL;
}
static WCHAR *detect_proxy_autoconfig_url_dhcp(void)
{
IP_ADAPTER_ADDRESSES *adapters, *ptr;
DHCPCAPI_PARAMS_ARRAY send_params, recv_params;
DHCPCAPI_PARAMS param;
WCHAR name[MAX_ADAPTER_NAME_LENGTH + 1], *ret = NULL;
DWORD err, size;
BYTE *tmp, *buf = NULL;
if (!(adapters = get_adapters())) return NULL;
memset( &send_params, 0, sizeof(send_params) );
memset( &param, 0, sizeof(param) );
param.OptionId = OPTION_MSFT_IE_PROXY;
recv_params.nParams = 1;
recv_params.Params = &param;
for (ptr = adapters; ptr; ptr = ptr->Next)
{
MultiByteToWideChar( CP_ACP, 0, ptr->AdapterName, -1, name, ARRAY_SIZE(name) );
TRACE( "adapter '%s' type %u dhcpv4 enabled %d\n", wine_dbgstr_w(name), ptr->IfType, ptr->Dhcpv4Enabled );
if (ptr->IfType == IF_TYPE_SOFTWARE_LOOPBACK) continue;
/* FIXME: also skip adapters where DHCP is disabled */
size = 256;
if (!(buf = heap_alloc( size ))) goto done;
err = DhcpRequestParams( DHCPCAPI_REQUEST_SYNCHRONOUS, NULL, name, NULL, send_params, recv_params,
buf, &size, NULL );
while (err == ERROR_MORE_DATA)
{
if (!(tmp = heap_realloc( buf, size ))) goto done;
buf = tmp;
err = DhcpRequestParams( DHCPCAPI_REQUEST_SYNCHRONOUS, NULL, name, NULL, send_params, recv_params,
buf, &size, NULL );
}
if (err == ERROR_SUCCESS && param.nBytesData)
{
int len = MultiByteToWideChar( CP_ACP, 0, (const char *)param.Data, param.nBytesData, NULL, 0 );
if ((ret = heap_alloc( (len + 1) * sizeof(WCHAR) )))
{
MultiByteToWideChar( CP_ACP, 0, (const char *)param.Data, param.nBytesData, ret, len );
ret[len] = 0;
}
TRACE("returning %s\n", debugstr_w(ret));
break;
}
}
done:
heap_free( buf );
heap_free( adapters );
return ret;
}
static char *get_computer_name( COMPUTER_NAME_FORMAT format )
{
char *ret;
DWORD size = 0;
GetComputerNameExA( format, NULL, &size );
if (GetLastError() != ERROR_MORE_DATA) return NULL;
if (!(ret = heap_alloc( size ))) return NULL;
if (!GetComputerNameExA( format, ret, &size ))
{
heap_free( ret );
return NULL;
}
len = CFStringGetLength( ref );
if (len)
ret = heap_alloc( (len+1) * sizeof(WCHAR) );
if (ret)
{
CFStringGetCharacters( ref, CFRangeMake(0, len), ret );
ret[len] = 0;
}
TRACE( "returning %s\n", debugstr_w(ret) );
CFRelease( settings );
return ret;
#else
static int once;
if (!once++) FIXME( "no support on this platform\n" );
return NULL;
#endif
}
static BOOL is_domain_suffix( const char *domain, const char *suffix )
{
int len_domain = strlen( domain ), len_suffix = strlen( suffix );
if (len_suffix > len_domain) return FALSE;
if (!_strnicmp( domain + len_domain - len_suffix, suffix, -1 )) return TRUE;
return FALSE;
}
static int reverse_lookup( const struct addrinfo *ai, char *hostname, size_t len )
{
return getnameinfo( ai->ai_addr, ai->ai_addrlen, hostname, len, NULL, 0, 0 );
}
static WCHAR *build_wpad_url( const char *hostname, const struct addrinfo *ai )
{
static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0};
static const WCHAR wpadW[] = {'/','w','p','a','d','.','d','a','t',0};
char name[NI_MAXHOST];
WCHAR *ret, *p;
int len;
while (ai && ai->ai_family != AF_INET && ai->ai_family != AF_INET6) ai = ai->ai_next;
if (!ai) return NULL;
if (!reverse_lookup( ai, name, sizeof(name) )) hostname = name;
len = lstrlenW( httpW ) + strlen( hostname ) + lstrlenW( wpadW );
if (!(ret = p = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
lstrcpyW( p, httpW );
p += lstrlenW( httpW );
while (*hostname) { *p++ = *hostname++; }
lstrcpyW( p, wpadW );
return ret;
}
static WCHAR *detect_proxy_autoconfig_url_dns(void)
{
char *fqdn, *domain, *p;
WCHAR *ret;
if (!(fqdn = get_computer_name( ComputerNamePhysicalDnsFullyQualified ))) return NULL;
if (!(domain = get_computer_name( ComputerNamePhysicalDnsDomain )))
{
heap_free( fqdn );
return NULL;
}
p = fqdn;
while ((p = strchr( p, '.' )) && is_domain_suffix( p + 1, domain ))
{
char *name;
struct addrinfo *ai;
int res;
if (!(name = heap_alloc( sizeof("wpad") + strlen(p) )))
{
heap_free( fqdn );
heap_free( domain );
return NULL;
}
strcpy( name, "wpad" );
strcat( name, p );
res = getaddrinfo( name, NULL, NULL, &ai );
if (!res)
{
ret = build_wpad_url( name, ai );
freeaddrinfo( ai );
if (ret)
{
TRACE("returning %s\n", debugstr_w(ret));
heap_free( name );
break;
}
}
heap_free( name );
p++;
}
heap_free( domain );
heap_free( fqdn );
return ret;
}
static WCHAR *get_proxy_autoconfig_url(void)
{
WCHAR *ret = detect_proxy_autoconfig_url_dhcp();
if (!ret) ret = detect_proxy_autoconfig_url_dns();
return ret;
}
static DWORD query_global_option(DWORD option, void *buffer, DWORD *size, BOOL unicode)