ฉันจะค้นหา DNS ใน Python รวมถึงการอ้างถึง / etc / hosts ได้อย่างไร


98

dnspythonจะทำการค้นหา DNS ของฉันเป็นอย่างดี แต่จะละเว้นเนื้อหาของ/etc/hosts.

มีการเรียกไลบรารี python ซึ่งจะทำสิ่งที่ถูกต้องหรือไม่? เช่นเช็คอินก่อนetc/hostsและถอยกลับไปที่การค้นหา DNS เท่านั้นเป็นอย่างอื่น?


ฉันสร้างปัญหาสำหรับสิ่งนั้น: github.com/rthalley/dnspython/issues/149
Greg Dubicki

1
dnspython จะไม่ใช้สิ่งนี้ สำหรับการค้นหาไปข้างหน้าอย่างง่ายให้ใช้สิ่งที่เสนอsocket.gethostbynameสำหรับการค้นหาที่ซับซ้อนมากขึ้นให้ใช้ dnspython
sebix

คำตอบ:


120

ฉันไม่แน่ใจจริงๆว่าคุณต้องการค้นหา 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
ไม่มีใครรู้ว่าการค้นหานี้แคชอยู่ในระดับใด ภายใน Python? หรือ OS? หรือเซิร์ฟเวอร์ DNS?
Simon East

@ Simon ไม่แคชโดย Python หรือ OS ขึ้นอยู่กับเซิร์ฟเวอร์ DNS ที่เกี่ยวข้องว่าแคชหรือไม่ - โดยทั่วไป: DNS ถูกแคชโดยแอปพลิเคชันเท่านั้นหรือโดยการแก้ไขเซิร์ฟเวอร์ DNS ที่ซ่อนอยู่ในห่วงโซ่การแก้ไข
Robert Siemer

@Jochen ถ้า“ localhost” มาจากไฟล์โฮสต์หรือไม่ขึ้นอยู่กับการกำหนดค่า!
Robert Siemer

@RobertSiemer ขออภัยสำหรับความคิดเห็นที่ล่าช้า: ผลลัพธ์อาจถูกแคชโดยตัวแก้ไขท้องถิ่น nscdและnslcdบนกล่อง Unix สามารถทำได้ นอกจากนี้ยังสามารถแคชโดยเซิร์ฟเวอร์ชื่อภายในที่กำหนดค่าไว้สำหรับการแคช (การตั้งค่าทั่วไปกาลครั้งหนึ่งอาจยังไม่มากในตอนนี้) มันไม่ใช่คำตอบที่ตรงไปตรงมา แต่น่าเสียดาย สิ่งเหล่านี้ไม่ค่อยมี :)
Alexios

สิ่งนี้จะส่งกลับที่อยู่เดียวเท่านั้น? ดังนั้นหากคุณมี dns round robin สิ่งนี้จะไม่เปิดเผยที่อยู่ทั้งหมดที่เกี่ยวข้องกับชื่อโฮสต์
ThorSummoner

91

ความละเอียดของชื่อปกติใน Python ทำงานได้ดี ทำไมคุณถึงต้องการ DNSpython สำหรับสิ่งนั้น เพียงแค่ใช้ซ็อกเก็ต 's getaddrinfoซึ่งตามกฎการกำหนดค่าสำหรับระบบปฏิบัติการของคุณ (ใน Debian ก็ดังนี้/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))]

5
จะเป็นการดีที่จะเพิ่มขั้นตอนการเปลี่ยนแปลง addrs = [ str(i[4][0]) for i in socket.getaddrinfo(name, 80) ]ขอรายชื่อ ips
Alex

ผลลัพธ์คำขอของฉันส่งคืนที่อยู่ IP เดียวกันหลายครั้ง เราสามารถแก้ไขได้ด้วยการเปลี่ยนแปลงคำแนะนำของ alex ง่ายๆ: addrs = { str(i[4][0]:i for i in socket.getaddrinfo(name, 80) }ส่งคืนคำสั่งที่มี ips ที่ไม่ซ้ำกันเป็นคีย์โดยจับคู่ผลลัพธ์ที่เหลือ
tk421storm


1

รหัสนี้ใช้ได้ดีในการส่งคืนที่อยู่ IP ทั้งหมดที่อาจเป็นของ URI เฉพาะ เนื่องจากขณะนี้ระบบจำนวนมากอยู่ในสภาพแวดล้อมที่โฮสต์ (AWS / Akamai / ฯลฯ ) ระบบอาจส่งคืนที่อยู่ 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

ฉันพบวิธีนี้ในการขยายชื่อโฮสต์ DNS RR ที่ขยายเป็นรายการ IP ในรายการชื่อโฮสต์ของสมาชิก:

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