Case sensitivity of ISA/TMG generated proxy auto configuration (pac) files

Scenario

From time to time we come across cases where customers complain that the proxy exception list does not work for certain URLs and (Winhttp) clients still try to connect to the destination server using the proxy instead of going directly.

Affected applications vary, we have seen issues with outlook 2007, SCCM, but the list might not be limited to those two – any Winhttp application might show the same symptoms.

Upon investigating these issues we found that the problem is a case-sensitivity issue – applications might provide an uppercase (or mixed-case) name as URL, whereas the ISA generated pac file works with lowercase exception names (no matter how you entered them in the UI) and case sensitive comparison.

The behavior of TMG is by default the same as that of ISA – however, we now have an option to influence whether we perform case sensitive comparison.

ISA behavior for generating the pac file

Looking at the relevant parts of an ISA generated script we see:

function MakeNames(){

this[0]="*.domain.tld";

}

DirectNames=new MakeNames();

cDirectNames=1;

….

function FindProxyForURL(url, host){

for(i=0; i<cDirectNames; i++){

  if(shExpMatch(host, DirectNames[i])){

   fIp = true;

   break;}

  if(shExpMatch(url, DirectNames[i]))

   return "DIRECT";

}

You might notice two things: “DirectNames”, our exception list contains lowercase names (as mentioned earlier, no matter how you enter it in the UI), and we do not convert the input to lowercase in FindProxyForUrl before making a comparison.

Because shExpMatch() performs a case sensitive comparison, here is what happens:

1. The Winhttp Client obtains the wpad script (AKA proxy.pac) from ISA.  This script contains code and data to assist the client with determining which proxy to use (if at all).

2. The Winhttp client passes each request to the wpad script for processing

3. The script relies on text matching functionality provided by the client in the form of shExpMatch(); shExpMatch is case-sensitive (by design)

4. if the URL being requested has an FQDN of HOST.DOMAIN.TLD and the wpad script includes *.domain.tld in the “direct access” list, shExpMatch() will return “false”

5. if the shExpMatch returns false for this comparison, the wpad script will return to the web client with a list of proxies to use for this request

Therefore, the client will not try to connect directly to the destination but will use a proxy instead.

TMG behavior for generating pac files

Although by default TMG behaves the same way as ISA, if you look at the generated pac file, you can notice the following differences (showing only the relevant parts):

ConvertUrlToLowerCase=false;

...

function MakeNames(){

this[0]="*.domain.tld";

}

DirectNames=new MakeNames();

cDirectNames=1;

....

function ImplementFindProxyForURL(url, host){

for(i=0; i<cDirectNames; i++){

if(ExpMatch(host, DirectNames[i])){

   fIp = true;

   break;}

  if(ExpMatch(url, DirectNames[i]))

   return "DIRECT";

}

...

function ExpMatch(str, exp){

if (ConvertUrlToLowerCase)

{

  str = str.toLowerCase();

}

return shExpMatch(str, exp);

}

The key difference is that for the comparison we first call a wrapper ExpMatch, which depending on the value of ConvertUrlToLowerCase converts the input string to lowercase before calling shExpMatch.

If we could manage to set ConvertUrlToLowercase to true, we could circumvent the problem described at the beginning.

Luckily, a new property ConvertUrlToLowerCase was added to the IFPCClientAutoScript3 interface (see http://msdn.microsoft.com/en-us/library/ff824480(VS.85).aspx) to allow lower-casing the URLs passed to the routing script before performing comparison, thus making the routing script case-insensitive.
This behavior is OFF by default. You can however enable this with the following script, provided here as an example.

'
' set wpad script to lowercase its input url – for Internal network
'
set fpc = CreateObject("FPC.ROOT")
set net_internal = fpc.GetContainingArray().NetworkConfiguration.Networks("Internal")
set wpad = net_internal.ClientConfig.Browser.AutoScript
wpad.ConvertUrlToLowerCase = -1
wpad.save

Authors
Balint Toth
Support Escalation Engineer
Microsoft CSS Forefront Edge Team

Technical Reviewer
Eric Detoc
Escalation Engineer
Microsoft CSS Forefront Edge Team