Skip to content

Commit

Permalink
feat(client): filter remote IP addresses by family of given local IP …
Browse files Browse the repository at this point in the history
…address

It is not possible to connect to an IPv4 address from an IPv6 address or
vice-versa so don't waste time trying. If no remote addresses match then a
"missing connect error" will now occur.
  • Loading branch information
chewi authored and seanmonstar committed Nov 19, 2019
1 parent 71d088d commit 131962c
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 14 deletions.
44 changes: 31 additions & 13 deletions src/client/connect/dns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,17 +194,25 @@ impl IpAddrs {
None
}

pub(super) fn split_by_preference(self) -> (IpAddrs, IpAddrs) {
let preferring_v6 = self.iter
.as_slice()
.first()
.map(SocketAddr::is_ipv6)
.unwrap_or(false);

let (preferred, fallback) = self.iter
.partition::<Vec<_>, _>(|addr| addr.is_ipv6() == preferring_v6);

(IpAddrs::new(preferred), IpAddrs::new(fallback))
pub(super) fn split_by_preference(self, local_addr: Option<IpAddr>) -> (IpAddrs, IpAddrs) {
if let Some(local_addr) = local_addr {
let preferred = self.iter
.filter(|addr| addr.is_ipv6() == local_addr.is_ipv6())
.collect();

(IpAddrs::new(preferred), IpAddrs::new(vec![]))
} else {
let preferring_v6 = self.iter
.as_slice()
.first()
.map(SocketAddr::is_ipv6)
.unwrap_or(false);

let (preferred, fallback) = self.iter
.partition::<Vec<_>, _>(|addr| addr.is_ipv6() == preferring_v6);

(IpAddrs::new(preferred), IpAddrs::new(fallback))
}
}

pub(super) fn is_empty(&self) -> bool {
Expand Down Expand Up @@ -325,14 +333,24 @@ mod tests {
let v6_addr = (Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 80).into();

let (mut preferred, mut fallback) =
IpAddrs { iter: vec![v4_addr, v6_addr].into_iter() }.split_by_preference();
IpAddrs { iter: vec![v4_addr, v6_addr].into_iter() }.split_by_preference(None);
assert!(preferred.next().unwrap().is_ipv4());
assert!(fallback.next().unwrap().is_ipv6());

let (mut preferred, mut fallback) =
IpAddrs { iter: vec![v6_addr, v4_addr].into_iter() }.split_by_preference();
IpAddrs { iter: vec![v6_addr, v4_addr].into_iter() }.split_by_preference(None);
assert!(preferred.next().unwrap().is_ipv6());
assert!(fallback.next().unwrap().is_ipv4());

let (mut preferred, fallback) =
IpAddrs { iter: vec![v4_addr, v6_addr].into_iter() }.split_by_preference(Some(v4_addr.ip()));
assert!(preferred.next().unwrap().is_ipv4());
assert!(fallback.is_empty());

let (mut preferred, fallback) =
IpAddrs { iter: vec![v4_addr, v6_addr].into_iter() }.split_by_preference(Some(v6_addr.ip()));
assert!(preferred.next().unwrap().is_ipv6());
assert!(fallback.is_empty());
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion src/client/connect/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ impl ConnectingTcp {
reuse_address: bool,
) -> ConnectingTcp {
if let Some(fallback_timeout) = fallback_timeout {
let (preferred_addrs, fallback_addrs) = remote_addrs.split_by_preference();
let (preferred_addrs, fallback_addrs) = remote_addrs.split_by_preference(local_addr);
if fallback_addrs.is_empty() {
return ConnectingTcp {
local_addr,
Expand Down

0 comments on commit 131962c

Please sign in to comment.