shadowsocks/shadowsocks-rust · error

iface

Error message

iface

What it means

On Windows, when resolving an interface name to an index for IP_UNICAST_IF, the code first tries GetAdaptersAddresses; failing that, it calls if_nametoindex with the interface name converted via CString::new().expect("iface"). CString::new fails when the string contains an interior NUL byte, so an interface name with '\0' panics instead of producing a user-facing error.

Source

Thrown at crates/shadowsocks/src/net/sys/windows/mod.rs:283

        static INTERFACE_INDEX_CACHE: RefCell<HashMap<String, (u32, Instant)>> =
            RefCell::new(HashMap::new());
    }

    let cache_index = INTERFACE_INDEX_CACHE.with(|cache| cache.borrow().get(iface).cloned());
    if let Some((idx, insert_time)) = cache_index {
        // short-path, cache hit for most cases
        let now = Instant::now();
        if now - insert_time < INDEX_EXPIRE_DURATION {
            return Ok(idx);
        }
    }

    // Get from API GetAdaptersAddresses
    let idx = match find_adapter_interface_index(addr, iface)? {
        Some(idx) => idx,
        None => unsafe {
            // Windows if_nametoindex requires a C-string for interface name
            let ifname = CString::new(iface).expect("iface");

            // https://docs.microsoft.com/en-us/previous-versions/windows/hardware/drivers/ff553788(v=vs.85)
            let if_index = if_nametoindex(ifname.as_ptr() as PCSTR);
            if if_index == 0 {
                // If the if_nametoindex function fails and returns zero, it is not possible to determine an error code.
                error!("if_nametoindex {} fails", iface);
                return Err(io::Error::new(ErrorKind::InvalidInput, "invalid interface name"));
            }

            if_index
        },
    };

    INTERFACE_INDEX_CACHE.with(|cache| {
        cache.borrow_mut().insert(iface.to_owned(), (idx, Instant::now()));
    });

    Ok(idx)

View on GitHub (pinned to 8eb0f0a65b)

Solutions

  1. Validate the interface name (non-empty, no NUL bytes) before calling set_ip_unicast_if
  2. Replace expect with error propagation: CString::new(iface).map_err(...)? and log/return a config error
  3. Verify the interface name matches an adapter name shown by `ipconfig /all` or `netsh interface show interface`
  4. If GetAdaptersAddresses already failed, prefer surfacing that error rather than falling through to if_nametoindex with unvalidated input

Example fix

// before
let ifname = CString::new(iface).expect("iface");
// after
let ifname = CString::new(iface).map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, format!("invalid interface name: {:?}", iface)))?;
Defensive patterns

Strategy: validation

Validate before calling

fn valid_iface(name: &str) -> bool { !name.is_empty() && !name.contains('\0') && name.len() < IFNAMSIZ }

Type guard

fn sanitize_iface(name: &str) -> Option<CString> { CString::new(name).ok() }

Try / catch

let ifname = CString::new(iface).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;

Prevention

When it happens

Trigger: Calling set_ip_unicast_if with an interface name containing a NUL byte (corrupt config value, incorrectly parsed CLI argument), after GetAdaptersAddresses could not find the adapter.

Common situations: Config files with mangled/escaped interface names on Windows; binary garbage read into the iface field; users specifying a GUID or description instead of the interface name so adapter lookup fails and the CString path runs on bad input.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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