shadowsocks/shadowsocks-rust · error
invalid dnsname "{domain}"
Error message
invalid dnsname "{domain}" What it means
connect_https builds a rustls TLS connection and must construct a rustls ServerName from the target domain. If the string is not a valid DNS name (empty, contains invalid characters, is an IP literal in a form rustls rejects, or has trailing dots), it returns InvalidInput with 'invalid dnsname'.
Source
Thrown at crates/shadowsocks-service/src/net/http_stream.rs:104
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 = match ServerName::try_from(domain) {
Ok(n) => n,
Err(_) => {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("invalid dnsname \"{domain}\""),
));
}
};
let tls_stream = connector.connect(host.to_owned(), stream).await?;
let (_, session) = tls_stream.get_ref();
let negotiated_http2 = matches!(session.alpn_protocol(), Some(b"h2"));
Ok(Self::Https(tls_stream, negotiated_http2))
}
pub fn negotiated_http2(&self) -> bool {
match *self {
Self::Http(..) => false,
#[cfg(any(feature = "local-http-native-tls", feature = "local-http-rustls"))]View on GitHub (pinned to 8eb0f0a65b)
Solutions
- Extract and pass only the bare hostname (strip scheme, port, brackets for IPv6)
- Convert IDN to punycode (ASCII) before connecting
- If the target is an IP address, upgrade to a rustls version supporting IP ServerName or use a TLS stack path that accepts IPs
- Validate/trim the host string before calling connect_https
- Log the offending domain to spot config or parsing mistakes
Example fix
// before let domain = "https://Example.com:443"; connect_https(domain).await?; // after let domain = "example.com"; // bare, lowercase, punycoded host connect_https(domain).await?;
Defensive patterns
Strategy: validation
Validate before calling
fn is_valid_dnsname(host: &str) -> bool {
!host.is_empty() && host.len() <= 253
&& host.split('.').all(|l| !l.is_empty() && l.len() <= 63
&& l.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'-'))
} Type guard
fn parse_server_name(host: &str) -> Option<rustls::pki_types::ServerName<'static>> {
rustls::pki_types::ServerName::try_from(host.to_string()).ok() } Try / catch
match connect_https(domain).await { Err(e) if e.kind()==InvalidInput && e.to_string().contains("invalid dnsname") => bail!("bad host in config: {domain}"), r => r } Prevention
- Strip scheme/port/brackets before passing hosts
- Punycode internationalized domains
- Use bare hostnames from URL parsing libraries (url::Url::host_str)
- Upgrade rustls if you must TLS-connect to raw IP addresses
When it happens
Trigger: Calling connect_https with a domain that fails ServerName::try_from: empty string, non-ASCII/IDN not pre-punycoded, embedded whitespace or control chars, IP address string (older rustls rejected IP ServerName), or names >253 chars.
Common situations: Proxy targets taken from URLs without proper host extraction (keeping scheme or port in the host), internationalized domain names not converted to punycode, IPv6 literal hosts like '[::1]' passed with brackets, or empty host from malformed config.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- invalid dnsname "{domain}"
- `local_dns_address` invalid
- tun destination must not be an domain name address
- failed to create ServerConfig, error: {}
- missing `addr` in configuration
AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09).
Data as JSON: /api/errors/d737c11ed87bc16c.
Report an issue: GitHub.