news 2026/9/9 20:13:37

curl 命令行 `--dns-servers` 选项完全指南:用 c-ares 自定义 DNS 服务器与端口

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
curl 命令行 `--dns-servers` 选项完全指南:用 c-ares 自定义 DNS 服务器与端口

curl 命令行--dns-servers选项完全指南:用 c-ares 自定义 DNS 服务器与端口

【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl

--dns-servers是 curl 提供的覆盖系统默认 DNS 解析目标的高级选项,它允许用户在命令行直接指定一个或多个 DNS 服务器(含自定义端口),常用于调试、绕过错误的上游 DNS、或对接内网解析环境。本文以 curl 仓库官方手册文档 docs/cmdline-opts/dns-servers.md 为核心,结合命令解析、libcurl 选项设置与 c-ares 解析器三层源码,讲透该选项的语法、适用范围、底层实现与排错思路。

一、选项概览:它能做什么

从官方选项定义文档来看,--dns-servers的核心作用非常聚焦:

设置要使用的 DNS 服务器列表,以取代系统默认配置。IP 地址列表应以逗号分隔;也支持可选端口号,以冒号附加在 IP 地址后。

即它控制的是 curl 内部做主机名解析(将主机名转换为 IP 地址)这一环节使用的上游 DNS 服务器,而非连接目标本身。

该选项定义在 docs/cmdline-opts/dns-servers.md,其 YAML 头元数据完整说明了关键属性:

字段取值含义
Longdns-servers长选项名称
Arg<addresses>需要一个"服务器地址列表"参数
HelpDNS server addrs to use帮助信息中的一句话说明
ProtocolsDNS作用于 DNS 解析过程
Requiresc-ares仅在启用 c-ares 解析后端时可用
Added7.33.0从该版本开始提供
Categorydns属于 DNS 相关选项类别
Multisingle非可累加选项(重复指定时后值覆盖前值,而非累积成列表)

二、前提条件:必须在编译期启用 c-ares

这是理解--dns-servers最重要的一步——它不是所有 curl 版本/发行版都携带的选项。curl 支持多种主机名解析后端(阻塞式、线程式、c-ares),而只有 c-ares 后端才能让应用自定义 DNS 服务器。选项元数据中的Requires: c-ares已明确这一点。

从仓库构建配置可以印证:

  • CMake 构建中默认关闭,需显式开启。见 CMakeLists.txt 第 184 行的option(ENABLE_ARES "Enable c-ares support" OFF);开启后它会通过 CMake/FindCares.cmake 定位系统 c-ares,并要求链接CURL::cares
  • autotools 构建中则通过--enable-ares启用,见 configure.ac 第 4380-4381 行,启用成功后会AC_DEFINE(USE_RESOLV_ARES, 1, ...),此时解析后端报告为c-ares
  • c-ares 版本有硬性下限。源码 lib/vdns/asyn-ares.c 第 63-65 行强制要求ARES_VERSION >= 0x011000(即 c-ares 1.16.0 及以上),否则编译直接报错。

验证当前构建是否支持该选项,可在交互使用前执行curl --version检查输出中是否包含c-ares,或直接运行:

curl --help all | grep dns-servers

三、命令语法与参数格式详解

完整语法:

curl --dns-servers <addresses> [其它选项] URL

参数<addresses>是一个由逗号分隔的 DNS 服务器地址列表,官方文档给出了两个示例:

# 使用两个 IPv4 DNS 服务器(默认 53 端口) curl --dns-servers 192.168.0.1,192.168.0.2 $URL # 使用一个带自定义端口的 DNS 服务器 curl --dns-servers 10.0.0.1:53 $URL

