10

As the title says I want to programmatically check if a DNS response for a domain are protected with DNSSEC.
How could I do this?

It would be great, if there is a pythonic solution for this.

UPDATE: changed request to response, sorry for the confusion

Thorben
  • 953
  • 13
  • 28

2 Answers2

20

Using a DNS resolver (e.g. dnspython), you can query the domain for its DNSKEY RRset and turn on the DO (dnssec OK) query flag. If the query succeeds, the answer will have the AD (authenticated data) flag set and will contain the RRSIG signatures for the zone (if it is signed).

Update: a basic example using dnspython

import dns.name
import dns.query
import dns.dnssec
import dns.message
import dns.resolver
import dns.rdatatype

# get nameservers for target domain
response = dns.resolver.query('example.com.',dns.rdatatype.NS)

# we'll use the first nameserver in this example
nsname = response.rrset[0].to_text() # name
response = dns.resolver.query(nsname,dns.rdatatype.A)
nsaddr = response.rrset[0].to_text() # IPv4

# get DNSKEY for zone
request = dns.message.make_query('example.com.',
                                 dns.rdatatype.DNSKEY,
                                 want_dnssec=True)

# send the query
response = dns.query.udp(request,nsaddr)
if response.rcode() != 0:
    # HANDLE QUERY FAILED (SERVER ERROR OR NO DNSKEY RECORD)

# answer should contain two RRSET: DNSKEY and RRSIG(DNSKEY)
answer = response.answer
if len(answer) != 2:
    # SOMETHING WENT WRONG

# the DNSKEY should be self signed, validate it
name = dns.name.from_text('example.com.')
try:
    dns.dnssec.validate(answer[0],answer[1],{name:answer[0]})
except dns.dnssec.ValidationFailure:
    # BE SUSPICIOUS
else:
    # WE'RE GOOD, THERE'S A VALID DNSSEC SELF-SIGNED KEY FOR example.com
turtlemonvh
  • 9,149
  • 6
  • 47
  • 53
isedev
  • 18,848
  • 3
  • 60
  • 59
  • I also already stumbled upon dnspython, but I did not find a way to get the data I need from it and the documentation is really bad. Do you know how to code this? – Thorben Oct 01 '14 at 11:24
  • @Thorben Added a basic example to the answer. – isedev Oct 01 '14 at 13:12
  • Thank you. The code looks nice. Unfortunately I get a strange error `TypeError: coercing to Unicode: need string or buffer, NS found` at `response = dns.query.udp(request, ns)`, but I trust you that it is working in general. However, I already ended up parsing the output of `dig +dnssec domain`. – Thorben Oct 01 '14 at 13:22
  • 2
    Could you extend the code to validate the trust chain please? – Tom Maier Jan 01 '15 at 19:36
  • @tmaier Unfortunately, I am not sure how to achieve that using dnspython – isedev Jan 03 '15 at 20:00
  • @isedev Do you reckon there is no support for this build into dnspython, but that it could be done by implementing recursion yourself and use dnspython for validating signatures at each level of the hierarchy? – kasperd Feb 04 '15 at 16:47
  • @tmaier It looks like the unbound library can do so: http://www.unbound.net/documentation/pyunbound/examples/example4.html – kasperd Feb 04 '15 at 17:43
  • According to: https://github.com/rthalley/dnspython/blob/4f26a2c7af86474a3800c616aa26f2f419dd28c5/dns/dnssec.py#L426 {name:answer[0]} does not work, because answer[0] is not a type of ``dns.node.Node`` or ``dns.rdataset.Rdataset``. How can you fix it? – weefwefwqg3 Feb 10 '17 at 20:15
2

To see if a particular request is protected, look at the DO flag in the request packet. Whatever language and library you use to interface to DNS should have an accessor for it (it may be called something else, like "dnssec").

The first answer is correct but incomplete if you want to know if a certain zone is protected. The described procedure will tell you if the zone's own data is signed. In order to check that the delegation to the zone is protected, you need to ask the parent zone's name servers for a (correctly signed) DS record for the zone you're interested in.

Calle Dybedahl
  • 5,228
  • 2
  • 18
  • 22
  • I've got exactly this problem but I don't have any idea how to extend the code to validate the trust chain with dnspython. Do you know a simple example? – Tom Maier Jan 01 '15 at 19:34
  • 2
    Unfortunately not. There is code that performs this check (and many others) in our recently released tool Zonemaster, but that's written in Perl. If you'd like to look at it, it's on Github at https://github.com/dotse/zonemaster-engine and the most relevant function is `dnssec11` in the file lib/Zonemaster/Test/DNSSEC.pm – Calle Dybedahl Jan 02 '15 at 22:34
  • so, how you do check if a particular "response" is protected? Do we also look at the existence of "DO flag" in the response packet? – weefwefwqg3 Feb 10 '17 at 18:31