2010-11-01 58 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

相關問題