Per location PAC files

,

Hello everyone,

as we have a lot of local proxy exceptions for regional branch offices where we require direct access for websites which only allow access from IPs coming from inside the country I was wondering if there is a way to create PAC files for specific locations (per location pac files) while using the Zapp.

Currently we use our own internal PAC files when inside the corporate network and the Zapp enforces this but we are considering using the Zapp tunnels internally as well for which we need to switch to pac files hosted with Zscaler. But since we have so many different local PAC files for the mentioned exceptions I cannot currently implement this as I do not want to configure every exception globally.

Regards
Thomas

The Zscaler-specific Source IP Variable for PAC files should allow this without needing separate PAC files per location.

Example Code:

    	var egressip = "${SRCIP}";

    	// Office Location: Austin, TX
    	if (egressip=="198.51.100.10" && 
    		(shExpMatch(host,"domain.com") || 
    			shExpMatch(host,"*.domain.com") || 
    			shExpMatch(host,"x.domain.com") || 
    			shExpMatch(host,"y.domain.com") || 
    			shExpMatch(host,"z.domain.com"))) {
    		return "DIRECT";}
    		
    	// Office Location: San Francisco, CA
    	if (egressip=="198.51.100.20" && 
    		(shExpMatch(host,"domain.com") || 
    			shExpMatch(host,"*.domain.com") || 
    			shExpMatch(host,"a.domain.com") || 
    			shExpMatch(host,"b.domain.com") || 
    			shExpMatch(host,"c.domain.com"))) {
    		return "DIRECT";}
    		
    ;}
1 Like

Alternatively you may consider the use of the Country Variable in your PAC files depending on the use-case.

Note: PAC files must be hosted on Zscaler to benefit from Zscaler-Specific Variables

First of all thanks for the replies.

The first Suggestion won’t work as we have too many Locations with dynamic IPs.
With the second Suggestion I fear that the PAC file will become too large. We have locations in almost 100 countries and quite a few proxy exceptions for various reasons.

But since there seems to be no possibility to make PAC files per Location or locationg Group I guess I will have to investigate the option of using the Country Variable more closely.

Instead of using the “country” variable, is there a way leverage States (CA, TX, etc) in a Zscaler Pac file?

Is there a way we can include CIDR block (x.x.x.x/y) in stead of a single host ip for the Zscaler "source-ip-variable?

Hi @buzzcock, PAC logic has JavaScript at it’s core, so you could use something like isinnet() to shexpmatch() to work through the conditions you’re thinking of.

I can’t show any examples right now, but this should get you on the path.

I have try the following and it’s NOT working.

        /* Push Hawaii Users To San Fran Zen Node */
			if (isInNet(myIpAddress(), "98.152.0.0", "255.252.0.0"))
            return "PROXY sjc4-2.sme.zscalerthree.net:80;DIRECT";

Is you client ip address really in that range or is that just your egress IP address?

@GordonWright that is our client’s egress public IP address ranges (CIDR block)

myipaddress only sees the IP address(es) assigned on the client machine.
So as long as this 98.152.x.y address does not show up with an ipconfig /all on the client you can not use it in the pac file

@Thomas Thank you sir. That make sense, but i’m still stuck of finding a solution to cover egress public CIDR subnet for the Source-IP-Variable.

You can check the SRCIP variable against your own (set of) CIDRs; basically you define your own kind of geolocation that way.
Like here (i split the IP into variables as that prevents the usage of isinnet; quicker, no dependency on DNS etc.)

function FindProxyForURL(url, host) {

// IP ZScaler sees pac request coming from
pubIP="${SRCIP}"; pfull=pubIP.split(".");
pA=parseInt(pfull[0]); pB=parseInt(pfull[1]); pC=parseInt(pfull[2]); pD=parseInt(pfull[3]);

// check exact pubIP
switch (pubIP) {
	case "1.2.3.4": do this; break;
	case "1.2.3.4": do that; break;
	default: do something;
	}
	
// check pubIP range
switch (pA) {
	case 11: if (pB==100) do this; break; //matches for 11.100.0.0/16
	case 22: if (pB==5 && (pC63 && pC<128)) do that; break; //matches for 22.5.64.0/18
	case 33: if (pB==3 || pB==8 && (pD<15)) do smth; break; //matches for 33.(3|8).any.0/28
	default: do whatever;
	}
}