{"record":{"id":"7fe342d62ef5031a","repo":"shadowsocks/shadowsocks-rust","slug":"invalid-dnsname-domain-7fe342","errorCode":null,"errorMessage":"invalid dnsname \"{domain}\"","messagePattern":"invalid dnsname \"(.+?)\"","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/shadowsocks-service/src/net/outbound/tls.rs","lineNumber":143,"sourceCode":"\n                for cert in certs {\n                    if let Err(err) = store.add(cert) {\n                        warn!(\"failed to add cert (native), error: {}\", err);\n                    }\n                }\n\n                store\n            })\n            .with_no_client_auth();\n\n        config.alpn_protocols = vec![b\"h2\".to_vec(), b\"http/1.1\".to_vec()];\n        Arc::new(config)\n    });\n\n    let connector = TlsConnector::from(TLS_CONFIG.clone());\n\n    let host = ServerName::try_from(domain)\n        .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, format!(\"invalid dnsname \\\"{domain}\\\"\")))?\n        .to_owned();\n\n    let tls_stream = connector.connect(host, stream).await?;\n    let (_, session) = tls_stream.get_ref();\n    let h2 = matches!(session.alpn_protocol(), Some(b\"h2\"));\n\n    Ok(OutboundTlsStream::Rustls(tls_stream, h2))\n}\n\n#[cfg(any(feature = \"local-http-native-tls\", feature = \"local-http-rustls\"))]\nmacro_rules! forward_call {\n    ($self:expr, $method:ident $(, $param:expr)*) => {\n        match $self.as_mut().project() {\n            #[cfg(all(feature = \"local-http-native-tls\", not(feature = \"local-http-rustls\")))]\n            OutboundTlsStreamProj::NativeTls(s, _) => s.$method($($param),*),\n            #[cfg(feature = \"local-http-rustls\")]\n            OutboundTlsStreamProj::Rustls(s, _) => s.$method($($param),*),\n        }","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/shadowsocks/shadowsocks-rust/blob/8eb0f0a65b1d976ab6bed5787327ef86529b0435/crates/shadowsocks-service/src/net/outbound/tls.rs#L125-L161","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Set the hop host to a bare valid DNS name (e.g. proxy.example.com) or a valid IP, with no scheme or path","Strip the scheme/port from a pasted URL so only the hostname remains in the host field","Pre-validate the hostname (non-empty, alphanumerics/hyphens/dots, or a parseable IP) before dialing"],"exampleFix":"// before\nlet hop = OutboundProxyHop { kind: OutboundProxyKind::Https { host: \"https://proxy.example.com:8443\".into(), .. } };\n// after\nlet hop = OutboundProxyHop { kind: OutboundProxyKind::Https { host: \"proxy.example.com\".into(), .. } };","handlingStrategy":"validation","validationCode":"fn valid_dns_host(host: &str) -> bool {\n    !host.is_empty()\n        && !host.contains(\"://\")\n        && host.parse::<std::net::IpAddr>().is_ok()\n        || (!host.is_empty() && host.split('.').all(|l| !l.is_empty() && l.chars().all(|c| c.is_ascii_alphanumeric() || c == '-')))\n}\nif !valid_dns_host(&hop_host) { return Err(anyhow!(\"invalid https proxy host: {hop_host}\")); }","typeGuard":"fn is_servername_ok(host: &str) -> bool {\n    rustls_pki_types::ServerName::try_from(host.to_string()).is_ok()\n}","tryCatchPattern":"match tls_connect(stream, domain).await {\n    Err(e) if e.kind() == io::ErrorKind::InvalidInput && e.to_string().starts_with(\"invalid dnsname\") => {\n        eprintln!(\"fix proxy host in config: {}\", e);\n    }\n    other => other?,\n}","preventionTips":["Store only the bare hostname in the host field — no scheme, port, or path","Reject empty hosts at config parse time","Test configs with IP literals and hostnames separately"],"tags":["tls","dns","validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"8eb0f0a65b1d976ab6bed5787327ef86529b0435","analyzedAt":"2026-09-09T12:20:43.168Z","contentChangedAt":"2026-09-09T12:20:43.168Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}