Skip to content

Commit 131962c

Browse files
chewiseanmonstar
authored andcommitted
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.
1 parent 71d088d commit 131962c

File tree

2 files changed

+32
-14
lines changed

2 files changed

+32
-14
lines changed

src/client/connect/dns.rs

+31-13
Original file line numberDiff line numberDiff line change
@@ -194,17 +194,25 @@ impl IpAddrs {
194194
None
195195
}
196196

197-
pub(super) fn split_by_preference(self) -> (IpAddrs, IpAddrs) {
198-
let preferring_v6 = self.iter
199-
.as_slice()
200-
.first()
201-
.map(SocketAddr::is_ipv6)
202-
.unwrap_or(false);
203-
204-
let (preferred, fallback) = self.iter
205-
.partition::<Vec<_>, _>(|addr| addr.is_ipv6() == preferring_v6);
206-
207-
(IpAddrs::new(preferred), IpAddrs::new(fallback))
197+
pub(super) fn split_by_preference(self, local_addr: Option<IpAddr>) -> (IpAddrs, IpAddrs) {
198+
if let Some(local_addr) = local_addr {
199+
let preferred = self.iter
200+
.filter(|addr| addr.is_ipv6() == local_addr.is_ipv6())
201+
.collect();
202+
203+
(IpAddrs::new(preferred), IpAddrs::new(vec![]))
204+
} else {
205+
let preferring_v6 = self.iter
206+
.as_slice()
207+
.first()
208+
.map(SocketAddr::is_ipv6)
209+
.unwrap_or(false);
210+
211+
let (preferred, fallback) = self.iter
212+
.partition::<Vec<_>, _>(|addr| addr.is_ipv6() == preferring_v6);
213+
214+
(IpAddrs::new(preferred), IpAddrs::new(fallback))
215+
}
208216
}
209217

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

327335
let (mut preferred, mut fallback) =
328-
IpAddrs { iter: vec![v4_addr, v6_addr].into_iter() }.split_by_preference();
336+
IpAddrs { iter: vec![v4_addr, v6_addr].into_iter() }.split_by_preference(None);
329337
assert!(preferred.next().unwrap().is_ipv4());
330338
assert!(fallback.next().unwrap().is_ipv6());
331339

332340
let (mut preferred, mut fallback) =
333-
IpAddrs { iter: vec![v6_addr, v4_addr].into_iter() }.split_by_preference();
341+
IpAddrs { iter: vec![v6_addr, v4_addr].into_iter() }.split_by_preference(None);
334342
assert!(preferred.next().unwrap().is_ipv6());
335343
assert!(fallback.next().unwrap().is_ipv4());
344+
345+
let (mut preferred, fallback) =
346+
IpAddrs { iter: vec![v4_addr, v6_addr].into_iter() }.split_by_preference(Some(v4_addr.ip()));
347+
assert!(preferred.next().unwrap().is_ipv4());
348+
assert!(fallback.is_empty());
349+
350+
let (mut preferred, fallback) =
351+
IpAddrs { iter: vec![v4_addr, v6_addr].into_iter() }.split_by_preference(Some(v6_addr.ip()));
352+
assert!(preferred.next().unwrap().is_ipv6());
353+
assert!(fallback.is_empty());
336354
}
337355

338356
#[test]

src/client/connect/http.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ impl ConnectingTcp {
501501
reuse_address: bool,
502502
) -> ConnectingTcp {
503503
if let Some(fallback_timeout) = fallback_timeout {
504-
let (preferred_addrs, fallback_addrs) = remote_addrs.split_by_preference();
504+
let (preferred_addrs, fallback_addrs) = remote_addrs.split_by_preference(local_addr);
505505
if fallback_addrs.is_empty() {
506506
return ConnectingTcp {
507507
local_addr,

0 commit comments

Comments
 (0)