Tencent/WeKnora · error
DNS resolution failed for %s: %w
Error message
DNS resolution failed for %s: %w
What it means
SSRFSafeDialContext resolves the hostname itself (once, via net.DefaultResolver.LookupIPAddr) so it can validate every answer before connecting, and this error means that lookup failed. The library resolves explicitly to close the DNS-rebinding window between validation and connection; a resolver failure aborts the dial. The wrapped error (%w) carries the underlying DNS failure (NXDOMAIN, timeout, no such host, resolver unreachable).
Source
Thrown at internal/utils/security.go:832
hostLower := strings.ToLower(host)
for _, restricted := range restrictedHostnames {
if hostLower == restricted {
return nil, fmt.Errorf("connection blocked: hostname %s is restricted", host)
}
}
for _, suffix := range restrictedHostSuffixes {
if strings.HasSuffix(hostLower, suffix) {
return nil, fmt.Errorf("connection blocked: hostname suffix %s is restricted", suffix)
}
}
// Resolve the hostname once, validate every answer, and then dial one of
// those exact IPs. Dialing the original hostname here would make the
// standard dialer resolve it a second time, leaving a DNS-rebinding window
// between validation and connection establishment.
ips, err := net.DefaultResolver.LookupIPAddr(ctx, host)
if err != nil {
return nil, fmt.Errorf("DNS resolution failed for %s: %w", host, err)
}
if len(ips) == 0 {
return nil, fmt.Errorf("DNS resolution returned no addresses for %s", host)
}
// Validate all resolved IPs
for _, ipAddr := range ips {
if restricted, reason := isRestrictedIP(ipAddr.IP); restricted {
return nil, fmt.Errorf("connection blocked: %s resolves to restricted IP %s (%s)", host, ipAddr.IP.String(), reason)
}
}
// If we get here, all IPs are safe. Pin the connection to the validated DNS
// answers; TLS still uses the request hostname for SNI/certificate checks.
dialer := &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}View on GitHub (pinned to 988cbb0330)
Solutions
- Verify the hostname resolves from the same environment: run a lookup (nslookup/getent hosts or net.LookupIP in Go) and fix the name or DNS records if it fails there too.
- Fix resolver configuration (/etc/resolv.conf, VPC DNS settings, CoreDNS) so the process can reach a working nameserver.
- Retry with backoff if the wrapped error indicates a transient resolver timeout.
- If the host is IP-only anyway, dial the literal IP (still subject to isRestrictedIP checks) to skip DNS entirely.
Example fix
// before
conn, err := utils.SSRFSafeDialContext(ctx, "tcp", "api.exmaple.com:443") // typo, NXDOMAIN
// after
if _, err := net.LookupIP("api.example.com"); err != nil { return fmt.Errorf("resolve check failed: %w", err) }
conn, err := utils.SSRFSafeDialContext(ctx, "tcp", "api.example.com:443") Defensive patterns
Strategy: retry
Validate before calling
ips, err := net.LookupIP(host)
if err != nil {
return fmt.Errorf("pre-flight DNS check failed for %s: %w", host, err)
} Try / catch
conn, err := utils.SSRFSafeDialContext(ctx, "tcp", addr)
if err != nil && strings.Contains(err.Error(), "DNS resolution failed") {
var dnsErr *net.DNSError
if errors.As(err, &dnsErr) && dnsErr.IsTimeout {
// transient: retry with backoff
}
return nil, fmt.Errorf("check DNS/resolver configuration for %s: %w", host, err)
} Prevention
- Verify /etc/resolv.conf and VPC DNS settings in every environment (containers, CI, prod).
- Spell-check hostnames against DNS records during config review.
- Add retry-with-backoff for transient DNSError timeouts.
- Monitor resolver health; alert on rising DNS failure rates.
When it happens
Trigger: Dialing a hostname that does not exist in DNS, with an unreachable/misconfigured resolver, under a network policy that blocks UDP/TCP 53, or when the resolver times out before LookupIPAddr returns — reached via SSRFSafeDialContext, SSRFSafeGRPCDialer, or an http.Transport using it as DialContext.
Common situations: Typo in the hostname in config; running in a container/air-gapped network without working DNS; DNS outage or flaky resolvers; corporate networks that require an internal resolver not visible to the process.
Understand the failure class
- DNS resolution errors: ENOTFOUND and getaddrinfo failures — how hostname lookups fail and how to debug them.
Related errors
- DNS resolution returned no addresses for %s
- fetch failed: %w
- HTTP GET: %w
- HTTP request: %w
- failed to execute request: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/49f88c1f530cc1b5.
Report an issue: GitHub.