shadowsocks/shadowsocks-rust · error

invalid dnsname "{domain}"

Error message

invalid dnsname "{domain}"

What it means

tls_connect_inner builds a rustls TlsConnector and must convert the proxy hostname into a rustls ServerName. If the domain fails ServerName::try_from (empty string, contains invalid characters, is not a valid DNS name or IP), the connection is rejected with InvalidInput carrying the offending domain.

Source

Thrown at crates/shadowsocks-service/src/net/outbound/tls.rs:143

                for cert in certs {
                    if let Err(err) = store.add(cert) {
                        warn!("failed to add cert (native), error: {}", err);
                    }
                }

                store
            })
            .with_no_client_auth();

        config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
        Arc::new(config)
    });

    let connector = TlsConnector::from(TLS_CONFIG.clone());

    let host = ServerName::try_from(domain)
        .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, format!("invalid dnsname \"{domain}\"")))?
        .to_owned();

    let tls_stream = connector.connect(host, stream).await?;
    let (_, session) = tls_stream.get_ref();
    let h2 = matches!(session.alpn_protocol(), Some(b"h2"));

    Ok(OutboundTlsStream::Rustls(tls_stream, h2))
}

#[cfg(any(feature = "local-http-native-tls", feature = "local-http-rustls"))]
macro_rules! forward_call {
    ($self:expr, $method:ident $(, $param:expr)*) => {
        match $self.as_mut().project() {
            #[cfg(all(feature = "local-http-native-tls", not(feature = "local-http-rustls")))]
            OutboundTlsStreamProj::NativeTls(s, _) => s.$method($($param),*),
            #[cfg(feature = "local-http-rustls")]
            OutboundTlsStreamProj::Rustls(s, _) => s.$method($($param),*),
        }

View on GitHub (pinned to 8eb0f0a65b)

Solutions

  1. Set the hop host to a bare valid DNS name (e.g. proxy.example.com) or a valid IP, with no scheme or path
  2. Strip the scheme/port from a pasted URL so only the hostname remains in the host field
  3. Pre-validate the hostname (non-empty, alphanumerics/hyphens/dots, or a parseable IP) before dialing

Example fix

// before
let hop = OutboundProxyHop { kind: OutboundProxyKind::Https { host: "https://proxy.example.com:8443".into(), .. } };
// after
let hop = OutboundProxyHop { kind: OutboundProxyKind::Https { host: "proxy.example.com".into(), .. } };
Defensive patterns

Strategy: validation

Validate before calling

fn valid_dns_host(host: &str) -> bool {
    !host.is_empty()
        && !host.contains("://")
        && host.parse::<std::net::IpAddr>().is_ok()
        || (!host.is_empty() && host.split('.').all(|l| !l.is_empty() && l.chars().all(|c| c.is_ascii_alphanumeric() || c == '-')))
}
if !valid_dns_host(&hop_host) { return Err(anyhow!("invalid https proxy host: {hop_host}")); }

Type guard

fn is_servername_ok(host: &str) -> bool {
    rustls_pki_types::ServerName::try_from(host.to_string()).is_ok()
}

Try / catch

match tls_connect(stream, domain).await {
    Err(e) if e.kind() == io::ErrorKind::InvalidInput && e.to_string().starts_with("invalid dnsname") => {
        eprintln!("fix proxy host in config: {}", e);
    }
    other => other?,
}

Prevention

When it happens

Trigger: An https outbound proxy hop is configured with a host string rustls cannot parse as a DNS name — empty host, underscores, scheme prefixes like `https://` left in the host field, IPv6 without brackets, or trailing whitespace/dot issues.

Common situations: Users paste the full proxy URL into the host field; config uses a hostname with illegal characters; empty host field after env-var expansion failed; IP literal formatting mistakes.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09). Data as JSON: /api/errors/7fe342d62ef5031a. Report an issue: GitHub.