Skip to content

Connecting to a dual-stack (ipv4 & ipv6 available) endpoint can return EADDRNOTAVAIL #7708

@mikekap

Description

@mikekap

Version
tokio v1.41.1 (but master is affected too)

Platform
Linux meeting-data 6.8.0-1029-aws #31~22.04.1-Ubuntu SMP Thu Apr 24 21:16:18 UTC 2025 x86_64 GNU/Linux

Description
The issue is TcpStream::connect may sometimes return EADDRNOTAVAIL (errno 99) hiding the actual error that occurred in an ipv4 connection.

When running in an ipv4-only environment (i.e. no external ipv6), getaddrinfo will happily return ipv6 addresses as well. The problem is that the code

let addrs = to_socket_addrs(addr).await?;
let mut last_err = None;
for addr in addrs {
match TcpStream::connect_addr(addr).await {
Ok(stream) => return Ok(stream),
Err(e) => last_err = Some(e),
}
}
Err(last_err.unwrap_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"could not resolve to any address",
)
}))
returns the LAST error encountered. So to trigger EADDRNOTAVAIL, you need:

  • getaddrinfo returns [IPV4, IPv6] in that order
  • Attempt to connect to IPV4 yields an actual network error (e.g. timeout, connection refused)
  • The code attempts an IPV6 connection.
  • The IPV6 connection fails with EADDRNOTAVAIL since the host doesn't have external IPv6 support enabled.
  • The last error wins, so instead of a "connection refused" message, you get a "cannot assign requested address"

For reference for others, one fix for this is to disable returning ipv6 addresses - add options no-aaaa to /etc/resolv.conf.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-tokioArea: The main tokio crateC-bugCategory: This is a bug.M-netModule: tokio/net

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions