Some examples of dnsruby in action
In this post, I’d like to look at how to use dnsruby to accomplish some common tasks.
Getting started
To follow these examples, you’ll need to install dnsruby :
$ gem install dnsruby
I’ll run these examples in Ruby’s interactive shell :
$ irb
First, I need to include Dnsruby :
>> require 'rubygems' >> require 'dnsruby' >> include Dnsruby
Now I’ll load the system’s default resolvers :
>> res = Resolver.new
And display them :
>> res.single_resolvers.each {|s| print "Server address : #{s.server}n"}
Server address : 192.168.1.1
Server address : 192.168.2.2
Now I’ll use them to run a couple of queries :
>> ret = res.query("example.com") # Defaults to A record
>> print ret.answer
example.com. 172789 IN A 208.77.188.166=> nil
>> res.query("example.com", "MX") # Query the MX record
This time, I’ll use some defined nameservers :
>> res = Resolver.new({:nameserver => ["ns1.nic.uk",
"ns1.nic.uk"]})
Asynchronous Queries
To run an asynchronous query, I’ll define a Queue to hold the results, and then prepare the query. This time, I’ll construct a Message to hold the query data, and set the RD (recursion desired) bit on the header to 0 :
>> queue = Queue.new
>> m = Message.new("co.uk", Types.NS)
>> m.header.rd = false
>> message_id = res.send_async(m, queue, 1)
Now my code can get on with other tasks, until I’m ready to get the response. Queue#pop is a blocking call, but you can check if it is empty using Queue#empty?.
>> id, reply, error = queue.pop # id == message_id
The [id, reply, error] tuple is popped off the queue. The id identifies which query the response is for (it should match the id returned by the send_async call), reply holds the best response that was received, and any errors will be held in error (which should be nil in this example).
Message Options
Now I’ll ask for a Message to be sent without checking (or the response being stored in) the cache. I’ll also make sure that no DNSSEC validation is performed on the response :
>> m.do_caching = false >> m.do_validation = false >> res.send_message(m)
I can ask for a Message to be sent without any pre- or post-processing. No EDNS headers are applied, the header flags are not adjusted, and no caching or validation is performed. This method is most useful for tools authors :
>> res.send_plain_message(Message.new("nic.uk"))
TSIG and Dynamic Updates
I can also use TSIG signatures to communicate securely with a resolver. In this example, I’ll use TSIG to sign a dynamic update. First, I’ll have to define the server to use, and the TSIG key to speak to it with :
>> res = Dnsruby::Resolver.new("ns0.validation-test-servers.nominet.org.uk")
>> res.dnssec = false
>> tsig = Dnsruby::RR.create({
:name => "rubytsig",
:type => "TSIG",
:key => "8n6gugn4aJ7MazyNlMccGKH1WxD2B3UvN/O/RA6iBupO2/03u9CTa3Ewz3gBWTSBCH3crY4Kk+tigNdeJBAvrw==",
})
Now I’ll create the dynamic update packet :
>> update = Dnsruby::Update.new("validation-test-servers.nominet.org.uk")
>> # ... add stuff to the update
>> update.absent("notthere.update.validation-test-servers.nominet.org.uk", 'TXT')
And apply the TSIG signature and send the message :
>> tsig.apply(update)
>> response = res.send_message(update)
>> print "TSIG response was verified? : #{response.verified?}n"
I could also have configured the Resolver to sign *all* packets with TSIG :
>> res.tsig=tsig.name, tsig.key
Recursive Queries
In addition to defining nameservers to do recursive queries on my behalf, I can also get Dnsruby to query recursively from the root. A static cache is built up, so the more client queries that are run, the less packets need be sent per client query.
>> rec = Recursor.new
>> ret = rec.query("uk-dnssec.nic.uk", "NS")
In my next article, I’ll look at how use Dnsruby with DNSSEC.

May 21st, 2009 at 11:33 am
[…] this post, I’d like to look at how to use Dnsruby with DNSSEC. As before, I’ll run these examples in irb, and assume that you’ve included Dnsruby […]