feat(client): filter remote IP addresses by family of given local IP 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.
This commit is contained in:
committed by
Sean McArthur
parent
71d088d3d0
commit
131962c86a
@@ -194,17 +194,25 @@ impl IpAddrs {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn split_by_preference(self) -> (IpAddrs, IpAddrs) {
|
pub(super) fn split_by_preference(self, local_addr: Option<IpAddr>) -> (IpAddrs, IpAddrs) {
|
||||||
let preferring_v6 = self.iter
|
if let Some(local_addr) = local_addr {
|
||||||
.as_slice()
|
let preferred = self.iter
|
||||||
.first()
|
.filter(|addr| addr.is_ipv6() == local_addr.is_ipv6())
|
||||||
.map(SocketAddr::is_ipv6)
|
.collect();
|
||||||
.unwrap_or(false);
|
|
||||||
|
|
||||||
let (preferred, fallback) = self.iter
|
(IpAddrs::new(preferred), IpAddrs::new(vec![]))
|
||||||
.partition::<Vec<_>, _>(|addr| addr.is_ipv6() == preferring_v6);
|
} else {
|
||||||
|
let preferring_v6 = self.iter
|
||||||
|
.as_slice()
|
||||||
|
.first()
|
||||||
|
.map(SocketAddr::is_ipv6)
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
(IpAddrs::new(preferred), IpAddrs::new(fallback))
|
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 {
|
pub(super) fn is_empty(&self) -> bool {
|
||||||
@@ -325,14 +333,24 @@ mod tests {
|
|||||||
let v6_addr = (Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 80).into();
|
let v6_addr = (Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 80).into();
|
||||||
|
|
||||||
let (mut preferred, mut fallback) =
|
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!(preferred.next().unwrap().is_ipv4());
|
||||||
assert!(fallback.next().unwrap().is_ipv6());
|
assert!(fallback.next().unwrap().is_ipv6());
|
||||||
|
|
||||||
let (mut preferred, mut fallback) =
|
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!(preferred.next().unwrap().is_ipv6());
|
||||||
assert!(fallback.next().unwrap().is_ipv4());
|
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]
|
#[test]
|
||||||
|
|||||||
@@ -501,7 +501,7 @@ impl ConnectingTcp {
|
|||||||
reuse_address: bool,
|
reuse_address: bool,
|
||||||
) -> ConnectingTcp {
|
) -> ConnectingTcp {
|
||||||
if let Some(fallback_timeout) = fallback_timeout {
|
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() {
|
if fallback_addrs.is_empty() {
|
||||||
return ConnectingTcp {
|
return ConnectingTcp {
|
||||||
local_addr,
|
local_addr,
|
||||||
|
|||||||
Reference in New Issue
Block a user