Search code examples
pythondnsnetwork-programmingdnspythondnssec

DNSSEC using dnspython error: AttributeError: 'NS' object has no attribute 'is_absolute'


I have a DNS server for (com) zone. I use BIND 9.10.3 in Ubuntu. I want to use DNSSEC for DNS queries to this server. I have created ZSK and KSK and I have a signed zone file named forward.com.signed.

The forward.com.signed file content is the following: (NOTE: I cut the signature to one-line length to make the post short):

; File written on Thu May 24 02:13:50 2018
; dnssec_signzone version 9.10.3-P4-Ubuntu
com.            604800  IN SOA  dns1.com. admin.com. (
                    33         ; serial
                    604820     ; refresh (1 week 20 seconds)
                    86600      ; retry (1 day 3 minutes 20 seconds)
                    2419600    ; expire (4 weeks 6 minutes 40 seconds)
                    604600     ; minimum (6 days 23 hours 56 minutes 40 seconds)
                    )
            604800  RRSIG   SOA 7 1 604800 (
                    20180623001350 20180524001350 12410 com.
                    Qfd9i1AndX/dmyQuksOo2CRXH5RyM7i52c3P
                    )
            604800  NS  dns1.com.
            604800  RRSIG   NS 7 1 604800 (
                    20180623001350 20180524001350 12410 com.
                    Qj1DMmEhfkU5KI9MVrIlgKmQ5DxTjGuRNJ8i
                    )
            604800  DNSKEY  256 3 7 (
                    AwEAAfZWrsuiFoAAGcOTDWyVlDoZjQC8CZc6
                    ) ; ZSK; alg = NSEC3RSASHA1; key id = 12410
            604800  DNSKEY  257 3 7 (
                    AwEAAbc92MYUBPIs1L6lNAbubqRmZCfgv1h7
                    ) ; KSK; alg = NSEC3RSASHA1; key id = 62649
            604800  RRSIG   DNSKEY 7 1 604800 (
                    20180623001350 20180524001350 12410 com.
                    MuNVIE6oWV03+dXnXu+VufPQqfIgQvNIBODh
                    )
            604800  RRSIG   DNSKEY 7 1 604800 (
                    20180623001350 20180524001350 62649 com.
                    HxKx8nsyZ/qtrAvhsFJ9r7EBBwhSCGh0FJfM
                    )
            0   NSEC3PARAM 1 0 10 1C5A91FD094B6845
            0   RRSIG   NSEC3PARAM 7 1 0 (
                    20180623001350 20180524001350 12410 com.
                    qXpHn0q2GG/BK71mMYqCELsoHiFT6Oel82Jv
                    )
dns1.com.       604800  IN A    192.168.56.3
            604800  RRSIG   A 7 2 604800 (
                    20180623001350 20180524001350 12410 com.
                    aHB7ZCD8dDV4jMHJsUg23jjcm48tTnUvS8hy
                    wYPPhwqjjYr/holMmg== )
a.com.      604800  IN A    192.168.56.7
            604800  RRSIG   A 7 2 604800 (
                    20180623001350 20180524001350 12410 com.
                    0V7mUWUOuru41Rkp+RFp6eV13AHOdPnEanrV
                    )
            604800  TXT "some-random-text"
            604800  RRSIG   TXT 7 2 604800 (
                    20180623001350 20180524001350 12410 com.
                    Uta2/oGszVJAhm/DlGd7vnD+irg/GzyXlKHp
                    )
b.com.      604800  IN A    192.168.56.8
            604800  RRSIG   A 7 2 604800 (
                    20180623001350 20180524001350 12410 com.
                    2ui9x3SjrrEvFkcPbfcfC/NQW0MQOv2jy/Bd
                    )
            604800  TXT ""
            604800  RRSIG   TXT 7 2 604800 (
                    20180623001350 20180524001350 12410 com.
                    etX8lM00XXK9hUMM4FVsc51zuYOCz2+6qNLM
                    )
8NRLOA7UP8TGKLFJ7A6KPTIS503NJ4NB.com. 604600 IN NSEC3 1 1 10 1C5A91FD094B6845 (
                    QNU3FGJ5VOCSBIP3N93ITKLM4OP6GMCO
                    A TXT RRSIG )
            604600  RRSIG   NSEC3 7 2 604600 (
                    20180623001350 20180524001350 12410 com.
                    0qFfv4wr6WYSb4JlrtOlmPWykmCUKNdADlH8
                    )
QNU3FGJ5VOCSBIP3N93ITKLM4OP6GMCO.com. 604600 IN NSEC3 1 1 10 1C5A91FD094B6845 (
                    TVQJ9TFT4DPK7IGFE32TKLFG6EH2CUH5
                    A RRSIG )
            604600  RRSIG   NSEC3 7 2 604600 (
                    20180623001350 20180524001350 12410 com.
                    qZCi11tgJWJwjK2NI9KTVkcaJ0Eln0NVDsjM
                    )
TVQJ9TFT4DPK7IGFE32TKLFG6EH2CUH5.com. 604600 IN NSEC3 1 1 10 1C5A91FD094B6845 (
                    0J67JF0QNUUEKT5VF6FQPCRR9T8I8RT7
                    NS SOA RRSIG DNSKEY NSEC3PARAM )
            604600  RRSIG   NSEC3 7 2 604600 (
                    20180623001350 20180524001350 12410 com.
                    gud9iAHIRi4vR6eCgwOe6Xz0fR5F1qksJz6x
                    )
0J67JF0QNUUEKT5VF6FQPCRR9T8I8RT7.com. 604600 IN NSEC3 1 1 10 1C5A91FD094B6845 (
                    8NRLOA7UP8TGKLFJ7A6KPTIS503NJ4NB
                    A TXT RRSIG )
            604600  RRSIG   NSEC3 7 2 604600 (
                    20180623001350 20180524001350 12410 com.
                    8ZowNBjQXgaAx89kjTmgCu/9lYLk14L+xTWr
                    )

I use the following client python script using dnspython library:

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('com.',dns.rdatatype.NS)

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

print("DONE")

But I got this error:

Traceback (most recent call last):
  File "test-3-dnssec.py", line 13, in <module>
    response = dns.resolver.query(nsname,dns.rdatatype.A)
  File "C:\Python36\lib\site-packages\dns\resolver.py", line 1132, in query
    raise_on_no_answer, source_port)
  File "C:\Python36\lib\site-packages\dns\resolver.py", line 907, in query
    if qname.is_absolute():
AttributeError: 'NS' object has no attribute 'is_absolute'

The full code for the client is from this answer is here:

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] # 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

I could not identify what is the problem. Can you help me please?


Solution

  • The dns.resolver.query() API is query(qname, rdtype=1, rdclass=1, tcp=False, source=None, raise_on_no_answer=True, source_port=0) and qname must be ns.name.Name object or string, per http://www.dnspython.org/docs/1.15.0/dns.resolver-module.html#query

    You are feeding it with 2 parameters, and the first one, based on how it is created, has type dns.rdtypes.ANY.NS.NS so that does not match the API.

    If you do instead:

    response = dns.resolver.query(str(nsname), rdtype=dns.rdatatype.A)
    

    then it works (the rdtype= is not strictly necessary, but clearer).

    In [1]: response = dns.resolver.query('com.',dns.rdatatype.NS)
    
    In [2]: nsname = response.rrset[0]
    
    In [3]: response = dns.resolver.query(str(nsname), rdtype=dns.rdatatype.A)
    
    In [4]: print response
    <dns.resolver.Answer object at 0x103c22090>
    
    In [5]: print response.rrset[0].to_text()
    192.42.93.30