如何在Python中进行DNS查询,包括引用/etc/hosts?

121 投票
7 回答
209713 浏览
提问于 2025-04-15 22:33

dnspython 这个库可以很好地处理我的DNS查询,但它完全不考虑 /etc/hosts 文件里的内容。

有没有哪个Python库可以做到这一点?也就是说,先检查 /etc/hosts 文件,如果找不到再去做DNS查询?

7 个回答

9

听起来你不想自己处理DNS解析。dnspython是一个独立的DNS客户端,它会忽略你的操作系统,因为它直接绕过了操作系统的工具。

我们可以看看一个叫getent的命令行工具,来了解像Debian 11这样的操作系统是如何为程序解析DNS的。这可能是所有使用套接字实现的类Unix系统的标准做法。

查看man getent中的“hosts”部分,它提到了getaddrinfo的使用,我们可以通过man getaddrinfo来了解更多。

在Python中使用它时,我们需要从数据结构中提取一些信息:

import socket

def get_ipv4_by_hostname(hostname):
    # see `man getent` `/ hosts `
    # see `man getaddrinfo`

    return list(
        i        # raw socket structure
            [4]  # internet protocol info
            [0]  # address
        for i in 
        socket.getaddrinfo(
            hostname,
            0  # port, required
        )
        if i[0] is socket.AddressFamily.AF_INET  # ipv4

        # ignore duplicate addresses with other socket types
        and i[1] is socket.SocketKind.SOCK_RAW  
    )

print(get_ipv4_by_hostname('localhost'))
print(get_ipv4_by_hostname('google.com'))
104

在Python中,正常的名称解析是可以正常工作的。那为什么还需要DNSpython呢?其实你只需要使用socket库里的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))]
129

我不太确定你是想自己做DNS查询,还是只是想要一个主机的IP地址。如果你想要后者,

/!\ socket.gethostbyname这个方法已经过时了,建议使用 socket.getaddrinfo

根据 man gethostbyname 的说明:

gethostbyname*()、gethostbyaddr*()等函数已经不再使用。应用程序应该使用getaddrinfo(3)和getnameinfo(3),

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

撰写回答