2010-11-01 14 views

Répondre

14

Voici ma tentative à ce sujet. Il utilise le serveur DNS standard du système pour rechercher le serveur racine pour le domaine de premier niveau et pour résoudre les noms des différents serveurs DNS le long de la chaîne, ce qui me semble approprié car ces noms changeraient vraisemblablement très rarement.

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) 

Voici quelques exemple de sortie:

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

je suis tombé sur la réponse de Jon Colverson, et il m'a aidé à comprendre le module dnspython et comment traiter les résultats (je suppose que tous les modules DNS ont le même tortueuse labyrinthe de la structure de la classe ...) J'avais besoin du TTL et des disques de colle, alors j'ai créé ma propre adaptation. Je le publie ici au cas où quelqu'un le trouverait utile; Je n'ai pas l'intention de rivaliser avec l'excellente réponse de Jon Colverson, il suffit de remplir quelques espaces supplémentaires. L'amélioration de base est l'utilisation des informations du serveur de noms dans la section supplémentaire de la réponse, si disponible. Je suppose qu'un serveur pourrait mettre autre chose que des enregistrements de collage dans la section supplémentaire, alors peut-être que cela devrait encore être amélioré pour corréler correctement les informations de la section supplémentaire avec les informations dans la section réponse. Je vais aussi chercher et imprimer tous les serveurs de noms, pas seulement le premier.

#!/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

Les autres exemples sont bien mais trop complexes si vous avez besoin seulement des serveurs de noms. Exemple de 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

Ai-je raison de penser que peut renvoyer les résultats mises en cache, si? Dans mon cas, je voulais spécifiquement trouver le serveur actuel évitant toute mise en cache, mais il pourrait y avoir une manière beaucoup plus simple de le faire que la façon dont je l'ai fait. :) –

+2

Cela vous donnera seulement le serveur de noms pour le domaine de premier niveau (ou les sous-domaines s'ils ont des enregistrements NS). Il ne vous dira pas quel est le serveur DNS faisant autorité pour 'www.example.org' et déclenchera une exception' dns.resolver.NoAnswer'. – pwaring

0

Im assez sûr que cela le ferait.

import dns.resolver 

domain = 'co.uk' 

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

Vous pouvez bien le nettoyage du cours de la réponse

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 

Ce produit

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

Corrigez-moi si je me trompe, mais je crois que ces résultats SOA pourraient encore être mis en cache sur le résolveur, cependant? C'était en contournant la mise en cache qui rendait les choses plus élaborées. –