shadowsocks/shadowsocks-rust · error
Invalid IPv6 address
Error message
Invalid IPv6 address
What it means
Identical logic to the Unix variant: when creating an outbound UDP socket with IPv4 address family but a bind_local_addr that is an IPv6 address, only IPv4-mapped IPv6 addresses can be converted down to IPv4. A non-mapped IPv6 address (like "::" or a global IPv6 addr) cannot serve as an IPv4 bind address, so create_outbound_udp_socket returns ErrorKind::InvalidInput with "Invalid IPv6 address".
Source
Thrown at crates/shadowsocks/src/net/sys/windows/mod.rs:473
};
if !allow_fragmentation && let Err(err) = set_disable_ip_fragmentation(addr_family, &socket) {
warn!("failed to disable IP fragmentation, error: {}", err);
}
disable_connection_reset(&socket)?;
Ok(socket)
}
/// Create a `UdpSocket` for connecting to `addr`
#[inline(always)]
pub async fn create_outbound_udp_socket(af: AddrFamily, opts: &ConnectOpts) -> io::Result<UdpSocket> {
let bind_addr = match (af, opts.bind_local_addr) {
(AddrFamily::Ipv4, Some(SocketAddr::V4(addr))) => addr.into(),
(AddrFamily::Ipv4, Some(SocketAddr::V6(addr))) => {
// Map IPv6 bind_local_addr to IPv4 if AF is IPv4
match addr.ip().to_ipv4_mapped() {
Some(addr) => SocketAddr::new(addr.into(), 0),
None => return Err(io::Error::new(ErrorKind::InvalidInput, "Invalid IPv6 address")),
}
}
(AddrFamily::Ipv6, Some(SocketAddr::V6(addr))) => addr.into(),
(AddrFamily::Ipv6, Some(SocketAddr::V4(addr))) => {
// Map IPv4 bind_local_addr to IPv6 if AF is IPv6
SocketAddr::new(addr.ip().to_ipv6_mapped().into(), 0)
}
(AddrFamily::Ipv4, ..) => SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 0),
(AddrFamily::Ipv6, ..) => SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0),
};
bind_outbound_udp_socket(&bind_addr, opts).await
}
/// Create a `UdpSocket` binded to `bind_addr`
pub async fn bind_outbound_udp_socket(bind_addr: &SocketAddr, opts: &ConnectOpts) -> io::Result<UdpSocket> {
let af = AddrFamily::from(bind_addr);
View on GitHub (pinned to 8eb0f0a65b)
Solutions
- Set bind_local_addr to an IPv4 address (e.g. "0.0.0.0") for IPv4 outbound sockets
- Use an IPv4-mapped IPv6 literal ("::ffff:0.0.0.0") if you want to express IPv4-any in v6 form
- Remove bind_local_addr entirely to let the OS pick the source address
- Make the bind address family consistent with the server address family in your config
Example fix
# before bind_address = "::" # after bind_address = "0.0.0.0" # matches IPv4 outbound
Defensive patterns
Strategy: validation
Validate before calling
fn bind_compatible(af: shadowsocks::net::AddrFamily, bind: Option<std::net::SocketAddr>) -> bool {
match (af, bind) {
(shadowsocks::net::AddrFamily::Ipv4, Some(std::net::SocketAddr::V6(v6))) => v6.ip().to_ipv4_mapped().is_some(),
_ => true,
}
}
assert!(bind_compatible(AddrFamily::Ipv4, opts.bind_local_addr), "bind_local_addr must be IPv4 or IPv4-mapped for Ipv4 outbound"); Type guard
fn is_ipv4_usable(addr: &std::net::SocketAddr) -> bool {
match addr {
std::net::SocketAddr::V4(_) => true,
std::net::SocketAddr::V6(v6) => v6.ip().to_ipv4_mapped().is_some(),
}
} Try / catch
match create_outbound_udp_socket(context, AddrFamily::Ipv4, &opts).await {
Err(e) if e.kind() == std::io::ErrorKind::InvalidInput && e.to_string().contains("Invalid IPv6") => {
let mut fixed = opts.clone();
fixed.bind_local_addr = Some("0.0.0.0:0".parse().unwrap());
create_outbound_udp_socket(context, AddrFamily::Ipv4, &fixed).await
}
r => r,
} Prevention
- Align bind_local_addr family with the server address family in the same config
- Use "0.0.0.0" instead of "::" when the remote is IPv4
- Omit bind_local_addr unless source binding is explicitly required
- Add a config lint step for family mismatch on Windows hosts
When it happens
Trigger: create_outbound_udp_socket on Windows with AddrFamily::Ipv4 and opts.bind_local_addr set to a non-IPv4-mapped IPv6 SocketAddr, e.g. bind_local_addr = "::" while the remote server is reached over IPv4.
Common situations: Config with bind_address = "::" intending dual-stack, but remote resolves to IPv4; reusing an IPv6 bind config for an IPv4 server; environment where Windows chooses IPv4 for the outbound route.
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
- Invalid IPv6 address
- Invalid IPv6 address
- Invalid IPv6 address
- Invalid IPv6 address
- `local_udp_port` cannot be 0
AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09).
Data as JSON: /api/errors/f93ebdf8008d92e1.
Report an issue: GitHub.