Tencent/WeKnora · error

connection blocked: %s resolves to restricted IP %s (%s)

Error message

connection blocked: %s resolves to restricted IP %s (%s)

What it means

After resolving the hostname, SSRFSafeDialContext validates every returned IP with isRestrictedIP; if any answer is private, loopback, link-local, metadata, or otherwise restricted, the whole dial is blocked. This closes DNS-rebinding attacks where a public name resolves to an internal address. The reason string in the message names the specific restricted category.

Source

Thrown at internal/utils/security.go:841

		}
	}

	// 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)
		conn, dialErr := dialer.DialContext(ctx, network, pinnedAddr)
		if dialErr == nil {
			return conn, nil
		}
		lastErr = dialErr
	}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Read the reason in the error to see which restricted class fired, then verify the DNS records for the host and remove any pointing at private/loopback/metadata space.
  2. If the host is legitimately internal and trusted, add it to the SSRF whitelist so dial-time IP checks are bypassed for it.
  3. If you suspect rebinding/abuse, treat it as a security event: audit who configured the record and block the domain.
  4. Dial the specific public IP literal if you know the correct address and it passes isRestrictedIP.

Example fix

// before
// evil.example.com resolves to 169.254.169.254
conn, err := utils.SSRFSafeDialContext(ctx, "tcp", "evil.example.com:80")

// after
// correct the DNS record to a public IP, then dial
conn, err := utils.SSRFSafeDialContext(ctx, "tcp", "api.example.com:443") // or whitelist trusted internal host
Defensive patterns

Strategy: validation

Validate before calling

ips, _ := net.LookupIP(host)
for _, ip := range ips {
    if restricted, reason := utils.IsRestrictedIPCheck(ip); restricted { // or reuse library's isRestrictedIP via exported helper
        return fmt.Errorf("%s resolves to restricted IP (%s); fix DNS or whitelist host", host, reason)
    }
}

Try / catch

conn, err := utils.SSRFSafeDialContext(ctx, "tcp", addr)
if err != nil && strings.Contains(err.Error(), "resolves to restricted IP") {
    // do NOT retry — treat as either misconfigured DNS or an SSRF attempt; alert and fail closed
    return nil, fmt.Errorf("possible DNS rebinding or internal-target attempt: %w", err)
}

Prevention

When it happens

Trigger: A hostname whose DNS answer includes any restricted IP (e.g. resolves to 127.0.0.1, 10.x/172.16.x/192.168.x, 169.254.169.254, or IPv6 equivalents) dialed through SSRFSafeDialContext / SSRFSafeGRPCDialer without a whitelist entry; malicious or misconfigured DNS records; hosts legitimately dual-homed onto private ranges.

Common situations: Attack or misconfiguration where a public domain points at 169.254.169.254 (metadata SSRF attempt); internal services whose DNS returns private IPs to the guarded client; VPN/split-horizon setups where the same name yields private answers internally.

Related errors


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