Tencent/WeKnora · error

DNS resolution returned no addresses for %s

Error message

DNS resolution returned no addresses for %s

What it means

The DNS lookup for the host succeeded but returned an empty answer set, so SSRF validation has nothing to check and the dial is refused. This is distinct from a resolver error: the resolver responded, but with zero addresses. The library treats an empty answer as a hard failure rather than falling back to the standard dialer, preserving the rebinding-free guarantee.

Source

Thrown at internal/utils/security.go:835

			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,
	}
	var lastErr error
	for _, ipAddr := range ips {
		pinnedAddr := net.JoinHostPort(ipAddr.IP.String(), port)

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Inspect the DNS zone and add proper A/AAAA records for the hostname, or point the client at a hostname that has addresses.
  2. Check whether a corporate/security resolver is empty-answering the domain and switch to the correct internal resolver.
  3. Dial the intended IP literal directly (subject to isRestrictedIP validation) if you know the address.
  4. Retry after DNS propagation if the record was just created.

Example fix

// before
conn, err := utils.SSRFSafeDialContext(ctx, "tcp", "staging-api.example.com:443") // no A record

// after
ips, err := net.LookupIP("staging-api.example.com")
if err != nil || len(ips) == 0 {
    // fix DNS or fall back to a known-good address
    return utils.SSRFSafeDialContext(ctx, "tcp", "203.0.113.10:443")
}
conn, err := utils.SSRFSafeDialContext(ctx, "tcp", "staging-api.example.com:443")
Defensive patterns

Strategy: validation

Validate before calling

ips, err := net.LookupIP(host)
if err == nil && len(ips) == 0 {
    return fmt.Errorf("hostname %s has no A/AAAA records; fix DNS or dial a literal IP", host)
}

Try / catch

conn, err := utils.SSRFSafeDialContext(ctx, "tcp", addr)
if err != nil && strings.Contains(err.Error(), "returned no addresses") {
    return nil, fmt.Errorf("no DNS addresses for %s: verify records or dial IP directly", host)
}

Prevention

When it happens

Trigger: LookupIPAddr returning no IPs — typically a name that exists but has no A/AAAA records (e.g. only CNAME to nothing, a NULL record, or a DNS64/filtering resolver returning an empty answer) — passed to SSRFSafeDialContext / SSRFSafeGRPCDialer / a transport DialContext.

Common situations: DNS entries pointing at services with missing A records; split-horizon DNS where the external view has no records; security appliances or sinkhole resolvers that return empty answers for blocked domains; recently created records not yet propagated.

Understand the failure class

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/2c2da4c8f5d5db7f. Report an issue: GitHub.