vADC Docs

glbcso.rts: Making use of the Client Subnet Option in GLB Decisions

by markbod on ‎11-03-2014 06:29 AM - edited on ‎06-01-2015 09:06 AM by PaulWallace (567 Views)

The SteelApp GLB (Global Load Balancer) performs global load balancing by manipulating DNS responses to clients. The load balancing algorithms available include round-robin, weighted, active/passive and load based. SteelApp also supports making the decision based on geographic proximity.

 

An extension to DNS known as the Client Subnet Option (CSO) has been drafted by the IETF. The draft: draft-vandergaast-edns-client-subnet-02 is now at version 2.0 and is currently being used by Google and some other large DNS providers. The Client Subnet Option adds an additional DNS Extension record (EDNS0) into requests which are sent to authoritative name servers. This additional record allows recursive DNS servers to add in the originating client IP subnet into the request. The authoritative name server may then provide an optimized response.

 

The SteelApp GLB does not natively understand  EDNS0 records at present, but we can detect the presence of the CSO extension using a simple TrafficScript. The script can then modify the request in such a way that the GLB will use the CSO in its decision making process.

 

Here's the TrafficScript:

 

#=-To log resolver, use macro: %t %v %h %A:%p %n %B %b %T %{resolver}d  
# Set verbose to 1 to enable logging to event log, 0 to disable.  
$verbose = 0;  
  
# EDNS0 OPT Code 0x0 0x08, Len 0x0 0x07, IPv4 family 0x01, length 24bits 0x18, mask 0x0  
$csoBytes = string.hexdecode("0008000700011800");  
$resolver = "-";  
$data = request.get( request.getLength() );  
$end = string.skip( $data, string.length($data) - 11 );  
if ( string.startswith($end, $csoBytes ) ) {  
   $cs = string.skip($end,8);  
   $client = string.bytesToInt(string.substring($cs,0,0)) . "." .  
             string.bytesToInt(string.substring($cs,1,1)) . "." .  
             string.bytesToInt(string.substring($cs,2,2)) . ".";  
   $resolver = request.getRemoteIP();  
   $resolverOctets = string.split($resolver, ".");  
   if ( $verbose )  
      log.info("DNS Request with CSO. Resolver: " . $resolver . ", Using Address: [" . $client . "]" . $resolverOctets[0]);  
   request.setRemoteIP( $client . $resolverOctets[0]);  
   connection.data.set("resolver", $resolver);  
}  

 

The script looks for the CSO data at the end of the incoming DNS request. If a record is found, then we use the address specified as the client IP when making our GLB decision. However the CSO only includes the first three octets of the clients address. The idea is for the resolver to give the name server enough information about the client to determine its region, without divulging the full IPv4 address. Unfortunately we need a full IP address for GLB, so the script uses the first octet of the resolvers IP as the last octet of the clients IP. Why not? If you prefer you could just hard code the last octet. An exercise for the reader.

 

The rule stores the resolver address in connection memory so that you can log both the resolver and the address from the CSO by using the following request log log!format macro:

 

%t %v %h %A:%p %n %B %b %T %{resolver}d

 

Optionally, enabling $verbose will cause the script to write an event to the standard event log whenever it receives a request containing CSO information.

 

This rule needs to be applied to your GLB DNS service as a request rule.

 

Enjoy!

Contributors