shadowsocks/shadowsocks-rust · error

dns

Error message

dns

What it means

The manager service passes the `--dns` CLI value to `config.set_dns_formatted(dns).expect("dns")`. The panic means the DNS configuration string is malformed. `set_dns_formatted` accepts either a simple DNS server address (e.g. `8.8.8.8` / `[::1]:53`) or a JSON-formatted DNS config object, and rejects anything it cannot parse.

Source

Thrown at src/service/manager.rs:426

            && let Some(ref mut m) = config.manager
        {
            m.mode = Mode::UdpOnly;
        }

        if matches.get_flag("TCP_AND_UDP")
            && let Some(ref mut m) = config.manager
        {
            m.mode = Mode::TcpAndUdp;
        }

        if let Some(acl_file) = matches.get_one::<String>("ACL") {
            let acl = AccessControl::load_from_file(acl_file)
                .map_err(|err| ShadowsocksError::LoadAclFailure(format!("loading ACL \"{acl_file}\", {err}")))?;
            config.acl = Some(acl);
        }

        if let Some(dns) = matches.get_one::<String>("DNS") {
            config.set_dns_formatted(dns).expect("dns");
        }

        if let Some(dns_cache_size) = matches.get_one::<usize>("DNS_CACHE_SIZE") {
            config.dns_cache_size = Some(*dns_cache_size);
        }

        if matches.get_flag("IPV6_FIRST") {
            config.ipv6_first = true;
        }

        if let Some(udp_timeout) = matches.get_one::<u64>("UDP_TIMEOUT") {
            config.udp_timeout = Some(Duration::from_secs(*udp_timeout));
        }

        if let Some(udp_max_assoc) = matches.get_one::<usize>("UDP_MAX_ASSOCIATIONS") {
            config.udp_max_associations = Some(*udp_max_assoc);
        }

View on GitHub (pinned to 8eb0f0a65b)

Solutions

  1. Pass a plain nameserver like `--dns 8.8.8.8` or `--dns "1.1.1.1:53"`
  2. If using the JSON form, validate it with `jq` first: ensure it matches shadowsocks Config dns format
  3. Quote the whole JSON value properly for your shell
  4. Move complex DNS config into the config file instead of the CLI flag

Example fix

// before
--dns "dns://8.8.8.8"
// after
--dns "8.8.8.8:53"
Defensive patterns

Strategy: validation

Validate before calling

use std::net::ToSocketAddrs;
fn valid_dns_value(v: &str) -> bool {
    v.to_socket_addrs().is_ok() || serde_json::from_str::<serde_json::Value>(v).is_ok()
}

Type guard

null

Try / catch

// mirror the library call with error reporting
if let Err(e) = config.set_dns_formatted(dns) {
    eprintln!("invalid --dns value {dns:?}: {e}");
    std::process::exit(2);
}

Prevention

When it happens

Trigger: Passing `--dns` with a value that is neither a valid nameserver address (missing port with unparseable format, bad IP) nor valid JSON DNS config (malformed `"[\"8.8.8.8\", ...]"`-style strings, wrong keys).

Common situations: Hand-writing JSON DNS configs with quoting mistakes on the shell, using `dns://` URLs or resolv.conf paths which this API doesn't accept, typos in IP addresses.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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