Wie kann ich DNS-Suchvorgänge in Python durchführen, einschließlich des Verweises auf / etc / hosts?


96

dnspython macht meine DNS-Lookups sehr gut, ignoriert aber den Inhalt von völlig /etc/hosts.

Gibt es einen Python-Bibliotheksaufruf, der das Richtige tut? dh zuerst einchecken etc/hostsund sonst nur auf DNS-Lookups zurückgreifen?


Ich habe ein Problem dafür erstellt: github.com/rthalley/dnspython/issues/149
Greg Dubicki

1
dnspython wird dies nicht implementieren. Verwenden Sie für einfache Forward-Lookups die vorgeschlagene socket.gethostbyname, für komplexere Abfragen dnspython.
Sebix

Antworten:


116

Ich bin mir nicht sicher, ob Sie selbst DNS-Lookups durchführen möchten oder ob Sie nur die IP eines Hosts möchten. Wenn Sie Letzteres möchten,

import socket
print(socket.gethostbyname('localhost')) # result from hosts file
print(socket.gethostbyname('google.com')) # your os sends out a dns query

1
Weiß jemand, auf welcher Ebene diese Suche zwischengespeichert wird? In Python? Oder Betriebssystem? Oder DNS-Server?
Simon East

@ Simon Wird weder von Python noch vom Betriebssystem zwischengespeichert. Es hängt von jedem beteiligten DNS-Server ab, ob er zwischengespeichert wird oder nicht. - Im Allgemeinen: DNS wird nur von der Anwendung selbst oder von auflösenden DNS-Servern zwischengespeichert, die sich in der Auflösungskette befinden.
Robert Siemer

@Jochen ob "localhost" aus der Hosts-Datei stammt oder nicht, hängt von der Konfiguration ab!
Robert Siemer

@RobertSiemer Entschuldigung für den späten Kommentar: Das Ergebnis kann vom lokalen Resolver zwischengespeichert werden. nscdund nslcdunter Unix können Boxen dies tun. Es könnte auch von einem lokalen Nameserver zwischengespeichert werden, der für das Zwischenspeichern konfiguriert ist (früher ein übliches Setup. Wahrscheinlich nicht so sehr jetzt). Leider ist dies keine einfache Nein-Antwort. Diese Dinge sind selten. :)
Alexios

Dies wird immer nur eine einzige Adresse zurückgeben, nein? Wenn Sie also ein DNS-Round-Robin haben, werden nicht alle mit dem Hostnamen verknüpften Adressen angezeigt.
ThorSummoner

90

Die normale Namensauflösung in Python funktioniert einwandfrei. Warum brauchen Sie dafür DNSpython? Verwenden Sie einfach Sockets , getaddrinfodie den für Ihr Betriebssystem konfigurierten Regeln entsprechen (unter Debian gilt Folgendes /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))]

4
wäre schön, den Transformationsschritt hinzuzufügen. addrs = [ str(i[4][0]) for i in socket.getaddrinfo(name, 80) ]gibt mir die Liste der ips.
Alex

2
list( map( lambda x: x[4][0], socket.getaddrinfo( \
     'www.example.com.',22,type=socket.SOCK_STREAM)))

gibt Ihnen eine Liste der Adressen für www.example.com. (ipv4 und ipv6)


1

Dieser Code eignet sich gut für die Rückgabe aller IP-Adressen, die möglicherweise zu einem bestimmten URI gehören. Da sich viele Systeme jetzt in einer gehosteten Umgebung befinden (AWS / Akamai / etc.), Können Systeme mehrere IP-Adressen zurückgeben. Das Lambda wurde von @Peter Silva "ausgeliehen".

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')

1

Die obige Antwort war für Python 2 gedacht. Wenn Sie Python 3 verwenden, finden Sie hier den Code.

>>> import socket
>>> print(socket.gethostbyname('google.com'))
8.8.8.8
>>>

-2

Ich habe diesen Weg gefunden, um einen DNS-RR-Hostnamen, der in eine Liste von IPs erweitert wird, in die Liste der Mitglieds-Hostnamen zu erweitern:

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

Was, wenn ich es ausführe, einige 1e100.net-Hostnamen auflistet:

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.