Dans le cadre d'un outil que j'écris, je veux avoir un diagnostic qui indiquera à l'utilisateur s'il a correctement configuré le DNS de son domaine pour un service particulier. Je veux interroger le serveur DNS faisant autorité pour leur domaine afin que je puisse contourner tous les résultats mis en cache.Comment puis-je trouver le serveur DNS faisant autorité pour un domaine utilisant dnspython?
Répondre
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
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)
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
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
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. –
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. :) –
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