IPv6 Support (Implement Happy Eyeballs) #268

Closed
opened 2023-08-01 03:35:33 +03:00 by s3lph · 4 comments

Description

I've recently tried out meli and found it to be the best CLI mail client I've encountered so far. However, I spend most of my time on IPv6-only networks (yes, they exist!), and meli does not manage to establish connections to my dual-stack IMAP servers, rendering it unusable for me.

I tracked down what's happening; it all comes down to this function:

melib/src/utils/connections.rs:497:

pub fn lookup_ip(host: &str, port: u16) -> crate::Result<std::net::SocketAddr> {
    use std::net::ToSocketAddrs;

    use crate::error::{Error, ErrorKind, NetworkErrorKind};

    let addrs = (host, port).to_socket_addrs()?;
    for addr in addrs {
        if matches!(
            addr,
            std::net::SocketAddr::V4(_) | std::net::SocketAddr::V6(_)
        ) {
            return Ok(addr);
        }
    }

    Err(
        Error::new(format!("Could not lookup address {}:{}", host, port))
            .set_kind(ErrorKind::Network(NetworkErrorKind::HostLookupFailed)),
    )
}

While it does iterate the DNS responses to check for v4 and v6, it only ever returns the first result, which (at least for me) always is the IPv4 address.

Observed Behavior

meli only ever connects to the first address returned by the DNS lookup, which always is an IPv4 address, unless there only is an AAAA record.

Expected Behavior

meli should implement RFC 6555 ("Happy Eyeballs"), and attempt to establish a connection using both IPv6 and IPv4.

There is a crate called happy-eyeballs, which from a cursory glance should be able to simply replace your calls to lookup_ip followed by connect; according to the documentation it can simply replace TcpStream::connect and takes a hostname + port as arguments. Though apparently it doesn't implement connect_timeout yet.

## Description I've recently tried out meli and found it to be the best CLI mail client I've encountered so far. However, I spend most of my time on IPv6-only networks (yes, they exist!), and meli does not manage to establish connections to my dual-stack IMAP servers, rendering it unusable for me. I tracked down what's happening; it all comes down to this function: `melib/src/utils/connections.rs:497`: ```rust pub fn lookup_ip(host: &str, port: u16) -> crate::Result<std::net::SocketAddr> { use std::net::ToSocketAddrs; use crate::error::{Error, ErrorKind, NetworkErrorKind}; let addrs = (host, port).to_socket_addrs()?; for addr in addrs { if matches!( addr, std::net::SocketAddr::V4(_) | std::net::SocketAddr::V6(_) ) { return Ok(addr); } } Err( Error::new(format!("Could not lookup address {}:{}", host, port)) .set_kind(ErrorKind::Network(NetworkErrorKind::HostLookupFailed)), ) } ``` While it does iterate the DNS responses to check for v4 and v6, it only ever returns the first result, which (at least for me) always is the IPv4 address. ## Observed Behavior meli only ever connects to the first address returned by the DNS lookup, which always is an IPv4 address, unless there only is an `AAAA` record. ## Expected Behavior meli should implement RFC 6555 ("Happy Eyeballs"), and attempt to establish a connection using both IPv6 and IPv4. There is a crate called [happy-eyeballs](https://docs.rs/happy-eyeballs/latest/happy_eyeballs/), which from a cursory glance should be able to simply replace your calls to `lookup_ip` followed by `connect`; according to the documentation it can simply replace `TcpStream::connect` and takes a hostname + port as arguments. Though apparently [it doesn't implement `connect_timeout` yet](https://codeberg.org/KMK/happy-eyeballs/issues/1).

@s3lph thanks a lot for the issue and well written explanations and solution! I had forgotten about happy eyeballs. happy-eyeballs crate seems small, perhaps it'd be better to just implement it in our source tree instead of adding yet another dependency.

@s3lph thanks a lot for the issue and well written explanations and solution! I had forgotten about happy eyeballs. `happy-eyeballs` crate seems small, perhaps it'd be better to just implement it in our source tree instead of adding yet another dependency.
Manos Pitsidianakis added the
enhancement
User Experience
labels 2023-08-05 16:21:26 +03:00

@s3lph I'm back home so I will start working on this asap.

@s3lph I'm back home so I will start working on this asap.

Update: I made an implementation, all the servers I tried work except for gmail's. It gives me "network unreachable", might be a problem on my end. I will investigate further.

Update: I made an implementation, all the servers I tried work except for gmail's. It gives me "network unreachable", might be a problem on my end. I will investigate further.

@s3lph the happy-eyeballs crate seems to be using sockets wrong 🤔 It calls connect, gets EINPROGRESS and then calls connect again when polling. Linux doesn't care about that but Macos returns EISCONN The socket is already connected. Both platforms suggest selecting the socket for writability instead. I will try that.

@s3lph the happy-eyeballs crate seems to be using sockets wrong 🤔 It calls `connect`, gets `EINPROGRESS` and then calls `connect` again when polling. Linux doesn't care about that but Macos returns `EISCONN The socket is already connected.` Both platforms suggest `select`ing the socket for writability instead. I will try that.
Sign in to join this conversation.
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: meli/meli#268
There is no content yet.