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
- Validate the interface name (non-empty, no NUL bytes) before calling set_ip_unicast_if
- Replace expect with error propagation: CString::new(iface).map_err(...)? and log/return a config error
- Verify the interface name matches an adapter name shown by `ipconfig /all` or `netsh interface show interface`
- 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
- Validate interface names read from config for NUL/control bytes
- Use the exact adapter name from `netsh interface show interface`
- Prefer interface index or GUID where the API allows
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.