格式要点可归纳为:

  1. 多服务器用英文逗号分隔:如--dns-servers 8.8.8.8,1.1.1.1。curl 会按文档语义将其理解为有序的服务器列表;同时从 c-ares 的ares_set_servers_ports_csv调用看,该函数本身也接受一个 CSV 格式字符串(见下文源码解析),两者格式完全对应。
  2. 可选端口用英文冒号追加<ip>:<port>形式,如10.0.0.1:5353。这与"默认 53 端口可省略"的常见 DNS 配置习惯一致。
  3. 支持 IPv6 地址场景:地址格式由 c-ares 解析器按 CSV 规则处理,结合同目录的 dns-ipv6-addr.md 等选项可知,curl 的 DNS 定制一族对 v4/v6 环境均有覆盖。涉及 IPv6 时需按 c-ares 的 CSV 规则书写,端口分隔同样是冒号。

与配置文件 / 变量写法

该选项也可以写入 curl 配置文件(--config指定的文件或~/.curlrc),行内写法与命令行一致:

# ~/.curlrc 示例 dns-servers = "192.168.0.1,192.168.0.2"

配置文件的通用解析规则参见 docs/cmdline-opts/config.md。

四、一条命令的完整调用链(源码级解析)

--dns-servers从命令行到真正生效,跨越了三个层次,仓库源码完整保留了这条链路。

第 1 层:命令行参数解析

在命令行工具源码 src/tool_getparam.c 第 120 行注册了选项名{"dns-servers", ARG_STRG, ' ', C_DNS_SERVERS},表明它是一个字符串参数;第 2536-2542 行则做了关键守卫:

case C_DNS_SERVERS: /* --dns-servers */ if(!curlinfo->ares_num) /* c-ares is needed for this */ err = PARAM_LIBCURL_DOESNT_SUPPORT; else /* IP addrs of DNS servers */ err = getstr(&config->dns_servers, nextarg, DENY_BLANK);

可见:工具会先检查运行时探测到的 c-ares 支持情况(curlinfo->ares_num)。若当前链接的 libcurl 未启用 c-ares,则直接返回PARAM_LIBCURL_DOESNT_SUPPORT,命令行会拒绝接受该选项并给出相应错误提示,而不是默默忽略。DENY_BLANK表示不允许空字符串参数。

第 2 层:映射为 libcurl 传输选项

解析得到字符串后,src/config2setopts.c 第 1062 行在构建 easy 句柄时把它转换为 libcurl 选项:

MY_SETOPT_STR(curl, CURLOPT_DNS_SERVERS, config->dns_servers);

程序化使用 libcurl 的开发者也可直接设置CURLOPT_DNS_SERVERS(字符串类型选项,见 lib/easyoptions.c 第 83 行的类型登记)。

第 3 层:libcurl 存储与 c-ares 落地

在 lib/setopt.c 第 2248-2250 行,CURLOPT_DNS_SERVERS的分支被#ifdef USE_RESOLV_ARES包裹:

#ifdef USE_RESOLV_ARES case CURLOPT_DNS_SERVERS: return Curl_setstropt(data, STRING_DNS_SERVERS, ptr);

这从库层面再次印证:编译时未定义USE_RESOLV_ARES(即未启用 c-ares)的 libcurl 根本不接受该选项,此时无论命令行还是curl_easy_setopt都无法使用自定义 DNS 服务器。

真正把服务器列表下发给 c-ares 的逻辑在 lib/vdns/asyn-ares.c 的async_ares_set_dns_servers()(第 658-693 行)。该函数在创建 c-ares channel 时被调用(第 165 行),核心是:

const char *servers = CURL_EASY_STR(data, STRING_DNS_SERVERS); ... if(ares && ares->channel) ares_result = ares_set_servers_ports_csv(ares->channel, servers);

即最终调用 c-ares 的ares_set_servers_ports_csv(),把逗号分隔的地址列表(含可选端口)解析并注入 ares channel。代码同时把 c-ares 返回码映射为 curl 错误码:

