Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Hi,
When creating an automatic proxy-configuration script (PAC-file also known as wpad.dat), questions arrive on how these could be optimized in order to speed up their performance.
The functions which can be used in order to evaluate an address (URL and hostname) are explained in the following article:
JavaScript or JScript Auto-Proxy Example Files
https://technet.microsoft.com/library/Dd361950
As mentioned in that article, the functions isInNet(), isResolvable() and dnsResolve() initiate queries to the DNS-subsystem.
Therefore the usage of these functions should be avoided, when possible or at least reduced.
1. Query for NetBIOS-names
NetBIOS-names (servernames with no dot in their name) are typically used in the intranet only and are therefore not routed through the proxy.
if (isPlainHostName(host))
return "DIRECT";
2. Query for internal DNS-suffixes
Internally used DNS-zones are normally routed directly. The easiest way to determine such hosts is done by using the function dnsDomainis:
if (dnsDomainIs (host,".dns.company.com"))
return "DIRECT";
The faster method for the same result can be done by using ShExMatch(), which performs astring compare. So the same result with the function above, where the “*”-character is then used as wildcard:
if (shExpMatch(host,"*.dns.company.com"))
return "DIRECT";
3. Query for IP-ranges
The idea for that rule is to check, if the IP-address of the host belongs to the local intranet, regardless to the name of the webserver, which should bypass the proxy in order to navigate directly to the it.
In case, that the IP-address had been entered directly in the address-bar there is no need to resolve it again. You can use the following code in order to check, if the host has already the format of an IP-address :
var isIpV4Addr = /^(\d+.){3}\d+$/;
ret = isIpV4Addr.test (host);
This routine checks if the variable host contains 3 numbers which are followed by a dot, and if another number is followed- The result of this check is then passed to the variable ret, which is true in case of an IP, and false – if otherwise.
This would be be the codesnip where the variable hostIP will contain the IP-address for additional checks later:
var hostIP;
var isIpV4Addr = /^(\d+.){3}\d+$/;
if (isIpV4Addr.test (host))
hostIP=host;
else
hostIP=dnsResolve (host);
When a non-existing host had been passed to the function (e.g. cause the user entered something wrong in the address bar), the result in hostIP might be 0. Any additional errorhandling could be done by the proxy:
if (hostIP==0)
return "PROXY myproxy:80";
Now, as we have the IP-address of the host, the checks for the internal IP-ranges needs to be done.
When possible, use the shExpMatch-function instead of isInNet. The following two codesnips have the identical result, while shExpMatch is faster in execution:
if (isInNet (hostIP, "95.53.0.0","255.255.0.0"))
return "DIRECT";
if (shExpMatch (hostIP, "95.53.*))
return "DIRECT";
4. Javascript is case-sensitive
The proxy script uses the language javascript, which is case-sensitve. Therefore an if-clause where upper characters are used will never turn true, while the other parameter is using lowercase.
Internet Explorer itself converts the variables host and url into lowercase before the function FindProxyForURL is called.
This is not true for WinHTTP, which passes the hoist and the url directly to the function.
Therefore the parameters, which are checked within the PAC-file should be converted within the PAC befotre they are evaluated. Here is the call for the convert:
host = host.toLowerCase();
5. Use of IPv6
In case that you want to use and handle IPv6-addresses, Internet Explorer supports them since IE7 on every OS-Version (and WinHTTP since Windows Vista), but you then need to use “Ex“-functions (like isInNetEx ()) as mentioned in the following Blogpost:
WinINet and WinHTTP IPv6 Support in Web Proxy Auto-Discovery (WPAD) scripts enabled in Windows Vista
https://blogs.msdn.com/b/wndp/archive/2006/07/18/ipv6-wpad-for-winhttp-and-wininet.aspx
One example, where the implementation of myIpAddressEx was very useful is also mentioned in the KB-article https://support.microsoft.com/kb/2839111/en-us
6. Testing of a PAC-file
In case that the script contains any syntax-error (e.g. a missing ‘)’-character in an if-statement, the script is no more executed. In order to minimize such errors, you may consider the usage of a script-editor which performs syntax-checking on the fly.
When using Visual Studio, you can just rename the extension of your PAC-file to JS when editing.
After this, you can test it by configuring it in IE as a local PAC-file. For the local C:-drive the syntax in order to configure IE would be file://c:\test.pac
With IE11, the usage of a PAC-file through the file-protocol is no more possible, unless you add the following registry-key
[HKLM\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings]
(DWORD)"EnableLegacyAutoProxyFeatures"=1
More information to the usage of local PAC-files is available in the following Blogpost:
Understanding Web Proxy Configuration
When debugging and testing the PAC-file, you can add statements as extraline which will initiate a popup, when the line is hit:
alert ("We are now here and host is: " + host);
Of course, alert ()-statements should never be active within the production environment.
6.1 Testing with autoprox.exe
Sometimes you need just to test your PAC-file, if the expected route is returned, although you have no access to the website in question. For such testing youcan use the (attached) command line-utility tool autoprox.exe, which my colleague Pierre-Louis Coll created.
When starting it in a CMD without additional parameter the usage is displayed:
C:\temp>autoprox
Version : 2.1.0.0
Usage : AUTOPROX -s (calling DetectAutoProxyUrl and saving wpad.dat file in temporary file)
Usage : AUTOPROX [-h] url [Path to autoproxy file]
-h: calls InternetInitializeAutoProxyDll with helper functions implemented in AUTOPROX
AUTOPROX url: calling DetectAutoProxyUrl and using WPAD.DAT logic to find the proxy for the url
AUTOPROX url path: using the autoproxy file from the path to find proxy for the url
Example: autoprox -s
Example: autoprox https://www.microsoft.com
Example: autoprox -h https://www.microsoft.com c:\inetpub\wwwroot\wpad.dat
Example: autoprox https://www.microsoft.com https://proxy/wpad.dat
Here is the output with our sample:
C:\temp>autoprox https://us.msn.com
c:\temp\sample.pac
The Winsock 2.2 dll was found okay
url: https://us.msn.com
autoproxy file path is : c:\temp\sample.pac
Calling InternetInitializeAutoProxyDll with c:\temp\sample.pac
Calling InternetGetProxyInfo with url https://us.msn.com and host us.msn.com
Proxy returned for url https://us.msn.com is:
PROXY myproxy:80;
When you want to see which DNS-related functions have been called, you can use the parameter “-h” in addition:
Here the output, when this is used:
C:\temp>autoprox -h https://us.msn.com
c:\temp\sample.pac
The Winsock 2.2 dll was found okay
Will call InternetInitializeAutoProxyDll with helperfunctions
url: https://us.msn.com
autoproxy file path is : c:\temp\sample.pac
Calling InternetInitializeAutoProxyDll with c:\temp\sample.pac
Calling InternetGetProxyInfo with url https://us.msn.com and host us.msn.com
ResolveHostByName called with lpszHostName: us.msn.com
ResolveHostByName returning lpszIPAddress:
65.55.206.229
Proxy returned for url https://us.msn.com is:
PROXY myproxy:80;
Error-Handling in autoprox.exe:
a) When you specify a non-existing PAC-file (e.g. typo in the command-line), the result from autoprox.exe will be:
ERROR: InternetInitializeAutoProxyDll failed with error number 0x6 6.
b) When the Pac-file contains syntax-errors, you typically receive the following message displayed:
ERROR: InternetGetProxyInfo failed with error number 0x3eb 1003.
After finishing the local test, the PAC-file should be copied to the webserver where it will be accessed through http-protocol.
Here would be the complete sample, as discussed above:
function FindProxyForURL(url,host)
{
// NetBIOS-names
if (isPlainHostName(host))
return "DIRECT";
// change to lower case – if not already been
done
host = host.toLowerCase();
// internal DNS-suffixes
if (shExpMatch(host, "*.corp.company.com") ||
shExpMatch(host, "*.dns.company.com"))
return "DIRECT";
// Save the IP-address to variable hostIP
var hostIP;
var isIpV4Addr = /^(\d+.){3}\d+$/;
if (isIpV4Addr.test (host))
hostIP=host;
else
hostIP=dnsResolve (host);
// IP could not be determined -> go to proxy
if (hostIP==0)
return "PROXY myproxy:80";
// These 3 scopes are used only internally
if (shExpMatch (hostIP, "95.53.*") ||
shExpMatch (hostIP, "192.168.*") ||
shExpMatch (hostIP, "127.0.0.1"))
return "DIRECT";
// Eveything else goes through the proxy
return "PROXY myproxy:80;";
}
Written by Heiko Mayer
Comments
- Anonymous
December 10, 2015
The comment has been removed - Anonymous
February 23, 2016
The comment has been removed - Anonymous
February 24, 2016
Following is my config but get direct reply for it. I think the below lines are not working as I cannot use the 10.x.x.x address as it timesout
var hostIP;
if (
shExpMatch(hostIP, "10.") ||
shExpMatch(hostIP, "172.16.") ||
shExpMatch(hostIP, "192.168.") ||
shExpMatch(hostIP, "170.") ||
return "DIRECT"; } - Anonymous
March 04, 2016
The comment has been removed - Anonymous
March 10, 2016
The comment has been removed