在 Python 中获取 IP 列表的反向 NS(又名被动 DNS)记录
Florian Weimer于 2005 年提出的被动 DNS 现在已成为 IP 安全调查、域名系统 (DNS) 运行安全等方面的核心资源。被动 DNS 数据库包含在 DNS 通信中 IP 解析到域名时观察到的事件。因此,它是一个独立于 DNS 本身的当前状态和物理基础设施的数据库。此外,它还包含时间信息:首次和最后一次观察到此类解析的日期和时间;这一点无法从 DNS 中找到。
获取此类数据的最简单方法之一就是使用 WhoisXML API 服务。在本博客中,我们重点讨论反向查询:使用 IPv4 地址,我们希望揭示这些 IP 在特定日期所属的域名。
我们将在 Linux 或 Mac OS X 命令行环境下使用 Python,但只要 Python 能够正常运行,在 Windows 命令行环境下也能轻松完成同样的工作。我们的描述面向初学者;只假定他们具备非常基本的 Python 和 shell 脚本技能。我们将使用反向 IP API和所提供的Python 软件包,它能让 API 的使用变得非常简单。可以使用 Python 的软件包管理器 pip 安装该库。在 shell 中运行以下命令即可下载并安装它:
pip3 install reverse-ip
(也可以选择以根用户身份安装,使整个系统都能使用该库,或者在Python 虚拟环境中安装,以限制安装范围)。
从技术上讲,reverse-ip 软件包现在已经可以使用,但还需要订阅 API,也可以免费订阅。订阅后,您将收到一个 API 密钥(字符串),在下文中将称为 YOUR_API_KEY。
有了所有前提条件,我们现在就可以完成任务了。因此,让我们假设在名为 ips_demo.csv 的文件中有一个 IP 地址列表。为便于演示,我们将使用以下示例:
172.67.155.63 104.21.20.75
这些 IP 地址属于 WhoisXML API 的网络服务,但也由我们的网络提供商与其他服务共享。
我们将执行一个脚本,从标准输入端读取 IP 地址,并以逗号分隔值(csv)格式将输出写入标准输出端。因此,让我们使用合适的程序员文本编辑器编辑 get_reverse_ip_of_a_list.py 脚本。首先,让我们读取 IP,然后在标准输出中重复这些 IP:
#!/usr/bin/env python3 导入 sys for line in sys.stdin.readlines(): ip = line.strip() sys.stdout.write('"%s",'%ip) sys.stdout.write("\n")
我们可以选择更复杂的方法来读取 IP,但还是简单点好。我们只需读取来自标准输入的行数,用 .strip() 删除换行符等附加字符,然后将 IP 写入标准输出,在双引号和逗号之间;结果将在这里显示。然后再写入换行符,因为我们已经为脚本的主要部分保留了两个 sys.stdout.write 调用之间的空间。
但在扩展之前,让我们先试一试:在 shell 命令行中执行以下操作
chmod +x get_reverse_ip_of_a_list.py get_reverse_ip_of_a_list.py < ips_demo.csv
结果输出如下
"172.67.155.63", "104.21.20.75",
这和预期的一样。
现在让我们扩展脚本,完成它的工作。它将读取
#!/usr/bin/env python3 导入日期时间 from time import sleep from reverseip import Client reverseip = Client('YOUR_API_KEY') for line in sys.stdin.readlines(): ip = line.strip() sys.stdout.write('"%s",'%ip) data = reverseip.data(ip) for record in data['result']: sys.stdout.write('"%s","%s","%s",'%(record['name']、 datetime.datetime.fromtimestamp( int(record['first_seen'])).strftime('%c')、 datetime.datetime.fromtimestamp( int(record['last_visit'])).strftime('%c')) sys.stdout.write("\n") sleep(.1)
不要忘记将 YOUR_API_KEY 替换为实际的 API 密钥,这样才能正常工作。我们要做的非常简单:只需从模块中导入客户端类,然后创建实例 reverseip,并在其中传递 API 密钥。然后调用 reverseip.data 即可获得结果,并以 Python 字典形式显示;有关输出数据格式的详细信息,请查阅API 文档。
目前只需知道输出结果字段,即 data['result'] 是找到的记录的迭代器即可。(更准确地说,是最多 300 条记录的迭代器。一般来说,只要一个 IP 的域名数超过 50 或 100,就需要共享基础架构,拥有所有记录的意义可能不大。不过,如果您需要所有记录,API 文档会说明如何操作)。
因此,如果有记录,我们就会遍历这些记录。每条记录都有 3 个字段,name 是实际域名,first_seen 和 last_visit 则是首次和最后一次观察该 IP 名称对的日期时间。这是由 API 以时间戳的形式提供的;我们使用看似繁琐但合乎逻辑的 datetime 标准 Python 库函数,将其转换为本地系统日期格式和时区的可读日期时间。我们将每个三元组附加到给定的输出行中。
最后,我们等待 0.1 秒,以避免遇到 API 的节流限制。(每秒的最大请求数实际上是 30,所以这一点甚至可以省略)。让我们看看我们都做了些什么:
./get_reverse_ip_of_a_list.py < ips_demo.csv
现在将导致
"172.67.155.63", "labbry.com", "Fri Jul 26 07:03:05 2019", "Fri May 7 11:09:07 2021", "livitte.com", "Fri Sep 13 07:15:39 2019", "Fri May ... "104.21.20.75", "taalmedia.com", "Fri Jun 21 13:50:38 2019", "Fri Apr 23 18:12:27 2021"、
至少在撰写本博客时是这样。(由于排版原因,我们截去了第二行):
./get_reverse_ip_of_a_list.py < ips_demo.csv > ips_pdns.csv
这样,就可以将 ips_pdns.csv 导入您最喜欢的办公电子表格。
总之,我们已经演示了如何用 Python 非常轻松地获取被动 DNS 数据,即使你刚刚开始使用 Python,也能很快上手。同时,对于高级 Python 程序员来说,只需安装 reverse-ip Python 软件包并从 WhoisXML API 获取 API 密钥即可、
从 reverseip 导入客户端 reverseip = Client('YOUR_API_KEY') data = reverseip.data(ip)
为您提供了一个包含 IP 地址被动 DNS 记录的 Python 字典。这也许是通过单个函数调用获取此类数据的最简单方法。