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

13 投票
5 回答
24401 浏览
提问于 2025-04-16 06:22

我正在写一个工具,想要添加一个诊断功能,帮助用户检查他们的域名的DNS设置是否正确,特别是针对某项服务。我想直接向他们域名的权威DNS服务器询问信息,这样可以避免使用缓存的结果。

5 个回答

2

其他的例子都没问题,但如果你只是想要域名服务器的名字,那些例子就显得太复杂了。下面是一个来自 http://c0deman.wordpress.com/2014/06/17/find-nameservers-of-domain-name-python/ 的简单例子:

import dns.resolver

domain = 'google.com'
answers = dns.resolver.query(domain,'NS')
for server in answers:
    print server
8

我看到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)
19

这是我对此的尝试。它使用系统的标准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)

下面是一些示例输出:

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

撰写回答