Friday, April 25, 2014

Getdns - easy access to advanced DNS features

For quite some time now IETF participants have been slaving over hot keyboards, specifying important DNS features, such as DNSSEC, which aren't seeing the hoped-for uptake.  Part of the problem has been out-of-date or difficult-to-use APIs ("The IETF doesn't do APIs").  So, several years ago Paul Hoffman started working with several application developers to come up with a modern, flexible C API that might help jumpstart DNS-related application development, and ended up publishing getdns.  Allison Mankin, Director of Verisign Labs, put together and funded an open source implementation project, bringing in NLNet Labs, and me.

The C getdns library was published in February of this year, and over the past few months we've been working on getdns bindings for Node.js and Python.  Those bindings were used in a Verisign challenge in the hack battle at The Next Web Europe conference earlier this week, and it seemed to go pretty well.

As a quick introduction, here's what's involved with doing a basic IP address lookup from Python:

import getdns
c = getdns.context_create()
ext = { "return_both_v4_and_v6" :  getdns.GETDNS_EXTENSION_TRUE }
ret  = getdns.address(c, "www.google.com", getdns.GETDNS_RRTYPE_A, ext)

Simply import the module, create a getdns context (an opaque data structure describing the environment within which the resolution will take place, such as root servers, timeouts, whether the resolution should be done recursively or as a stub resolver, etc).  We've added an extension saying that we'd like both IPv4 and IPv6 addresses returned (this is the default with getdns.address() but would need to be set for other query types).  The call returns a somewhat complex dictionary containing everything returned in the query, plus some additional information to make the developer's life a little easier, and I plan to walk through this dictionary in later posts.

But just doing an address resolution isn't that interesting.  Here's an example of checking the DNSSEC status of a given domain name:


#!/usr/bin/python

import getdns, pprint, sys

dnssec_status = {
    "GETDNS_DNSSEC_SECURE" : 400,
    "GETDNS_DNSSEC_BOGUS" : 401,
    "GETDNS_DNSSEC_INDETERINATE" : 402,
    "GETDNS_DNSSEC_INSECURE" : 403,
    "GETDNS_DNSSEC_NOT_PERFORMED" : 404
}


def dnssec_message(value):
    for message in dnssec_status.keys():
        if dnssec_status[message] == value:
            return message

def main():
    if len(sys.argv) != 2:
        print "Usage: {0} hostname".format(sys.argv[0])
        sys.exit(1)

    ctx = getdns.context_create()
    extensions = { "return_both_v4_and_v6" : getdns.GETDNS_EXTENSION_TRUE,
                   "dnssec_return_status" : getdns.GETDNS_EXTENSION_TRUE }
    results = getdns.address(ctx, name=sys.argv[1], extensions=extensions)
    if results["status"] == getdns.GETDNS_RESPSTATUS_GOOD:
        sys.stdout.write("Addresses: ")
        for addr in results["just_address_answers"]:
            print " {0}".format(addr["IPSTRING"])
        sys.stdout.write("\n")

        for result in results["replies_tree"]:
            if "dnssec_status" in result.keys():
                print "{0}: dnssec_status: {1}".format(result["canonical_name"],
                                                       dnssec_message(result["dnssec_status"]))

    if results["status"] == getdns.GETDNS_RESPSTATUS_NO_NAME:
        print "{0} not found".format(sys.argv[1])


if __name__ == "__main__":
    main()

This is a lot more interesting.  The real work takes place in just a few lines.  We add an extension asking for the DNSSEC status to be returned, do the lookup just as we did in the previous example, and then check for the presence of the "dnssec_status" key in the results.  This makes it trivial to check to see whether or not a given DNS record is DNSSEC-protected.

One of the hack battle teams used the equivalent functionality in the Node.js bindings to implement a web interface to a DNSSEC status checker and called it "DNSSEC Name and Shame!"



We're hopeful that making it easy for application developers to check DNSSEC status might help provide some incentive for folks running DNS servers to get their their records signed.

My next post will look at using getdns to implement DANE functionality.  But if you'd like a teaser, check out example code, here.

No comments:

Post a Comment