vADC Docs

libDNS.rts: Interrogating and managing DNS traffic in Stingray

by on ‎04-10-2013 07:35 AM - edited on ‎05-13-2016 05:37 AM by PaulWallace (3,422 Views)

 UPDATE January 2015: libDNS version 2.1 released!

The new release is backward-compatible with previous releases and includes the following bug fixes:

  • Fixed multiple bugs in parsing of DNS records

 

The libDNS.rts library (written by Matthew Geldert and enhanced by Matthias Scheler) attached below provides a means to interrogate and modify DNS traffic from a TrafficScript rule, and to respond directly to DNS request when desired.

 

You can use it to:

 

 

Note: This library allows you to inspect and modify DNS traffic as it is balanced by Stingray.  If you want to issue DNS requests from Stingray, check out the net.dns.resolveHost() and net.dns.resolveIP() TrafficScript functions for this purpose.

 

Overview

 

This rule can be used when Stingray receives DNS lookups (UDP or TCP) using a Virtual Server, and optionally uses a pool to forward these requests to a real DNS server:

 

dns1.png

Typically, a listen IP addresses of the Stingray will be published as the NS record for a subdomain so that clients explicitly direct DNS lookups to the Stingray device, although you can use Stingray software in a transparent mode and intercept DNS lookups that are routed through Stingray using the iptables configuration described in Transparent Load Balancing with Stingray Traffic Manager.

 

Installation

 

 

Step 1:

 

Configure Stingray with a virtual server listening on port 53; you can use the 'discard' pool to get started:

 

dns2.png

If you use 'dig' to send a DNS request to that virtual server (listening on 192.168.35.10 in this case), you won't get a response because the virtual server will discard all requests:

 

$ dig @192.168.35.10 www.zeus.com

; <<>> DiG 9.8.3-P1 <<>> @192.168.35.10 www.zeus.com

; (1 server found)

;; global options: +cmd

;; connection timed out; no servers could be reached

 

Step 2:

 

Create a new rule named libDNS.rts using the attached TrafficScript Source:

 

DNS3.pngThis rule is used as a library, so you don't need to associate it with a Virtual Server.

 

Then associate the following request rule with your virtual server:

 

import libDNS.rts as dns;

$request = request.get();

$packet = dns.convertRawDataToObject($request, "udp");


# Ignore unparsable packets and query responses to avoid

# attacks like the one described in CVE-2004-0789.

if( hash.count( $packet ) == 0 || $packet["qr"] == "1" ) {

   break;

}

log.info( "DNS request: " . lang.dump( $packet ) );


$host = dns.getQuestion( $packet )["host"];


$packet = dns.addResponse($packet, "answer", $host, "www.site.com.", "CNAME", "IN", "60", []);

$packet["qr"] = 1;


log.info( "DNS response: " . lang.dump( $packet ) );

request.sendResponse( dns.convertObjectToRawData($packet, "udp"));

 

This request rule will catch all DNS requests and respond directly with a CNAME directing the client to look up 'www.site.com' instead:

 

$ dig @192.168.35.10 www.zeus.com

; <<>> DiG 9.8.3-P1 <<>> @192.168.35.10 www.zeus.com

; (1 server found)

;; global options: +cmd

;; Got answer:

;; ->>HEADER<

 

 

Documentation

 

This DNS library provides a set of helper functions to query and modify DNS packets.  Internally, a decoded DNS packet is represented as a TrafficScript datastructure and when you are writing and debugging rules, it may be useful to use log.info( lang.dump( $packet ) ) as in the rule above to help understand the internal structures.

 

Create a new DNS packet

 

$packet = dns.newDnsObject();

log.info( lang.dump( $packet ) );

 

Creates a data structure model of a DNS request/response packet. The default flags are set for an A record lookup. Returns the internal hash data structure used for the DNS packet.

 

Set the question in a DNS packet

 

$packet = dns.setQuestion( $packet, $host, $type, $class );

 

Sets the question in a data structure representation of a DNS packet.

 

  • $packet - the packet data structure to manipulate.
  • $host - the host to lookup.
  • $type - the type of RR to request.

 

Returns the modified packet data structure, or -1 if the type is unknown.

 

 

Get the question in the DNS packet

 

$q = dns.getQuestion( $packet );

$host = $q["host"];

$type = $q["type"];

$class = $q["class"];

 

Gets the question from a data structure representing a DNS request/response.  Returns a hash of the host and type in the data structure's question section.

 

Add an answer to the DNS packet

 

$packet = dns.addResponse($packet, $section, $name, $host, $type, $class, $ttl, $additional);

 

Adds an answer to the specified RR section:

 

  • $packet - the packet data structure to manipulate.
  • $section - name of the section ("answer", "authority" or "additional") to add the answer to
  • $name, $host, $type, $class, $ttl, $additional - the answer data

 

Returns the modified packet data structure.

 

Remove an answer from the DNS packet

 

$packet = dns.removeResponse( $packet, $section, $answer ); while( $packet["additionalcount"] > 0 ) { $packet = dns.removeResponse( $packet, "additional", 0); }

 

Removes an answer from the specified RR section.

 

  • $packet - the packet data structure to manipulate.
  • $section - name of the section ("answer", "authority" or "additional") to remove the entry from
  • $answer - the array position of the answer to remove (0 removes the first).

 

Returns the modified packet data structure, or -1 if the specified array key is out of range.

 

Convert the datastructure packet object to a raw packet

 

$data = dns.convertObjectToRawData( $packet, $protocol ); request.sendResponse( $data );

 

Converts a data structure into the raw data suitable to send in a DNS request or response.

 

  • $packet - data structure to convert.
  • $protocol - transport protocol of data ("udp" or "tcp").

 

Returns the raw packet data.

 

 

Convert a raw packet to  an internal datastructure object

 

$data = request.get(); $packet = dns.convertRawDatatoObject( $data, $protocol );

 

Converts a raw DNS request/response to a manipulatable data structure.

 

  • $data - raw DNS packet
  • $protocol - transport protocol of data ("udp" or "tcp")

 

Returns trafficscript data structure (hash).

 

 

Kudos

 

Kudos to Matthew Geldert, original author of this library, and Matthias Scheler, author of version 2.0.

Comments
by
on ‎04-15-2013 10:29 PM

The library has been updated to v1.2, adding a fix to handle DNS requests that contain Answer, Authority or Additional sections.  These are generated by some Exchange servers, and by versions of dig >= 9.9.1.

Contributors