作为我正在编写的工具的一部分,我希望有一个诊断,告诉用户他们是否已为特定服务正确配置了他们的域的DNS.我想查询权威DNS服务器的域名,以便我可以绕过任何缓存的结果.
这是我对此的尝试.它使用系统的标准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
我遇到了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)