如何使用dnspython找到域的权威DNS服务器?

Jon*_*son 10 python dns dnspython

作为我正在编写的工具的一部分,我希望有一个诊断,告诉用户他们是否已为特定服务正确配置了他们的域的DNS.我想查询权威DNS服务器的域名,以便我可以绕过任何缓存的结果.

Jon*_*son 18

这是我对此的尝试.它使用系统的标准DNS服务器来查找顶级域的根服务器,并解析链中各种DNS服务器的名称,我认为这是合适的,因为这些名称可能很少发生变化.

import dns
import dns.name
import dns.query
import dns.resolver

def get_authoritative_nameserver(domain, log=lambda msg: None):
    n = dns.name.from_text(domain)

    depth = 2
    default = dns.resolver.get_default_resolver()
    nameserver = default.nameservers[0]

    last = False
    while not last:
        s = n.split(depth)

        last = s[0].to_unicode() == u'@'
        sub = s[1]

        log('Looking up %s on %s' % (sub, nameserver))
        query = dns.message.make_query(sub, dns.rdatatype.NS)
        response = dns.query.udp(query, nameserver)

        rcode = response.rcode()
        if rcode != dns.rcode.NOERROR:
            if rcode == dns.rcode.NXDOMAIN:
                raise Exception('%s does not exist.' % sub)
            else:
                raise Exception('Error %s' % dns.rcode.to_text(rcode))

        rrset = None
        if len(response.authority) > 0:
            rrset = response.authority[0]
        else:
            rrset = response.answer[0]

        rr = rrset[0]
        if rr.rdtype == dns.rdatatype.SOA:
            log('Same server is authoritative for %s' % sub)
        else:
            authority = rr.target
            log('%s is authoritative for %s' % (authority, sub))
            nameserver = default.query(authority).rrset[0].to_text()

        depth += 1

    return nameserver


import sys

def log(msg):
    print msg

print get_authoritative_nameserver(sys.argv[1], log)
Run Code Online (Sandbox Code Playgroud)

这是一些示例输出:

Looking up com. on 192.168.255.10
l.gtld-servers.net. is authoritative for com.
Looking up stackoverflow.com. on 192.41.162.30
ns1.p19.dynect.net. is authoritative for stackoverflow.com.
Looking up meta.stackoverflow.com. on 208.78.70.19
Same server is authoritative for meta.stackoverflow.com.
208.78.70.19
Run Code Online (Sandbox Code Playgroud)


tri*_*eee 7

我遇到了Jon Colverson的回答,它帮助我理解了dnspython模块以及如何处理结果(我猜所有的DNS模块都有类似结构的错误迷宫......)我需要TTL和胶水记录,所以我创造了我自己的改编.我在这里发帖,以防有人发现它有用; 我不打算与Jon Colverson的优秀答案竞争,只是填补一些额外的空白.基本改进是使用答案的附加部分中的名称服务器信息(如果可用).我认为服务器可以在附加部分中添加除粘合记录之外的其他内容,因此可能仍应增强此功能以将附加部分中的信息与答案部分中的信息正确关联.我还获取并打印所有名称服务器,而不仅仅是第一个.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import dns.query
import dns.resolver
from dns.exception import DNSException

def query_authoritative_ns (domain, log=lambda msg: None):

    default = dns.resolver.get_default_resolver()
    ns = default.nameservers[0]

    n = domain.split('.')

    for i in xrange(len(n), 0, -1):
        sub = '.'.join(n[i-1:])

        log('Looking up %s on %s' % (sub, ns))
        query = dns.message.make_query(sub, dns.rdatatype.NS)
        response = dns.query.udp(query, ns)

        rcode = response.rcode()
        if rcode != dns.rcode.NOERROR:
            if rcode == dns.rcode.NXDOMAIN:
                raise Exception('%s does not exist.' % (sub))
            else:
                raise Exception('Error %s' % (dns.rcode.to_text(rcode)))

        if len(response.authority) > 0:
            rrsets = response.authority
        elif len(response.additional) > 0:
            rrsets = [response.additional]
        else:
            rrsets = response.answer

        # Handle all RRsets, not just the first one
        for rrset in rrsets:
            for rr in rrset:
                if rr.rdtype == dns.rdatatype.SOA:
                    log('Same server is authoritative for %s' % (sub))
                elif rr.rdtype == dns.rdatatype.A:
                    ns = rr.items[0].address
                    log('Glue record for %s: %s' % (rr.name, ns))
                elif rr.rdtype == dns.rdatatype.NS:
                    authority = rr.target
                    ns = default.query(authority).rrset[0].to_text()
                    log('%s [%s] is authoritative for %s; ttl %i' % 
                        (authority, ns, sub, rrset.ttl))
                    result = rrset
                else:
                    # IPv6 glue records etc
                    #log('Ignoring %s' % (rr))
                    pass

    return result

import sys

def log (msg):
    sys.stderr.write(msg + u'\n')

for s in sys.argv[1:]:
    print query_authoritative_ns (s, log)
Run Code Online (Sandbox Code Playgroud)