Jak mogę wyszukiwać adresy DNS w Pythonie, w tym odwoływać się do / etc / hosts?

97

dnspython bardzo dobrze wykona moje wyszukiwania DNS, ale całkowicie ignoruje zawartość /etc/hosts.

Czy istnieje wywołanie biblioteki Pythona, które zrobi właściwą rzecz? tzn. sprawdzaj najpierw etc/hosts, a w przeciwnym razie wracaj tylko do wyszukiwania DNS?

Toby White
źródło
Stworzyłem w tym celu numer: github.com/rthalley/dnspython/issues/149
Greg Dubicki
1
dnspython tego nie zaimplementuje. W celu prostego wyszukiwania do przodu użyj proponowanego socket.gethostbyname, dla bardziej złożonych zapytań, użyj dnspython.
sebix,

Odpowiedzi:

118

Nie jestem pewien, czy chcesz samodzielnie wyszukiwać DNS, czy po prostu chcesz uzyskać adres IP hosta. Jeśli chcesz to drugie,

import socket
print(socket.gethostbyname('localhost')) # result from hosts file
print(socket.gethostbyname('google.com')) # your os sends out a dns query
Jochen Ritzel
źródło
1
Czy ktoś wie, na jakim poziomie to wyszukiwanie jest buforowane? W Pythonie? Lub OS? Lub serwer DNS?
Simon East,
@Simon Nie jest buforowane przez Pythona ani przez system operacyjny. Zależy to od dowolnego zaangażowanego serwera DNS, czy buforuje, czy nie. - Ogólnie mówiąc: DNS jest zapisywany w pamięci podręcznej tylko przez samą aplikację lub przez serwery rozpoznawania nazw DNS umieszczone w łańcuchu rozwiązywania.
Robert Siemer
@Jochen, czy „localhost” pochodzi z pliku hosts, czy nie, zależy od konfiguracji!
Robert Siemer
@RobertSiemer Przepraszamy za późny komentarz: wynik może zostać zapisany w pamięci podręcznej przez lokalny przelicznik. nscda nslcdna skrzynkach Unix może to zrobić. Może być również buforowany przez lokalny serwer nazw skonfigurowany do buforowania (typowa konfiguracja, kiedyś. Prawdopodobnie nie tak bardzo teraz). Niestety nie jest to prosta odpowiedź „nie”. Takie rzeczy rzadko się zdarzają. :)
Alexios
to zwróci tylko jeden adres nie? Więc jeśli masz dns round robin, nie ujawni to wszystkich adresów powiązanych z nazwą hosta.
ThorSummoner
91

Normalne rozpoznawanie nazw w Pythonie działa dobrze. Dlaczego potrzebujesz do tego DNSpython. Po prostu użyj gniazd , getaddrinfoktóre są zgodne z regułami skonfigurowanymi dla twojego systemu operacyjnego (w Debianie wygląda to następująco /etc/nsswitch.conf:

>>> print socket.getaddrinfo('google.com', 80)
[(10, 1, 6, '', ('2a00:1450:8006::63', 80, 0, 0)), (10, 2, 17, '', ('2a00:1450:8006::63', 80, 0, 0)), (10, 3, 0, '', ('2a00:1450:8006::63', 80, 0, 0)), (10, 1, 6, '', ('2a00:1450:8006::68', 80, 0, 0)), (10, 2, 17, '', ('2a00:1450:8006::68', 80, 0, 0)), (10, 3, 0, '', ('2a00:1450:8006::68', 80, 0, 0)), (10, 1, 6, '', ('2a00:1450:8006::93', 80, 0, 0)), (10, 2, 17, '', ('2a00:1450:8006::93', 80, 0, 0)), (10, 3, 0, '', ('2a00:1450:8006::93', 80, 0, 0)), (2, 1, 6, '', ('209.85.229.104', 80)), (2, 2, 17, '', ('209.85.229.104', 80)), (2, 3, 0, '', ('209.85.229.104', 80)), (2, 1, 6, '', ('209.85.229.99', 80)), (2, 2, 17, '', ('209.85.229.99', 80)), (2, 3, 0, '', ('209.85.229.99', 80)), (2, 1, 6, '', ('209.85.229.147', 80)), (2, 2, 17, '', ('209.85.229.147', 80)), (2, 3, 0, '', ('209.85.229.147', 80))]
bortzmeyer
źródło
4
byłoby miło dodać krok transformacji. addrs = [ str(i[4][0]) for i in socket.getaddrinfo(name, 80) ]daje mi listę adresów IP.
Alex
2
list( map( lambda x: x[4][0], socket.getaddrinfo( \
     'www.example.com.',22,type=socket.SOCK_STREAM)))

wyświetla listę adresów dla www.example.com. (ipv4 i ipv6)

Peter Silva
źródło
1

Ten kod działa dobrze w przypadku zwracania wszystkich adresów IP, które mogą należeć do określonego identyfikatora URI. Ponieważ wiele systemów znajduje się obecnie w środowisku hostowanym (AWS / Akamai / itp.), Systemy mogą zwracać kilka adresów IP. Lambda została „pożyczona” od @Peter Silva.

def get_ips_by_dns_lookup(target, port=None):
    '''
        this function takes the passed target and optional port and does a dns
        lookup. it returns the ips that it finds to the caller.

        :param target:  the URI that you'd like to get the ip address(es) for
        :type target:   string
        :param port:    which port do you want to do the lookup against?
        :type port:     integer
        :returns ips:   all of the discovered ips for the target
        :rtype ips:     list of strings

    '''
    import socket

    if not port:
        port = 443

    return list(map(lambda x: x[4][0], socket.getaddrinfo('{}.'.format(target),port,type=socket.SOCK_STREAM)))

ips = get_ips_by_dns_lookup(target='google.com')
jedzenie
źródło
1

Powyższa odpowiedź była przeznaczona dla Pythona 2. Jeśli używasz Pythona 3, oto kod.

>>> import socket
>>> print(socket.gethostbyname('google.com'))
8.8.8.8
>>>
Sabrina
źródło
-2

Znalazłem sposób, aby rozwinąć nazwę hosta DNS RR, która rozwija się do listy adresów IP, do listy nazw hostów członków:

#!/usr/bin/python

def expand_dnsname(dnsname):
    from socket import getaddrinfo
    from dns import reversename, resolver
    namelist = [ ]
    # expand hostname into dict of ip addresses
    iplist = dict()
    for answer in getaddrinfo(dnsname, 80):
        ipa = str(answer[4][0])
        iplist[ipa] = 0
    # run through the list of IP addresses to get hostnames
    for ipaddr in sorted(iplist):
        rev_name = reversename.from_address(ipaddr)
        # run through all the hostnames returned, ignoring the dnsname
        for answer in resolver.query(rev_name, "PTR"):
            name = str(answer)
            if name != dnsname:
                # add it to the list of answers
                namelist.append(name)
                break
    # if no other choice, return the dnsname
    if len(namelist) == 0:
        namelist.append(dnsname)
    # return the sorted namelist
    namelist = sorted(namelist)
    return namelist

namelist = expand_dnsname('google.com.')
for name in namelist:
    print name

Który po uruchomieniu wyświetla kilka nazw hostów 1e100.net:

gwizdek
źródło