curl socks5h 与 socks5:谁来解析主机名
多出的那个字母移动的是 DNS 查询,而不是加密。比较两种写法,然后确认哪个主机名仍需要本地解析器。
人们把 socks5h 当作 socks5 的顺口写法,以为两者会把同一个请求发到同一个地方。多出的字母移动的却是 DNS 查询。在解析器与代理分处不同网络的机器上,这就是请求成功与失败的区别。
一个字母,两个解析器
方案决定目标名在何处变成地址。本地解析使用机器上配置的解析器。远端解析把主机名放进 SOCKS 请求里,由代理用自身的解析器和自身对网络的看法去查询。两种写法仍然连接同一端口上的同一代理地址,所以区别在请求体,而不在路径。
方案本身不改变加密或认证,移动的只有 DNS 路径。正因如此,这个字母容易被忽略,弄错却代价高昂。
同一个代理,不同的请求
两条命令只差一个字符。其余部分完全相同:
curl --proxy socks5://proxy.example:1080 https://service.example/
curl --proxy socks5h://proxy.example:1080 https://service.example/The curl 代理参考文档 分别记录这两种方案,这正是不能把它们当作别名的权威理由。拿你获准使用的无害端点分别跑一次,读出差别。远端查询成功并不能说明其他应用程序的情况,因为 浏览器、包管理器和语言运行时各自独立选择。
代理自身的名字是本地解析的
在那条命令里,proxy.example 必须在其他任何事情发生之前先变成地址,而那次查询永远是本地的。把 service.example 的解析移到代理上,对代理自身的名字毫无帮助,它仍然需要一个你的机器能访问到的解析器。VPN 正是在这里改变了局面。
如果代理名只在隧道内解析,连接就取决于隧道是否在 curl 启动前已经建立。哪个方案胜出则取决于哪一侧能给出答案。当你的机器解析不了目标而代理解析得了时,socks5 失败、socks5h 成功;当你的机器通过隧道解析得了而代理解析不了时,socks5 可用、socks5h 失败。
方案并不决定到代理的连接走 VPN 内还是外,那是路由表的事,方案根本看不到。这也是为什么同一条隧道能在同一台机器上修好一个方案、弄坏另一个方案。字母只决定谁来提问。
每一侧能解析什么
公网代理解析不了只在公司内部存在的名字,所以把主机名发给它会在代理侧失败,表现为代理错误而不是本地 DNS 错误。同一私有网络内的代理通常能解析这类名字,socks5h 的价值就在这里。请按真正需要的策略选择解析器所在的位置,因为远端 DNS 并不会自动更强,而且确实把名字交给了第三方。面向公网目标时两种写法都行,那就选你其他工具已经在用的那种。
把这项选择写进运行手册而不是注释里,并让凭据远离共享历史和诊断输出。然后一次只改一个变量:同一目标、同一二进制、同一解析器、一个字母。
是哪个二进制在应答
同一台机器上的两个 curl 二进制可能在版本和构建特性上不同。在类 Unix 的 shell 里,type -a curl 会列出路径上的每一个匹配,而 curl --version 显示真正会运行的那个的特性。路径上更靠前的包装脚本或别名,是结果与你以为在测试的二进制对不上的常见原因。
不支持的方案、解析不了名字的代理和不可达的目标是三种不同的错误,所以改字母之前先读消息。缺少 socks5h 语法的构建会把代理字符串报成不支持,这和解析失败的名字不是一回事。不要把一份关于系统 curl 的旧报告变成适用于所有平台的永久规则。