/ etc / hosts 참조를 포함하여 Python에서 DNS 조회를 어떻게 수행 할 수 있습니까?


97

dnspython 은 내 DNS 조회를 매우 훌륭하게 수행하지만 /etc/hosts.

옳은 일을 할 파이썬 라이브러리 호출이 있습니까? 즉에서 먼저 확인 etc/hosts하고 그렇지 않으면 DNS 조회로만 폴백합니까?



1
dnspython은 이것을 구현하지 않습니다. 단순 정방향 조회의 경우 제안 socket.gethostbyname된를 사용하고 더 복잡한 쿼리의 경우 dnspython을 사용하십시오.
sebix

답변:


118

DNS 조회를 직접 수행 할지 아니면 호스트의 IP 만 원하는지 잘 모르겠습니다 . 후자를 원하는 경우,

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

1
이 조회가 캐시되는 수준을 아는 사람이 있습니까? 파이썬 안에서? 아니면 OS? 아니면 DNS 서버?
사이먼 이스트

@Simon Python이나 OS에 의해 캐시되지 않습니다. 캐시 여부는 관련된 DNS 서버에 따라 다릅니다. – 일반적으로 말해서 : DNS는 응용 프로그램 자체에 의해서만 캐시되거나 확인 체인에있는 확인 DNS 서버에 의해서만 캐시됩니다.
Robert Siemer 2013 년

@Jochen "localhost"가 호스트 파일에서 왔는지 여부가 구성에 의존하지 않는 경우!
Robert Siemer 2013 년

@RobertSiemer 늦은 의견에 대해 죄송합니다 : 결과 로컬 해석기에 의해 캐시 될 수 있습니다. nscd그리고 nslcd유닉스 박스에서는 이것을 할 수 있습니다. 또한 캐싱을 위해 구성된 로컬 이름 서버에 의해 캐싱 될 수 있습니다 (일반적인 설정, 한 번에 한 번. 아마도 지금은 그리 많지 않을 것입니다). 안타깝게도 간단한 '아니오'대답이 아닙니다. 이러한 것들은 거의 없습니다. :)
Alexios

이것은 단일 주소 만 반환 할 것입니다. 따라서 DNS 라운드 로빈을 사용하는 경우 호스트 이름과 관련된 모든 주소가 노출되지는 않습니다.
ThorSummoner

91

Python의 일반적인 이름 확인은 정상적으로 작동합니다. 왜 DNSpython이 필요합니까? 그냥 사용하는 소켓getaddrinfo데비안 (운영 체제에 대해 구성된 규칙에 따라, 그것은 다음과 /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
변형 단계를 추가하면 좋을 것입니다. addrs = [ str(i[4][0]) for i in socket.getaddrinfo(name, 80) ]나에게 IP 목록을 제공합니다.
Alex

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

www.example.com의 주소 목록을 제공합니다. (ipv4 및 ipv6)


1

이 코드는 특정 URI에 속할 수있는 모든 IP 주소를 반환하는 데 적합합니다. 이제 많은 시스템이 호스팅 된 환경 (AWS / Akamai / etc.)에 있으므로 시스템이 여러 IP 주소를 반환 할 수 있습니다. 람다는 @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')

1

위의 답변은 Python 2를위한 것입니다. Python 3을 사용하는 경우 여기에 코드가 있습니다.

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

-2

이 방법으로 IP 목록으로 확장되는 DNS RR 호스트 이름을 구성원 호스트 이름 목록으로 확장하는 방법을 찾았습니다.

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

실행할 때 몇 개의 1e100.net 호스트 이름이 나열됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.