diff --git a/src/client/legacy/connect/dns.rs b/src/client/legacy/connect/dns.rs index ca041274..f8eb07ed 100644 --- a/src/client/legacy/connect/dns.rs +++ b/src/client/legacy/connect/dns.rs @@ -212,14 +212,28 @@ impl SocketAddrs { SocketAddrs::new(self.iter.filter(predicate).collect()) } + pub(super) fn filter_by_local_address( + self, + local_addr_ipv4: Option, + local_addr_ipv6: Option, + ) -> SocketAddrs { + match (local_addr_ipv4, local_addr_ipv6) { + (Some(_), None) => self.filter(SocketAddr::is_ipv4), + (None, Some(_)) => self.filter(SocketAddr::is_ipv6), + _ => self, + } + } + pub(super) fn split_by_preference( self, local_addr_ipv4: Option, local_addr_ipv6: Option, ) -> (SocketAddrs, SocketAddrs) { match (local_addr_ipv4, local_addr_ipv6) { - (Some(_), None) => (self.filter(SocketAddr::is_ipv4), SocketAddrs::new(vec![])), - (None, Some(_)) => (self.filter(SocketAddr::is_ipv6), SocketAddrs::new(vec![])), + (Some(_), None) | (None, Some(_)) => ( + self.filter_by_local_address(local_addr_ipv4, local_addr_ipv6), + SocketAddrs::new(vec![]), + ), _ => { let preferring_v6 = self .iter diff --git a/src/client/legacy/connect/http.rs b/src/client/legacy/connect/http.rs index 745ba306..2b27b79a 100644 --- a/src/client/legacy/connect/http.rs +++ b/src/client/legacy/connect/http.rs @@ -750,7 +750,13 @@ impl<'a> ConnectingTcp<'a> { } } else { ConnectingTcp { - preferred: ConnectingTcpRemote::new(remote_addrs, config.connect_timeout), + preferred: ConnectingTcpRemote::new( + remote_addrs.filter_by_local_address( + config.local_address_ipv4, + config.local_address_ipv6, + ), + config.connect_timeout, + ), fallback: None, config, } @@ -1132,6 +1138,26 @@ mod tests { } } + #[tokio::test] + async fn local_address_filters_incompatible_remote_addrs_without_happy_eyeballs() { + use std::net::TcpListener; + + let server = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = server.local_addr().unwrap().port(); + + let mut connector = HttpConnector::new(); + connector.set_local_address(Some("::1".parse().unwrap())); + connector.set_happy_eyeballs_timeout(None); + + let err = connect( + connector, + format!("http://127.0.0.1:{port}").parse().unwrap(), + ) + .await + .unwrap_err(); + assert_eq!(&*err.msg, "tcp connect error"); + } + // NOTE: pnet crate that we use in this test doesn't compile on Windows #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] #[tokio::test]