c-ares:一个把异步 DNS 查询做成 C 库的老牌项目,值得用吗
该项目围绕「c-ares/c-ares」构建,面向真实业务场景提供可复用的开源实践方案,支持稳定落地与可扩展的项目实践。
秒懂
- 它是什么?
- c-ares 是一个用 C 写的异步 DNS stub resolver 库,主打不阻塞、可并行,且自称比系统自带的解析器更好。本文基于其 README 与仓库信息,拆解它的设计目标、构建方式、适用边界,以及真正需要留意的取舍。
- 适合谁用?
- c-ares 适合那些需要非阻塞 DNS 解析、或要在同一事件循环里发起大量并行查询的 C 网络应用,比如 HTTP 客户端、邮件代理或自定义协议栈。它不适合只想简单把主机名换成 IP、且愿意接受系统解析器阻塞行为的场景,因为引入它意味着你要管理事件循环、回调上下文和额外的构建依赖。
- 能商用吗?
- 可以。MIT 是宽松许可证:你可以使用、修改并销售基于它的软件,只需保留版权和许可证声明。
- 还在维护吗?
- 在维护。仓库最近一次提交在 15 天前。
- 用什么语言写的?
- 主要是 C(依据 GitHub 的语言统计)。
以上回答依据项目的 GitHub 数据(最近同步于 2026年9月14日)和我们的分析,不构成法律意见。
开源项目深度解析
它解决的是阻塞问题,而不是 DNS 本身
c-ares 的定位很直接:一个用 C 写的 DNS stub resolver 库,核心卖点是异步。传统上,你调用系统提供的 getaddrinfo 时,线程会卡在那里,直到 DNS 响应返回或超时。c-ares 把查询拆成非阻塞操作,你发起请求后可以继续做别的事,等结果就绪再处理。README 里明确说,它最初就是为那些需要不阻塞查询、或者需要并行发起多个查询的应用设计的。所以它解决的问题不是 DNS 协议有多难,而是阻塞这个行为在事件驱动或高并发场景里有多碍事。它面向的是一类具体的开发者:写网络服务、需要把 DNS 查询塞进现有事件循环的人。
从查询到回调:它的事件模型藏在 API 后面
从仓库结构和文档描述看,c-ares 的工作方式是你先初始化一个 channel,然后提交查询,库内部管理 socket 和超时,最后通过回调把结果交给你。README 没有展开 API 细节,但它的异步本质决定了你必须把自己的事件循环和 c-ares 的 socket 状态对接起来。这意味着你通常要周期性调用它的处理函数,或者在 socket 可读时触发它。这个机制的好处是你可以同时挂多个查询,互不阻塞;代价是你得自己维护这个循环。对于已经用 libevent、libuv 或自写 epoll 循环的应用,这不算负担,但如果你只是想在单线程脚本里查个域名,这个模型就明显偏重。
构建与安装:C89 兼容,MIT 许可,平台列表很长
README 声称 c-ares 可以用任何 C89 编译器构建,这降低了嵌入旧工具链的门槛。它采用 MIT 许可,意味着商业和自由软件都能用,这一点对很多公司来说是决定性的。支持的平台包括 Linux、FreeBSD、OpenBSD、MacOS、Solaris、AIX、Windows、Android、iOS 以及更多。具体的构建步骤指向 INSTALL.md 文件,仓库里没有在 README 里直接贴出 configure 或 cmake 命令,所以你需要去那个文件里找。对于大多数 Unix 系系统,典型的路径是 ./configure 然后 make,但这不是从 README 确认的,只能说根据这类项目的常规布局,INSTALL.md 会给出准确指令。
安全投入是明写的,但你要自己验证
README 花了不小篇幅谈安全。它说自己实现了安全的解析器和数据构建器,避免了很多 C 库常见的坑,并且通过自动化测试、静态分析、动态分析以及 OSS-Fuzz 持续模糊测试来验证。这些说法是项目方的自我描述,不是第三方审计结论。它确实挂了一堆质量相关的徽章链接,比如 Coveralls、SonarCloud、Coverity,但这只能说明它有这些工具的接入,不能等同于无漏洞。对使用者来说,更实际的动作是验证你下载的 release 包。README 给出了完整的 GPG 签名验证命令,以及 SLSA provenance 的验证流程,后者能确认 release 是从预期仓库和 tag 构建出来的。这一步值得做,尤其是你要把这个库编进长期运行的服务里。
支持哪些记录类型,决定了它能用在哪
c-ares 支持的 RFC 列表相当长,从基础的 A 和 AAAA,到 SRV、NAPTR、TLSA、SVCB、HTTPS、URI、CAA 都有覆盖。这意味着它不只是把域名换成 IP,还能处理服务发现、DANE 验证、HTTPS 参数协商这类更细的 DNS 用法。对写邮件客户端、VoIP 或自定义传输协议的人来说,SRV 和 NAPTR 是刚需。对做 HTTPS 服务发现的人来说,SVCB 和 HTTPS 记录的支持是近年才跟进的功能,说明项目没有停在 20 年前的实现上。但要注意,支持这些记录类型只代表库能解析,不代表你的上游 DNS 服务器会返回它们。实际链路里,很多递归解析器对 SVCB 的处理还不一致,这会在集成时暴露出来。
一个明显的权衡:它想取代系统解析器,但系统解析器不是一无是处
README 里有一句很直接的话:c-ares 的目标是成为比系统提供的解析器更好的解析器,并且建议所有网络应用都用它,哪怕你不需要异步。这个立场值得商榷。系统解析器通常和操作系统的网络配置深度绑定,比如 /etc/resolv.conf、DHCP 下发的搜索域、VPN 的 DNS 分流,这些细节 c-ares 作为一个库需要自己处理或部分忽略。它的跨平台支持是优点,但也意味着它要自己实现很多系统层逻辑,这既是复杂度来源,也是潜在行为差异的来源。如果你的应用依赖系统特定的解析行为,比如 mDNS 或特定搜索域逻辑,c-ares 不一定能完全模拟。这不是说它不好,而是说它把解析器从系统里抽出来,你就得自己承担那些系统原本替你处理的事情。
替代方案:不是只有它一个,但思路不同
最常见的替代是直接调用系统解析器,比如 POSIX 的 getaddrinfo。它的优势是零依赖、行为与系统配置一致,缺点是阻塞,而且并行查询要么靠多线程,要么靠自己写超时逻辑。另一个思路是 libunbound,它来自 NLnet Labs,是一个验证性的递归解析器库,能自己处理 DNSSEC 验证和缓存。c-ares 是 stub resolver,它把查询发给上游递归器,自己不验证 DNSSEC 链条;libunbound 则能做完整验证。如果你的需求是端到端的 DNSSEC 信任,c-ares 不是那个工具。反过来,如果你只是要一个轻量、嵌入式的异步查询接口,libunbound 的功能和复杂度可能超出你的需要。选择的关键在于你要的是简单转发还是完整解析。
维护节奏与升级代价:活跃但需要你跟上
从仓库的 recent releases 看,v1.34.6 在 2025 年 12 月发布,v1.34.7 和 v1.34.8 分别在 2026 年 7 月 6 日和 7 日发布,两天内连发两个补丁版本,说明维护相当活跃,但也暗示上游在快速修问题。这种节奏对使用者是双刃剑:你得到及时的安全修复,但你也要承担升级的测试成本。c-ares 是 C 库,API 变化通常受语义化版本约束,但行为变化不一定在 changelog 里写清楚。升级前最好跑一遍你自己的解析场景,尤其是涉及超时、重试和 EDNS0 行为的用例。另外,README 提到 release 包有 GPG 签名和 SLSA provenance,这降低了被投毒的风险,但前提是你真的去验证。跳过验证,这些机制等于不存在。
编辑结论
c-ares 适合那些需要非阻塞 DNS 解析、或要在同一事件循环里发起大量并行查询的 C 网络应用,比如 HTTP 客户端、邮件代理或自定义协议栈。它不适合只想简单把主机名换成 IP、且愿意接受系统解析器阻塞行为的场景,因为引入它意味着你要管理事件循环、回调上下文和额外的构建依赖。在采用之前,先确认你的目标平台是否在官方支持列表里,再读一遍 INSTALL.md 里的构建选项,尤其是你打算静态链接还是动态链接。还要验证你需要的记录类型是否在 FEATURES.md 的清单中,比如 SVCB 和 HTTPS 记录虽然已支持,但你的解析目标服务器是否真的返回这些记录,是另一回事。最后,如果你对供应链安全敏感,务必按 README 里给出的 GPG 签名验证步骤和 SLSA provenance 流程核对下载的 release 包,而不是直接解压。
社区笔记