pythondnsdnspython

Python: Get the RA flag from DNS


I'm trying to specifically get the Recursion Available (RA) flag from the DNS. According to the RFC 1035, if there's no recursion it should return zero, otherwise non-zero. If a DNS response is blocked by Quad9 DNS service it returns an "NXDOMAIN" with a "RA:0"

However, using DNSPython is always returns non-zero (128). Can this hardcoded in the library?

import dns
import dns.resolver

# Allowed Domain
# should return an IP address with "RA" non-zero
domain = "google.com"

# Blocked domain 
# Should return NXDOMAIN with "RA" to 0
#domain = "takelady.net" ---> UNCOMMENT

# Set Resolver to Quad9 (quad9.net)
my_resolver = dns.resolver.Resolver()
my_resolver.nameservers = ['9.9.9.9']

try:
    dns_response = dns.resolver.query(domain, "A")

    for resp in dns_response:
        print("[+]", resp.to_text())

    print("RA flag:", dns.flags.RA)
    
except dns.resolver.NXDOMAIN:
    print("[+] NXDOMAIN")
    print("RA flag:", dns.flags.RA)
    pass

except dns.resolver.NoAnswer:
    print("[+] NoAnswer")
    pass

except dns.resolver.Timeout:
    print("[+] Timeout")
    pass

Allowed Response:

[+] 172.217.214.100
[+] 172.217.214.101
[+] 172.217.214.138
[+] 172.217.214.139
[+] 172.217.214.113
[+] 172.217.214.102
RA flag: 128

Blocked Response:

[+] NXDOMAIN
RA flag: 128

Solution

  • You do not use the resolver object you have created, so queries go to the system resolver. You should use this instead:

    dns_response = my_resolver.query(domain, "A")
    

    query() performs search list processing, so you should clear the search list first, like this:

        my_resolver = dns.resolver.Resolver()
        my_resolver.nameservers = ['9.9.9.9']
        my_resolver.search = []
    

    Finally, the NXDOMAIN response results in an exception, and you need to read the flags from the response object in the exception, like this:

    except dns.resolver.NXDOMAIN as e:
        print("[+] NXDOMAIN")
        for (name, resp) in e.responses().items():
            print(name, "RA flag:", resp.flags & dns.flags.RA)