{"record":{"id":"836b5c703117c5ba","repo":"siyuan-note/siyuan","slug":"failed-to-resolve-host","errorCode":null,"errorMessage":"failed to resolve host: ","messagePattern":"failed to resolve host: ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/httprequest.go","lineNumber":52,"sourceCode":"\t\"time\"\n\n\t\"github.com/siyuan-note/httpclient\"\n\tgolangProxy \"golang.org/x/net/proxy\"\n)\n\nconst (\n\tmaxHTTPRequestBytes     = 5 * 1024 * 1024  // text/html、text/plain、application/json 等文本类响应上限\n\tmaxHTTPRequestFileBytes = 10 * 1024 * 1024 // 二进制响应落盘上限\n\tmaxHTTPRequestChars     = 50000\n)\n\n// CheckHostSSRF 校验主机名解析出的 IP 不落在内网/回环等不可达地址段，\n// 防止智能体被诱导发起 SSRF 攻击。web_fetch 与 http_request 共用此校验。\n// https://github.com/siyuan-note/siyuan/security/advisories/GHSA-rg26-cg95-gq6p\nfunc CheckHostSSRF(host string) error {\n\tips, err := net.LookupIP(host)\n\tif err != nil {\n\t\treturn errors.New(\"failed to resolve host: \" + err.Error())\n\t}\n\tfor _, ip := range ips {\n\t\t// 与 SSRFSafeDialer 共用 isPrivateIP，覆盖 NAT64、6to4、Teredo 等 IPv6 过渡地址。\n\t\tif isPrivateIP(ip) {\n\t\t\treturn errors.New(\"access to private/internal IP is prohibited\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// ssrfSafeClient 是智能体出站请求专用的 HTTP 客户端：直连时将目标固定到已校验的公网 IP，\n// 使用代理时则先与用户配置的代理建立隧道，再通过隧道连接固定后的目标 IP，同时保留原始 Host 和 TLS SNI。\n// 两种方式都不会在校验后再次按目标域名解析，避免 DNS 重绑定 TOCTOU 绕过。\n// https://github.com/siyuan-note/siyuan/security/advisories/GHSA-x8gv-g2g3-65fj\nvar ssrfSafeClient = newSSRFSafeClient()\n\nfunc newSSRFSafeClient() *http.Client {\n\treturn newSSRFSafeClientWithResolver(net.DefaultResolver.LookupIPAddr)","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/util/httprequest.go#L34-L70","documentation":"CheckHostSSRF performs a DNS lookup of the requested host before any outbound agent HTTP request (web_fetch / http_request) so it can block private/loopback addresses. If net.LookupIP fails — the hostname does not resolve, DNS is down, or the host string is malformed — the request is rejected with this error wrapping the resolver message.","triggerScenarios":"HTTPRequest, WebFetch, downloadGeneratedImage, or downloadSkillSource called with a hostname that cannot be resolved: typo'd domain, expired domain, offline/filtered DNS, or a garbage host string.","commonSituations":"An AI agent hallucinating a URL; corporate DNS blocking external lookups; IPv6-only or sandboxed environments without resolv.conf; typo like 'htps://example.com' producing an unparseable host.","solutions":["Verify the hostname spelling and that it is a real registered domain (dig/nslookup the host from the same machine)","Check the machine's DNS configuration (/etc/resolv.conf, systemd-resolved) and network connectivity","Retry once DNS is restored — this is a transient/environmental failure, not a policy block (a policy block returns the private-IP error instead)","If a local/hosts-file name is intended, it will still fail the SSRF policy by design; use the public domain instead"],"exampleFix":"// before\nHTTPRequest(ctx, \"https://exmaple.com/api\") // typo, DNS fails\n// after\nHTTPRequest(ctx, \"https://example.com/api\")","handlingStrategy":"retry","validationCode":"addrs, err := net.LookupIP(host)\nif err != nil || len(addrs) == 0 {\n    return fmt.Errorf(\"host %q does not resolve; aborting request\", host)\n}","typeGuard":null,"tryCatchPattern":"if err := CheckHostSSRF(host); err != nil {\n    if strings.Contains(err.Error(), \"failed to resolve host\") {\n        time.Sleep(retryBackoff)\n        return retryFetch(url, 2)\n    }\n    return err // policy blocks are not retryable\n}","preventionTips":["Validate and normalize URLs extracted from model output before requesting them","Check DNS health (resolv.conf, systemd-resolved) in sandboxed/containerized environments","Distinguish resolver failures (transient) from private-IP blocks (policy) by message before retrying"],"tags":["dns","network","ssrf","security"],"backgroundTag":"dns-resolution-failed","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}