Как мне найти авторитетный DNS-сервер для домена, использующего dnspython? - PullRequest
10 голосов
/ 01 ноября 2010

Как часть инструмента, который я пишу, я хочу провести диагностику, которая скажет пользователю, правильно ли они настроили DNS своего домена для конкретной службы.Я хочу запросить официальный DNS-сервер для своего домена, чтобы я мог обойти любые кэшированные результаты.

Ответы [ 4 ]

18 голосов
/ 01 ноября 2010

Вот моя попытка сделать это.Он использует стандартный 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 голосов
/ 19 декабря 2011

Я наткнулся на ответ Джона Колверсона, и он помог мне понять модуль 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 голосов
/ 02 июля 2014

Другие примеры хороши, но слишком сложны, если вам нужны только серверы имен.Пример из 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
0 голосов
/ 25 августа 2017

Я уверен, что это сделало бы это.

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
...