【免费下载链接】Cybersecurity-Projects
Building 70 Projects ranging from beginner to advanced so anyone can — learn from, build upon, use as a reference, or even copy directly. Gamified Cybersecurity learning 👇
本篇指南以 Cybersecurity-Projects 仓库中 dns-lookup 项目 及其 DEMO.md 为核心,完整讲解 dnslookup-cli 的安装方式、五种命令用法、Rich 彩色表格输出与 JSON 结构化导出的两种工作模式,并结合 resolver.py、cli.py、output.py 的源码细节,带你理解并发异步 DNS 查询、解析路径追踪(trace)和 WHOIS 集成背后的实现原理。读完本文,你将能够直接安装运行这套 DNS 侦察工具,掌握它的全部命令行参数,并能基于源码思路扩展出子域枚举、DNS 监控告警等自己的安全工具。
一、项目概览与安装启动
dnslookup-cli 是一个"专业级"的 DNS 查询命令行工具:它不只是dig/nslookup的简单封装,而是实现了并发异步 DNS 查询、从根服务器到权威服务器的完整解析路径追踪、以及适合人读和机器读的双格式输出(详见 00-OVERVIEW.md)。在安全场景中,它主要用于侦察阶段的基础设施枚举——A/AAAA 记录暴露 IP 与托管商、MX 记录暴露邮件基础设施、NS 记录暴露 DNS 服务商、TXT 记录泄露 SPF/DKIM 配置(对应 MITRE ATT&CK 的 T1590.002 DNS 侦察技术)。
1.1 安装方式
项目支持两种启动方式。最推荐的是通过 PyPI 使用uv tool全局安装(这也是 DEMO.md 中给出的官方安装命令):
uv tool install dnslookup-cli安装完成后即可全局调用dnslookup命令。若希望从源码运行(适用于本地开发或学习),可以在项目目录PROJECTS/beginner/dns-lookup/下通过just任务运行器或uv直接执行:
# 方式一:项目内置 justfile 提供 run / lookup 等快捷任务 just lookup example.com # 方式二:直接使用 uv 运行 uv run dnslookup query example.com项目依赖非常精简,完整依赖列表可在 pyproject.toml 中查看:
| 依赖 | 版本要求 | 用途 |
|---|---|---|
| dnspython | >=2.8.0 | DNS 协议底层库(异步解析、报文构造) |
| rich | >=14.2.0 | 终端彩色表格、树形图与面板渲染 |
| typer | >=0.20.0 | CLI 命令行框架与参数解析 |
| python-whois | >=0.9.6 | WHOIS 注册信息查询 |
注意:项目要求 Python 3.13+(
requires-python = ">=3.13"),因为源码使用了StrEnum等较新的语言特性。
1.2 五个核心命令
工具入口定义在 cli.py,提供了五个子命令,与 README.md 的命令表一致:
| 命令 | 功能 | 典型示例 |
|---|---|---|
dnslookup query | 查询域名的各类 DNS 记录(彩色表格输出) | dnslookup query example.com |
dnslookup reverse | IP 反查主机名(PTR 记录) | dnslookup reverse 8.8.8.8 |
dnslookup trace | 从根服务器到权威服务器追踪解析路径 | dnslookup trace example.com |
dnslookup batch | 从文件批量并发查询多个域名 | dnslookup batch domains.txt -o results.json |
dnslookup whois | 查询域名注册信息 | dnslookup whois example.com |
全局还提供--version/-v参数用于查看版本号并退出(实现在 cli.py)。
二、Table Output:彩色表格输出模式
DEMO.md 展示的第一种输出模式是Table Output(表格输出),官方描述为:"Full DNS record query with colored table, record type filtering, and response time tracking"——即完整的 DNS 记录查询,支持彩色表格、记录类型筛选与响应时间统计。
2.1 基本用法与参数
query命令最常用的完整参数如下(源码见 cli.py):
dnslookup query <domain> \ [--type A,AAAA,MX,NS,TXT,CNAME,SOA | ALL] \ [--server 8.8.8.8] \ [--timeout 5.0] \ [--json]| 参数 | 简写 | 默认值 | 说明 |
|---|---|---|---|
--type/-t | -t | ALL | 逗号分隔的记录类型列表;传入ALL或留空即查询全部 7 种(A、AAAA、MX、NS、TXT、CNAME、SOA) |
--server/-s | -s | 系统默认 DNS | 指定要查询的 DNS 服务器,如8.8.8.8,用于测试特定解析器 |
--timeout | 无 | 5.0 | 单次查询超时(秒) |
--json/-j | -j | False | 切换为 JSON 输出模式(详见第三章) |
记录类型字符串的解析逻辑在parse_record_types()(cli.py):输入会先转为大写,再按逗号拆分;遇到未知类型不会报错中断,而是打印黄色警告后跳过;若最终没有有效类型则回退到全部类型。因此--type A,MX、--type a,mx、--type ALL都是合法写法。
2.2 表格渲染细节
表格输出由 output.py 中的print_results_table()负责。表头固定为三列——Type(记录类型)、Value(记录值)、TTL(生存时间),并采用了这些 Rich 排版特性:
box=box.ROUNDED:圆角边框;row_styles=["", "dim"]:奇偶行交替变暗,提升长表格的可读性;header_style="bold cyan":表头加粗青色;- TTL 列右对齐、加窄列宽(
width=8),并经过format_ttl()(output.py)转换为人类可读形式——86400 秒显示为1d、3600 秒显示为1h、60 秒以上显示为分钟、其余显示为秒。
每种记录类型还有专属配色(output.py):
| 记录类型 | 颜色 | | 记录类型 | 颜色 | |----------|------|--|----------|------| | A | green | | CNAME | red | | AAAA | blue | | SOA | white | | MX | magenta | | PTR | bright_cyan | | NS | cyan | | TXT | yellow |
这样在同一次混合类型的查询结果里,可以一眼区分不同记录类型。对于 MX 记录,工具还会在值后面附加(priority: N)的备注(output.py),因为 MX 记录带优先级字段(在 resolver.py 中通过rdata.preference提取)。
表格下方还会打印一行摘要(print_summary(),output.py):找到的记录条数、查询耗时(毫秒)以及使用的 nameserver——这就是 DEMO 截图中所见"50ms / 107ms"响应时间追踪的由来。若查询出错(如 NXDOMAIN、超时),print_errors()会以红色✗逐条打印错误信息(output.py)。
2.3 底层:并发查询与数据模型
表格里的每一行数据,来自 resolver.py 的lookup()异步函数。它的关键设计是一次性创建全部记录类型的查询任务,再用asyncio.gather()并发执行:
tasks = [ query_record_type(domain, rt, resolver) for rt in record_types ] query_results = await asyncio.gather(*tasks, return_exceptions=True)return_exceptions=True保证某个记录类型失败(如该域名没有 MX 记录)时不会取消其他查询,而是把异常作为返回值收集进DNSResult.errors,从而支持"部分成功"的结果。对 7 种记录类型、每类 50ms 延迟的场景,顺序查询需 350ms,而并发查询只需约 50ms(7 倍提速,见 03-IMPLEMENTATION.md)。
查询结果被组织为三个清晰的数据类(resolver.py):
RecordType(StrEnum):枚举 A/AAAA/MX/NS/TXT/CNAME/SOA/PTR 八种类型,StrEnum既提供类型安全又可直接与 DNS 协议的字符串类型名比较;DNSRecord:单条记录,含record_type、value、ttl,以及仅 MX 使用的priority;DNSResult:一次查询的聚合结果,含domain、records、errors、query_time_ms、nameserver,其中列表字段使用field(default_factory=list)避免可变默认参数陷阱。
每种记录类型的值提取由extract_record_value()(resolver.py)完成:A/AAAA 取rdata.address,MX 取rdata.exchange并保留rdata.preference,NS/CNAME/PTR 取rdata.target,TXT 取原始文本,SOA 则拼接为NS: xxx, Serial: xxx形式——所有 FQDN 值都会用.rstrip(".")去掉结尾点。
三、JSON Export:脚本与管道集成的机器可读输出
DEMO.md 展示的第二种输出模式是JSON Export(JSON 导出),官方描述为:"Machine-readable JSON output for scripting and pipeline integration"——面向脚本与管道集成。在任意子命令后追加--json/-j即可启用,例如:
dnslookup query certgames.com --json dnslookup batch domains.txt --json dnslookup trace example.com --json dnslookup whois example.com --json3.1 JSON 结构说明
单域名查询的 JSON 由results_to_json()(output.py)生成,结构如下:
{ "domain": "certgames.com", "records": [ { "type": "A", "value": "93.184.216.34", "ttl": 181, "priority": null }, { "type": "MX", "value": "mail.example.com", "ttl": 3600, "priority": 10 } ], "errors": [], "query_time_ms": 45.2, "nameserver": null }各字段含义:
| 字段 | 类型 | 说明 |
|---|---|---|
domain | string | 被查询的域名 |
records | array | 记录数组,每条含type(字符串枚举值)、value、ttl(秒)、priority(MX 之外的记录为null) |
errors | array | 本次查询的错误信息列表,正常为空 |
query_time_ms | number | 查询总耗时,毫秒,保留两位小数 |
nameserver | string | null | 指定的 DNS 服务器(未指定时为null) |
results_to_json()还处理了一个易用性细节:单条结果输出为对象,批量结果输出为数组(if len(data) == 1: return json.dumps(data[0], ...)),下游脚本无需关心两种形态的分歧。
3.2 批量查询的 JSON 落盘
batch命令除了--json输出到 stdout 外,还支持--output/-o将 JSON 结果直接写入文件(cli.py):
echo "example.com" > domains.txt echo "example.org" >> domains.txt dnslookup batch domains.txt --type A,MX,NS --output results.json批量结果是一个数组,随后可用标准工具继续加工:
jq '.[] | select(.records != []) | .domain' results.json批量命令的文件格式约定(cli.py)为:每行一个域名、#开头为注释、空行忽略;文件不存在时报错并以退出码 1 结束,文件内没有任何有效域名时提示警告并正常退出。批量执行的底层是batch_lookup()(resolver.py 附近),它把每个域名的一次完整lookup()作为独立任务,再一次通过asyncio.gather()并发执行——对 100 个域名、每个 50ms 的场景,顺序需 5000ms,并发仅约 200–500ms(受 DNS 服务器限速约束),可带来 10–25 倍提速。
3.3 其他命令的 JSON 变体
reverse:反查结果同样通过results_to_json()输出,记录类型固定为 PTR;trace:由trace_to_json()(output.py)生成,结构为{ domain, hops: [{zone, server, server_ip, response, is_authoritative}], final_answer, error },完整保留了每一跳的解析路径信息;whois:由whois_to_json()序列化,包含注册商、创建/过期/更新日期、nameserver、状态与 DNSSEC 等字段。
四、表格之外的两种可视化输出:reverse 与 trace
虽然 DEMO 只展示了 query 的两种输出,但该工具的终端渲染能力远不止于此,理解它们有助于你把 JSON 与表格模式灵活组合。
4.1 反查(reverse)
dnslookup reverse 8.8.8.8会执行 PTR 反查,底层调用reverse_lookup()(resolver.py 起),借助 dnspython 的resolver.resolve_address()自动处理 IPv4 的.in-addr.arpa与 IPv6 的.ip6.arpa反向区转换。表格模式会渲染一张IP Address / Hostname / TTL三列表格(print_reverse_result(),output.py)。PTR 记录常用于邮件服务器身份验证与日志溯源,缺失往往意味着基础设施卫生状况不佳。
4.2 解析路径追踪(trace)
dnslookup trace example.com是理解 DNS 层级最直观的命令。它实现了一套迭代式解析(resolver.py):
- 从硬编码的根服务器 IP 起步(
a.root-servers.net198.41.0.4、b.root-servers.net170.247.170.2、c.root-servers.net192.33.4.12)——因为"解析根服务器自身的域名"需要先有能工作的解析器,这是 DNS 的引导(bootstrap)问题,所有递归解析器都硬编码这些地址; - 用底层 API
dns.message.make_query()+dns.query.udp()直接向指定服务器发 UDP 报文,而不是走高层resolver.resolve()——这样才能控制"向谁查"; - 若响应含
authority区的 NS 记录,则提取下一层服务器,并从additional区读取glue records(胶水记录)直接拿到 NS 的 IP,避免"解析 ns1.example.com 需要查询 ns1.example.com"的循环依赖;无胶水记录时才回退去单独解析 NS 主机名; - 若响应含
answer区,即到达权威服务器,记录最终答案后终止。
输出端由print_trace_result()(output.py)渲染为 Rich树形图:根([.] Root)、TLD、权威(Authoritative)三个层级,每个跳点显示服务器名与 IP,权威跳点绿色、转介跳点青色,最后打印最终解析结果与总跳数。
五、whois 与实战安全场景
dnslookup whois <domain>用于查询域名注册信息,实现在 whois_lookup.py。由于不同 TLD 注册局返回的字段并不一致,代码采用了防御式hasattr()属性访问、对 status 字段做 string/list 归一化、对日期字段取列表首个元素并格式化为YYYY-MM-DD等处理(详见 03-IMPLEMENTATION.md 的 WHOIS 章节)。查询到的 DNSSEC 状态也会一并展示。
把这些命令组合起来,就构成了一套完整的 DNS 侦察与监测工作流(安全注意事项:请仅对自有或获授权的目标执行):
# 侦察阶段:枚举目标域名的解析记录与基础设施 dnslookup query target.com --type A,MX,NS,TXT dnslookup trace target.com # 关联分析:反查已知 IP 识别服务器归属 dnslookup reverse 8.8.8.8 # 批量侦察:从文件并发探测一批域名并落盘 dnslookup batch domains.txt --output results.json # 注册信息:评估域名归属与过期时间(威胁情报常用) dnslookup whois target.com --json在安全防御视角,这套工具对应 MITRE ATT&CK 的若干技术点:DNS 侦察(T1590.002)、DNS 隧道(T1071.004)、DNS 基础设施劫持(T1584.002);在历史事件中,Dyn DDoS 攻击(2016)、Sea Turtle 政府 DNS 劫持行动(2019)、MyEtherWallet 因 BGP 劫持导致 DNS 指向钓鱼站(2018)等案例都表明 DNS 攻击面的现实威胁(详见 01-CONCEPTS.md)。
六、架构与测试:为什么它值得学习
整个项目遵循清晰的三层架构(见 02-ARCHITECTURE.md):
CLI 层(cli.py,Typer + Rich) ↓ 调用 业务逻辑层(resolver.py + whois_lookup.py,dnspython) ↓ 协议 DNS 协议(UDP:53)/ WHOIS 协议(TCP:43) ↓ 返回数据对象 呈现层(output.py,Rich 格式化)关键解耦原则:resolver 从不 import output——它只返回DNSResult/TraceResult数据对象,由 CLI 层决定渲染成表格还是 JSON。这让业务逻辑脱离终端可独立测试,也让切换输出格式(如扩展 CSV)无需触碰解析代码。
测试方面,tests/test_resolver.py 直接导入真实模块(而非 mock)发起真实 DNS 查询:例如test_lookup_real_domain断言example.com的查询耗时大于 0,test_lookup_nonexistent_domain用几乎不可能存在的域名断言返回空记录。异步测试通过@pytest.mark.asyncio配合 pytest-asyncio 插件完成(pyproject.toml 中设置了asyncio_mode = "auto")。开发质量门禁在 justfile 中聚合为just ci(lint + typecheck + test)。
七、扩展方向
基于当前实现,你可以沿着 04-CHALLENGES.md 提供的 18 个挑战继续深入,其中与本篇两种输出模式直接相关、最易上手的包括:
- CSV 输出格式:在
output.py中仿照results_to_json()增加results_to_csv(),把嵌套结构拍平为domain,record_type,value,ttl,priority,query_time_ms,即可直接导入 Excel 分析; - DNSSEC 校验:在
create_resolver()中启用resolver.use_edns(0, dns.flags.DO, 4096)请求 DNSSEC 记录,再验证 RRSIG 签名链; - 子域枚举:以
batch_lookup()为起点,对常见子域前缀做并发暴力枚举(安全提示:AXFR 区域传送通常被禁止,仅能对自有域名测试); - DNS 监控告警:定时执行
query并对比历史状态(A/AAAA/MX/NS 记录变化),一旦发现 NS 记录突变即可预警可能的注册商账号劫持。
结语
dnslookup-cli 以四行依赖、一个uv tool install命令,把 DNS 协议、异步并发、CLI 设计与终端可视化这几大主题串成了一套开箱即用的安全工具。通过本文,你已经掌握它的表格输出(彩色分类型、TTL 人性化、耗时统计)与JSON 导出(单对象/批量数组、文件落盘、管道集成)两种核心用法,也理解了并发查询、迭代式追踪与 WHOIS 防御式解析的实现细节。后续学习可继续阅读仓库内的 00-OVERVIEW.md、01-CONCEPTS.md、02-ARCHITECTURE.md、03-IMPLEMENTATION.md 与 04-CHALLENGES.md 五个学习模块,构建从"会用"到"会造"的完整知识链。
【免费下载链接】Cybersecurity-Projects
Building 70 Projects ranging from beginner to advanced so anyone can — learn from, build upon, use as a reference, or even copy directly. Gamified Cybersecurity learning 👇
相关推荐
OpenColorIO色彩配置实战指南:3步打造专业级色彩工作流
OpenColorIO色彩配置实战指南:3步打造专业级色彩工作流 OpenColorIO Configs作为开源色彩配置方案,为影视制作和图像处理提供了完整的色
Perfetto 内存分析:用 heapprofd 抓住 Android 内存泄漏
Perfetto 内存分析:用 heapprofd 抓住 Android 内存泄漏 凌晨的告警群弹出一条消息:某购物应用线上 OOM 率在过去两小时抬升, Ou
可观测性后端开发工具前端数据可视化3步打造专业PPT配色:PPTist色彩工具全解析
3步打造专业PPT配色:PPTist色彩工具全解析 你是否还在为PPT配色头疼?明明用了高级模板,却总调不出协调的视觉效果?本文将通过PPTist(基于Vue3
前端企业应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考