[Bug] web_fetch 在 fake-ip(198.18.0.0/15)环境下对所有站点都抛 WEB_BLOCKED_URL,且无配置可放宽地址预检 #6737
zhinengfan
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Summary
在 fake-ip 模式下运行的 Clash/mihomo 类透明代理网络中,本地解析器会把所有域名统一解析为
198.18.0.0/15的假地址,此时web_fetch抓取任意站点都失败:内置的
web-fetch-http是当前唯一的 fetch provider,它的公网地址预检把 fake-ip 段判为非公网地址。该判定没有配置项、环境变量或地址白名单可以放宽,所以web_fetch在这类网络里对任何目标都不可用(不只是内网目标)。同一条规则还会命中其他"本地解析器返回非公网地址"的部署:企业或校园 DNS 对内部域名返回私有/CGNAT 地址、DNS 沉洞、部分 VPN,以及 DNS64/NAT64 环境。
Reproduction
最小复现(不依赖任何代理,只涉及校验器本身):
198.18.0.0/15是 RFC 2544 保留段,ipaddr.js将其归类为reserved,因此isPublicIpAddress()返回false:沿用
tests/fetch-http.spec.ts已有的导入方式:真实环境复现:
dig +short example.com返回198.18.x.x;web_fetch抓取任意公网站点,必然抛WEB_BLOCKED_URL。Current behavior
判定发生在
resolvePublicAddresses()(packages/web/web-fetch-http/src/network.ts:75):它逐条检查 DNS 答案,只要有一条不是公网单播地址就整包拒绝(第 100-102 行),isPublicIpAddress()(同文件第 54-66 行)只接受ipaddr.range() === 'unicast'。Config(src/index.ts:32-51)只有maxResponseBytes、maxBodyChars、timeoutMs、maxRedirects、userAgent五个限额字段,没有放宽地址判定的入口。目前唯一的绕行方式是在进程上配置
http_proxy/https_proxy:命中代理时 provider 走requestVia()(src/provider.ts:134-138),既不解析也不校验。这相当于为网络环境整体放弃这项防护,而不是在配置层放行特定地址。同一台机器上,把同一个 URL 交给普通 HTTP 客户端(同样的 DNS 答案、同样的 fake-ip 地址)可以正常取回内容,说明链路本身可用,失败只来自这条预检。
Expected behavior
希望在保持默认严格行为的前提下,让"本地解析器给出的非公网地址"可以按配置放行。按侵入性从小到大:
allowNonPublicAddresses?: string[](CIDR 列表,默认空),命中的网段从拒绝改为放行,例如['198.18.0.0/15'];allowPrivateNetwork?: boolean(默认 false,文档注明会关闭 SSRF 防护);tests/fetch-http.spec.ts:136现有断言(rejects the whole DNS answer set when one address is not public),取舍需要一并决定。三种方式都建议默认维持现状,由部署方显式放宽。
Environment
0.1.5-rc.2(npm 全局安装);master(2026-09-15)上同一判定仍位于packages/web/web-fetch-http/src/network.ts:100-102@deepseek-ai/dsh-web-fetch-http(唯一内置 fetch provider)198.18.0.0/15All reactions