c-ares 返回码curl 结果
ARES_SUCCESSCURLE_OK(成功)
ARES_ENOMEMCURLE_OUT_OF_MEMORY
ARES_ENOTINITIALIZED/ARES_ENODATA/ARES_EBADSTRCURLE_BAD_FUNCTION_ARGUMENT,并打印bad servers set调试信息

这意味着非法格式的服务器列表会在选项生效检查阶段被拒绝(返回参数错误),而非在解析时静默失败。

调试彩蛋:CURL_DNS_SERVER

在同文件第 666-669 行,还存在一个仅供调试构建(DEBUGBUILD)使用的环境变量覆盖机制:

#ifdef DEBUGBUILD if(getenv("CURL_DNS_SERVER")) servers = getenv("CURL_DNS_SERVER"); #endif

也就是说在开启 debug 的 curl 构建中,可通过设置CURL_DNS_SERVER环境变量临时覆盖命令行传入的服务器列表,方便测试人员在不改动参数的情况下切换上游 DNS。

五、与相近 DNS 定制选项的关系

--dns-servers属于 curl 的 DNS 定制选项族,使用时常与以下选项区分或搭配,它们定义于同目录:

  • --dns-interface:指定发送 DNS 查询所使用的本地网络接口(同样要求 c-ares),对应CURLOPT_DNS_INTERFACE
  • --dns-ipv4-addr / --dns-ipv6-addr:指定绑定到 DNS 套接字上的本地 IPv4/IPv6 地址(源地址),对应CURLOPT_DNS_LOCAL_IP4/CURLOPT_DNS_LOCAL_IP6
  • --doh-url:使用 DNS-over-HTTPS 方式解析,走 HTTPS 通道而非传统 DNS 服务器,不要求 c-ares。
  • --resolve:为指定主机名静态固定解析结果(可含端口),优先级高于任何 DNS 服务器;适合"就是要连到某个特定 IP"的场景。

四者的关系可以这样理解:--resolve是绕过解析、直接钉死结果;--dns-servers是替换查询目标;--dns-interface/--dns-ipv4-addr/--dns-ipv6-addr是控制查询报文从哪个本地出口发出。底层上,四个 c-ares 相关选项在 lib/vdns/asyn-ares.c 的 channel 初始化流程中按顺序依次应用(第 165-179 行),互不冲突。

在 lib/vdns/asyn-ares.c 第 652-657 行的注释中还揭示了两种特殊场景:应用通过CURLOPT_DNS_SERVERS传入NULL表示清除先前设定并重建 ares channel;而在 channel 惰性初始化且值为NULL(无偏好)时不重置既有 channel。这解释了为何在同一个 easy 句柄生命周期内反复设置/清除该选项是安全的。

六、常见问题与排查思路

Q1:提示选项不支持 /curl --help中看不到该选项?大概率是链接的 curl 未启用 c-ares。按第二节方法重新编译(CMake 开启ENABLE_ARES、autotools 加--enable-ares),或换用带 c-ares 的发行包。可先curl --version确认。

Q2:传入的服务器列表报参数错误?确认列表格式:纯逗号分隔、端口用冒号、无多余空白、每个地址本身合法。底层ares_set_servers_ports_csv解析失败会映射为CURLE_BAD_FUNCTION_ARGUMENT(见第四节错误映射表)。

Q3:指定后仍走了系统 DNS?先确认命中 c-ares 后端而不是线程式/阻塞式解析器;其次确认没有--resolve或 DoH(--doh-url)等更高优先级机制在起作用。

Q4:多个 DNS 服务器如何选择?列表以逗号分隔作为整体传入 c-ares,由 c-ares 按自身策略使用这些服务器;curl 侧不额外做负载均衡,因此"顺序即策略"的期望应由 c-ares 行为决定,不同 c-ares 版本对服务器选择/失败切换的策略可能存在差异。

