siyuan-note/siyuan · error
failed to resolve host: %s
Error message
failed to resolve host: %s
What it means
Returned by CheckHostSSRF when net.LookupIP fails for the given host. The DNS resolution error text is appended, so the message shows the underlying resolver failure. This runs before any connection is opened and is shared by web_fetch and the http_request tool to prevent SSRF.
Source
Thrown at kernel/util/httprequest.go:45
"strings"
"github.com/imroc/req/v3"
"github.com/siyuan-note/httpclient"
)
const (
maxHTTPRequestBytes = 5 * 1024 * 1024 // text/html、text/plain、application/json 等文本类响应上限
maxHTTPRequestFileBytes = 10 * 1024 * 1024 // 二进制响应落盘上限
maxHTTPRequestChars = 50000
)
// CheckHostSSRF 校验主机名解析出的 IP 不落在内网/回环等不可达地址段,
// 防止智能体被诱导发起 SSRF 攻击。web_fetch 与 http_request 共用此校验。
// https://github.com/siyuan-note/siyuan/security/advisories/GHSA-rg26-cg95-gq6p
func CheckHostSSRF(host string) error {
ips, err := net.LookupIP(host)
if err != nil {
return errors.New("failed to resolve host: " + err.Error())
}
for _, ip := range ips {
// 与 SSRFSafeDialer 共用 isPrivateIP,覆盖 NAT64、6to4、Teredo 等 IPv6 过渡地址。
if isPrivateIP(ip) {
return errors.New("access to private/internal IP is prohibited")
}
}
return nil
}
// HTTPRequest 发起一次通用 HTTP 调用,供智能体 http_request 工具使用。
// 与 WebFetch 不同:本函数不做 HTML→Markdown 转换,文本类响应(含 JSON/XML)原样返回,
// 便于智能体直接消费 REST API 的 JSON 输出。method 取值:GET/POST/PUT/DELETE/PATCH。
// 返回的 text 为响应正文(文本类)或落盘后的文件路径(二进制类)。
func HTTPRequest(method, rawURL string, headers map[string]string, body string) (statusCode int, contentType string, text string, err error) {
u, err := url.Parse(rawURL)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") {
return 0, "", "", errors.New("URL must start with http:// or https://")View on GitHub (pinned to 251596fc0d)
Solutions
- Verify the hostname is correct and resolvable (dig/nslookup host from the kernel host).
- Fix DNS on the kernel host: check /etc/resolv.conf, connectivity to the resolver, firewall rules blocking port 53.
- Retry transient DNS failures (SERVFAIL, timeout) after the resolver recovers.
Example fix
// before
if err := util.CheckHostSSRF(host); err != nil {
return err
}
// after
if _, err := net.LookupHost(host); err != nil {
return fmt.Errorf("precheck: host %q is not resolvable: %w", host, err)
}
if err := util.CheckHostSSRF(host); err != nil {
return err
} Defensive patterns
Strategy: validation
Validate before calling
func hostResolvable(host string) bool {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
_, err := net.DefaultResolver.LookupHost(ctx, host)
return err == nil
} Prevention
- Pre-resolve agent-supplied hostnames to give a clear 'unknown host' message.
- Ensure the kernel host has working DNS (/etc/resolv.conf, port 53 reachable).
When it happens
Trigger: Calling util.CheckHostSSRF(host) or HTTPRequest with a host that does not resolve: NXDOMAIN, SERVFAIL, DNS server unreachable, or a malformed hostname that LookupIP rejects.
Common situations: The agent typed a typo'd or non-existent domain; the kernel host has no working DNS (container with broken /etc/resolv.conf, offline, captive portal); a temporary DNS outage; an IPv6-only host queried with a v4-only resolver.
Related errors
- access to private/internal IP is prohibited
- URL must start with http:// or https://
- URL has no host
- request failed: %s
- response too large
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/a0c1097ce6e91e3a.
Report an issue: GitHub.