Novell Home

Proxy Failover (Without Clustering)

Novell Cool Solutions: Feature
By Shaun Pond

Digg This - Slashdot This

Posted: 15 Jul 2003
 

If you are using BorderManager mostly for controlling outbound web access, and you want to ensure maximum availability, you can cluster the proxy service (see TID 10070800). However, there is a simple way to do failover and load-sharing of the http proxy between two or more BorderManager servers that does not involve clustering. Automatic configuration of browsers by means of an automatic configuration file, commonly called a "proxy.pac" file has been available for some time, and this little piece of javascript can be used in many useful ways.

The purpose of a proxy.pac is to allow you to apply your own logic to a browser, to determine if it should attempt to talk directly to a web site, or to go through a proxy. It is much more flexible than the standard methods available in browsers, for example Internet Explorer's "Do not use proxy for addresses beginning with:" option. Whatever logic you use in a proxy.pac, the end result returns a string, containing a semicolon delimited list of destinations for the browser, for example "PROXY 10.10.1.1:8080; DIRECT" - this tells the browser to try to contact the proxy on address 10.10.1.1, port 8080, and if it cannot, try to talk directly to the web server. The only commands it understands are PROXY, DIRECT and SOCKS (the latter for SOCKS gateways). The file is read by the browser on startup.

This article shows a proxy.pac that uses one possible method to do load sharing, offers an explanation of the logic within, and discusses some methods that you could use to distribute the file.

Proxy.Pac

Sample proxy.pac
function FindProxyForURL(url,host)
{
// set bm1 and bm2 to the 2 proxies
var bm1="10.90.193.213"
var bm2="10.90.193.211"
//find the 4th octet - if even, is bm1/bm2 else bm2/bm1
var myip=myIpAddress()
var ipbits=myip.split(".")
var myseg=parseInt(ipbits[3])
if(myseg==Math.floor(myseg/2)*2) {
   var proxone=bm1
   var proxtwo=bm2
}
else {
   var proxone=bm2
   var proxtwo=bm1
  }

//if name has no dots, or is our domain, or starts 10., or if my
//current address does not start 10. don't use proxy
 if(isPlainHostName(host)  ||
	dnsDomainIs(host,".mydomain.co.uk") ||
	myip.substring(0,3)!=="10." || 
	host.substring(0,3)=="10." )

//
{
// alert("direct")	
return "DIRECT";
}
	else {
//  alert("proxy")
	return "PROXY "+proxone+":8080; PROXY "+proxtwo+":8080" ;
}
}

Dissecting the Routine

Simple, eh?

OK, let's dissect the routine: note that I am assuming that for the purposes of this article, our company uses the class A "10" for all internal IP addresses, and that our internal DNS domain is "mydomain.co.uk".

function FindProxyForURL(url,host)
{

This marks the start of the function - it is always called FindProxyForURL, and the browser passes the full URL (e.g. http://www.novell.com/products/bordermanager/index.html ) and the host name (e.g. www.novell.com ). The final closing "}" at the end of the script denotes the end of the function.


// set bm1 and bm2 to the 2 proxies
var bm1="10.90.193.213"
var bm2="10.90.193.211"

The first line is a comment, and the next two set the values of the two variables we're going to use - putting them here at the start of the routine makes it easier to find them if we want to change them. (A little tip, if you want to take down one of the proxies, change these variables so that they both refer to the same server, once everyone has reloaded their browser, they will only talk to one proxy - you can easily take down the second without any effect whatsoever.)


//find the 4th octet - if even, is bm1/bm2 else bm2/bm1
var myip=myIpAddress()
var ipbits=myip.split(".")
var myseg=parseInt(ipbits[3])
if(myseg==Math.floor(myseg/2)*2) {
   var proxone=bm1
   var proxtwo=bm2
}
else {
   var proxone=bm2
   var proxtwo=bm1
  }

What's happening here is that we're storing the IP address of your workstation into a variable ("myip"), then automatically dividing it into the four octets (splitting at the ".") and storing each octet into an element of an array ("ipbits"). Then we extract the last octet, and call it "myseg". We divide the number by 2, discarding any remainder. We then multiply the result by 2. If the result is the same as the original number, it was even. If not, it was odd. We then populate the variables "proxone" and "proxtwo" accordingly.


//if name has no dots, or is our domain, or starts 10., or if my
//current address does not start 10. don't use proxy
 if(isPlainHostName(host)  ||
	dnsDomainIs(host,".mydomain.co.uk") ||
	myip.substring(0,3)!=="10." || 
	host.substring(0,3)=="10." )

At this point, we apply our logic to decide if we should try to talk to our proxy or not. if(isPlainHostName(host) means "if the name typed in does not contain any dots", i.e. if the user has just typed in a single word, we're assuming that they are referring to a web server inside our DNS domain, and is expecting DNS resolution to supply the rest of the address (for example, if I am using a workstation at my company, where the DNS domain is mydomain.co.uk, and I do "Ping www" at a command prompt, it will go and ping www.mydomain.co.uk, this line performs a similar function for web browsing).

Note - the two vertical bars (||) represent "OR".

  • dnsDomainIs(host,".mydomain.co.uk")
    means "if the domain of the specified host matches .mydomain.co.uk", so if we're trying to talk to a web server within the firewall, don't contact the proxy.
  • myip.substring(0,3)!=="10." ||
    means "if my current IP address does not begin 10.", i.e. if I'm not within our firewall, go directly to the web server.
  • host.substring(0,3)=="10." )
    means "if the IP address you're trying to reach begins 10.", i.e. if you've typed in the IP address of the web server instead of the DNS name, and it's inside the firewall, go directly.

Nearly there?


{
// alert("direct")	
return "DIRECT";
}
	else {
//  alert("proxy")
	return "PROXY "+proxone+":8080; PROXY "+proxtwo+":8080" ;
}

The "alert" lines are commented out, but you can uncomment them for troubleshooting. The other lines mean "if the following test result in a TRUE value, return the value "DIRECT" to make the browser bypass the proxy, otherwise return a string containing the two proxies in the order we specified earlier".


The upshot of all this is that workstations on even IP addresses try to use the first named BM server (BM1), and failover to the second (BM2), and workstations with odd IP addresses try to use the second named BM server (BM2), and failover to the first (BM1).

IMPORTANT NOTE: the failover requires that the IP address is not contactable - if BorderManager Abends, for example, but the server is still functioning, failover will not occur. For this eventuality, I would suggest that you change the value of the set parameter SET AUTO RESTART AFTER ABEND to 2, or even better, to zero. Thus, if you have an Abend on one server, it will stop completely, and the failover process can more easily work.

Distribution methods

There are several methods of delivering the proxy.pac, usually by http or by a local file. For the local file process, Netscape and Internet Explorer use different formats:

  • Netscape:
    file:///C|/proxy.pac
  • Internet Explorer:
    file://c:/proxy.pac

For delivery by http, put the file on a web server, and if you're using Internet Explorer, you can deliver the address of a web server to the client by DNS or DHCP if you wish - check the Microsoft site for WPAD (Web Proxy Auto-Discovery). Alternatively, you can set the address in the registry (IE) or in PREFS.JS (Netscape). Later versions of Opera and Mozilla also support the use of proxy.pac.


Novell Cool Solutions (corporate web communities) are produced by WebWise Solutions. www.webwiseone.com

© 2014 Novell