七、速查与延伸

  • 选项手册原文:docs/cmdline-opts/dns-servers.md
  • 命令行帮助清单:src/tool_listhelp.c 第 158 行
  • 参数解析与 c-ares 守卫:src/tool_getparam.c 第 120、2536-2542 行
  • 选项到 libcurl 的映射:src/config2setopts.c 第 1062 行
  • libcurl 选项存储:lib/setopt.c 第 2248-2250 行、lib/easyoptions.c 第 83 行
  • c-ares 落地实现:lib/vdns/asyn-ares.c 第 658-693 行
  • 构建开关:CMakeLists.txt 第 184 行、configure.ac 第 4380-4381 行、CMake/FindCares.cmake

一句话总结:--dns-servers的威力在于把"用哪台 DNS 服务器解析"的决定权从操作系统交还到 curl 使用者手中,但其可用性的根基是 c-ares 编译支持——先确认后端,再关注列表格式,最后借助错误映射快速定位问题。

【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 20:10:48

PB03低功耗蓝牙SoC二次开发实战:从SDK到自定义GATT服务

简介&#xff1a;面向蓝牙嵌入式开发者与物联网爱好者的PB03模块二次开发资料包已打包发布&#xff0c;覆盖安信可PB-03蓝牙5.2模块基于PHY6252 SoC的完整开发链路。资料面向有单片机基础、希望快速上手低功耗蓝牙产品研发的读者&#xff0c;可解决环境搭建、固件升级、外设驱动…

作者头像 李华
网站建设 2026/9/9 20:10:46

JVM invokedynamic 三层动态链接协议:从字节码到调用点

一条invokedynamic&#xff0c;在 JVM 面试题里出现频率不低&#xff0c;但真正说清楚它的人不多。很多人背了一句“Java 7 引入的&#xff0c;用于支持动态类型语言”&#xff0c;然后被问“它和反射有什么区别”“为什么 lambda 要用它”就卡住了。这篇文章不打算停留在概念层…

作者头像 李华
网站建设 2026/9/9 20:09:45

无模型自适应控制MFAC原理与Matlab仿真实现

搞控制的人一定听过一句话&#xff1a;建模不准&#xff0c;控制白费。但实际工程里很多被控对象根本给不出像样的机理模型&#xff0c;有些即使能建立模型&#xff0c;参数也随工况漂移得厉害。这种情况下再去做基于模型的控制设计&#xff0c;往往花了大把时间&#xff0c;投…

作者头像 李华
网站建设 2026/9/9 20:09:37

SOA:激光雷达与光纤传感共用的“定盘星”

前两年我陪客户调试一台光纤分布式声波传感设备&#xff0c;实验室里一切正常&#xff0c;一进现场就出幺蛾子&#xff1a;同一段光纤&#xff0c;人工在路边走&#xff0c;波形倒是出来了&#xff0c;但隔壁工地重型卡车一过&#xff0c;系统直接饱和&#xff0c;整条曲线白茫…

作者头像 李华
网站建设 2026/9/9 20:09:22

显示器支架安装与调试全攻略:气压弹簧、VESA匹配与桌搭避坑

显示器支架现在几乎是桌搭和游戏外设场景里的标配硬件&#xff0c;它解决的不仅是“屏幕抬高一点”的问题&#xff0c;而是把显示器重心从桌面上释放出来&#xff0c;让键盘、音箱、手柄、耳机架都能回到桌面上。百元价位的显示器支架之所以讨论度高&#xff0c;是因为这个价格…

作者头像 李华
网站建设 2026/9/9 20:08:44

Adreno GPU如何让手机游戏实现端侧AI实时推理

1. 项目概述&#xff1a;当AI推理从“云端排队”变成“手机里秒算”最近刷到一条消息&#xff0c;说高通在骁龙8 Gen3的Adreno GPU上跑通了7B参数量的量化大模型&#xff0c;推理延迟压到了80毫秒以内——我第一反应不是“哇好快”&#xff0c;而是把手机翻过来摸了摸后盖温度。…

作者头像 李华