首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用特定DNS服务器的套接字解析DNS

使用特定DNS服务器的套接字解析DNS
EN

Stack Overflow用户
提问于 2016-01-14 23:16:47
回答 2查看 15.6K关注 0票数 15

我想用特定的DNS服务器解析DNS,例如Google的8.8.8.8。我实际的Python代码是:

代码语言:javascript
复制
import socket

def getIP(d):
    try:
        data = socket.gethostbyname(d)
        ip = repr(data)
        return True
    except Exception:
        # fail gracefully!
        return False

可以使用Python吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-01-14 23:30:10

你可以在ubuntu/debian上使用dnspython:http://www.dnspython.org/,你可以使用:

代码语言:javascript
复制
sudo apt-get install python-dnspython

否则,请通过以下方式获取:

代码语言:javascript
复制
sudo pip install dnspython

或者下载源代码,通过以下方式安装:

代码语言:javascript
复制
sudo python setup.py install

你的代码应该是这样的:

代码语言:javascript
复制
from dns import resolver

res = resolver.Resolver()
res.nameservers = ['8.8.8.8']

answers = res.query('stackexchange.com')

for rdata in answers:
    print (rdata.address)

编辑:由于OP在Mac OS X上使用它似乎有问题,下面是我安装它的方法(仅供本地用户使用):

代码语言:javascript
复制
git clone git://github.com/rthalley/dnspython.git
cd dnspython
python setup.py install --user
票数 11
EN

Stack Overflow用户

发布于 2020-02-08 08:57:21

dnspython是一个成熟的库,但对于刚到这里的人来说可能有些过头了。因此,我提供了一个简单的单文件implementation

代码语言:javascript
复制
import socket
import ipaddress


def parse_dns_string(reader, data):
    res = ''
    to_resue = None
    bytes_left = 0

    for ch in data:
        if not ch:
            break

        if to_resue is not None:
            resue_pos = chr(to_resue) + chr(ch)
            res += reader.reuse(resue_pos)
            break

        if bytes_left:
            res += chr(ch)
            bytes_left -= 1
            continue

        if (ch >> 6) == 0b11 and reader is not None:
            to_resue = ch - 0b11000000
        else:
            bytes_left = ch

        if res:
            res += '.'

    return res


class StreamReader:
    def __init__(self, data):
        self.data = data
        self.pos = 0

    def read(self, len_):
        pos = self.pos
        if pos >= len(self.data):
            raise

        res = self.data[pos: pos+len_]
        self.pos += len_
        return res

    def reuse(self, pos):
        pos = int.from_bytes(pos.encode(), 'big')
        return parse_dns_string(None, self.data[pos:])


def make_dns_query_domain(domain):
    def f(s):
        return chr(len(s)) + s

    parts = domain.split('.')
    parts = list(map(f, parts))
    return ''.join(parts).encode()


def make_dns_request_data(dns_query):
    req = b'\xaa\xbb\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00'
    req += dns_query
    req += b'\x00\x00\x01\x00\x01'
    return req


def add_record_to_result(result, type_, data, reader):
    if type_ == 'A':
        item = str(ipaddress.IPv4Address(data))
    elif type_ == 'CNAME':
        item = parse_dns_string(reader, data)
    else:
        return

    result.setdefault(type_, []).append(item)


def parse_dns_response(res, dq_len, req):
    reader = StreamReader(res)

    def get_query(s):
        return s[12:12+dq_len]

    data = reader.read(len(req))
    assert(get_query(data) == get_query(req))

    def to_int(bytes_):
        return int.from_bytes(bytes_, 'big')

    result = {}
    res_num = to_int(data[6:8])
    for i in range(res_num):
        reader.read(2)
        type_num = to_int(reader.read(2))

        type_ = None
        if type_num == 1:
            type_ = 'A'
        elif type_num == 5:
            type_ = 'CNAME'

        reader.read(6)
        data = reader.read(2)
        data = reader.read(to_int(data))
        add_record_to_result(result, type_, data, reader)

    return result


def dns_lookup(domain, address):
    dns_query = make_dns_query_domain(domain)
    dq_len = len(dns_query)

    req = make_dns_request_data(dns_query)
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.settimeout(2)

    try:
        sock.sendto(req, (address, 53))
        res, _ = sock.recvfrom(1024 * 4)
        result = parse_dns_response(res, dq_len, req)
    except Exception:
        return
    finally:
        sock.close()

    return result


if __name__ == '__main__':
    print(dns_lookup('www.stackoverflow.com', "8.8.8.8"))

输出:

代码语言:javascript
复制
{'CNAME': ['stackoverflow.com'], 'A': ['151.101.1.69', '151.101.65.69', '151.101.129.69', '151.101.193.69']}
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34793061

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档