2010-11-01 56 views

回答

14

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

我碰到乔恩Colverson的答案来了,它帮助我了解dnspython模块以及如何处理的结果(我猜所有DNS模块具有相同的曲折迷宫式的结构...)我需要TTL和胶水记录,所以我创造了我自己的改编。我在这里发布它,以防有人觉得它有用;我不打算与乔·科尔森的出色答案竞争,只是填写一些额外的空白。基本的改进是使用来自答案附加部分的名称服务器信息(如果可用)。我认为服务器可以在附加部分添加粘合剂记录以外的东西,所以也许应该增强它以正确地将来自附加部分的信息与答案部分中的信息相关联。我还取出并打印所有的名称服务器,而不仅仅是第一个。

#!/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) 
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 
+1

我会是正确的思想,可能会返回缓存的结果有关系吗?在我的例子中,我特别想找到当前的服务器来避免任何缓存,但是可能比我做到这一点更简单。 :) – 2014-07-02 18:43:41

+2

这只会为您提供顶级域名的域名服务器(如果他们有NS记录的话,还会提供子域名)。它不会告诉你“www.example.org”的权威DNS服务器是什么,并且会引发一个'dns.resolver.NoAnswer'异常。 – pwaring 2016-06-10 15:29:03

0

Im相当肯定,这将做到这一点。

import dns.resolver 

domain = 'co.uk' 

response = dns.resolver.query(domain, 'SOA') 
if response.rrset is not None: 
    print response.rrset 

你当然可以清理的响应

import dns.resolver 
import re 

domain = 'co.uk' 

response = dns.resolver.query(domain, 'SOA') 

if response.rrset is not None: 
    pattern= r'(%s)\.\s(\d{1,})\s(\w+)\sSOA\s(.*?)\.\s(.*?)\.\s(\d{1,})\s(\d{1,})\s(\d{1,})\s(\d{1,})\s(\d{1,})' % domain 
    match = re.match(pattern, str(response.rrset)) 
    m_name, ttl, class_, ns, email, serial, refresh, retry, expiry, minim = match.groups() 

output =''' 
Main Name In Zone: {a}, 
Cache TTL: {b}, 
Class: {c}, 
Authoritive NS: {d}, 
Email Address: {e}, 
Last Change: {f}, 
Retry In Secs: {g}, 
Expiry: {h}, 
Slave Cache In Sec: {i} 
'''.format(a = m_name, b = ttl, c = class_, d = ns, e = str(email).replace('\\', ''), f = serial, g = retry, h = expiry, i = minim) 

print output 

这将产生

Main Name In Zone: co.uk, 
Cache TTL: 600, 
Class: IN, 
Authoritive NS: dns1.nic.uk, 
Email Address: hostmaster.nominet.org.uk, 
Last Change: 1305857394, 
Retry In Secs: 300, 
Expiry: 2419200, 
Slave Cache In Sec: 10800 
+1

纠正我,如果我错了,但我相信那些SOA结果仍然可以在解析器上缓存,但?它绕过缓存,使事情更加精细。 – 2017-08-25 23:40:17

相关问题