hyper_system_resolver/
system.rs1use std::{io, net::SocketAddr, vec};
4
5use dns_lookup::AddrInfoHints;
6use hyper_util::client::legacy::connect::dns::Name;
7use tokio::task::JoinHandle;
8
9use crate::background;
10
11#[derive(Debug, Builder, Default, Clone)]
17pub struct System {
18 pub addr_info_hints: Option<AddrInfoHints>,
25
26 pub service: Option<String>,
35}
36
37impl background::Resolve for System {
38 type Iter = vec::IntoIter<SocketAddr>;
39
40 fn resolve(&mut self, name: Name) -> JoinHandle<io::Result<Self::Iter>> {
41 let addr_info_hints = self.addr_info_hints;
42 let service = self.service.clone();
43 tokio::task::spawn_blocking(move || {
44 debug!("resolving host={:?} service={:?}", name, service);
45
46 let iter =
47 dns_lookup::getaddrinfo(Some(name.as_str()), service.as_deref(), addr_info_hints)?;
48 let list = iter
49 .map(|result| result.map(|addr_info| addr_info.sockaddr))
50 .collect::<Result<Vec<_>, _>>()?;
51 Ok(list.into_iter())
52 })
53 }
54}
55
56pub type Resolver = background::Resolver<System>;
58
59impl System {
60 pub fn resolver(self) -> Resolver {
62 Resolver::new(self)
63 }
64}
65
66impl From<System> for Resolver {
67 fn from(system: System) -> Self {
68 system.resolver()
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use std::{
75 net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6},
76 str::FromStr,
77 };
78
79 use tower_service::Service;
80
81 use super::*;
82
83 #[tokio::test]
84 async fn test_resolve_ipv4() {
85 let mut resolver = background::Resolver::new(System {
86 addr_info_hints: Some(AddrInfoHints {
87 address: dns_lookup::AddrFamily::Inet.into(),
88 ..Default::default()
89 }),
90 service: None,
91 });
92
93 let addrs: Vec<_> = resolver
94 .call(Name::from_str("localhost").unwrap())
95 .await
96 .unwrap()
97 .collect();
98
99 let localhost = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 0));
100
101 assert!(!addrs.is_empty());
102 for addr in addrs {
103 assert_eq!(addr, localhost);
104 }
105 }
106
107 #[tokio::test]
108 async fn test_resolve_ipv6() {
109 let mut resolver = background::Resolver::new(System {
110 addr_info_hints: Some(AddrInfoHints {
111 address: dns_lookup::AddrFamily::Inet6.into(),
112 ..Default::default()
113 }),
114 service: None,
115 });
116
117 let addrs: Vec<_> = resolver
118 .call(Name::from_str("localhost").unwrap())
119 .await
120 .unwrap()
121 .collect();
122
123 let localhost = SocketAddr::V6(SocketAddrV6::new(
124 Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1),
125 0,
126 0,
127 0,
128 ));
129
130 assert!(!addrs.is_empty());
131 for addr in addrs {
132 assert_eq!(addr, localhost);
133 }
134 }
135}