1//! Looking up host names.
23use crate::base::iana::Rtype;
4use crate::base::message::RecordIter;
5use crate::base::name::{ParsedDname, ToDname, ToRelativeDname};
6use crate::rdata::{Aaaa, A};
7use crate::resolv::resolver::{Resolver, SearchNames};
8use octseq::octets::Octets;
9use std::io;
10use std::net::{IpAddr, SocketAddr, ToSocketAddrs};
1112//------------ lookup_host ---------------------------------------------------
1314/// Creates a future that resolves a host name into its IP addresses.
15///
16/// The future will use the resolver given in `resolv` to query the
17/// DNS for the IPv4 and IPv6 addresses associated with `name`.
18///
19/// The value returned upon success can be turned into an iterator over
20/// IP addresses or even socket addresses. Since the lookup may determine that
21/// the host name is in fact an alias for another name, the value will also
22/// return the canonical name.
23pub async fn lookup_host<R: Resolver>(
24 resolver: &R,
25 qname: impl ToDname,
26) -> Result<FoundHosts<R>, io::Error> {
27let (a, aaaa) = tokio::join!(
28 resolver.query((&qname, Rtype::A)),
29 resolver.query((&qname, Rtype::Aaaa)),
30 );
31 FoundHosts::new(aaaa, a)
32}
3334//------------ search_host ---------------------------------------------------
3536pub async fn search_host<R: Resolver + SearchNames>(
37 resolver: &R,
38 qname: impl ToRelativeDname,
39) -> Result<FoundHosts<R>, io::Error> {
40for suffix in resolver.search_iter() {
41if let Ok(name) = (&qname).chain(suffix) {
42if let Ok(answer) = lookup_host(resolver, name).await {
43if !answer.is_empty() {
44return Ok(answer);
45 }
46 }
47 }
48 }
49 lookup_host(resolver, qname.chain_root()).await
50}
5152//------------ FoundHosts ----------------------------------------------------
5354/// The value returned by a successful host lookup.
55///
56/// You can use the `iter()` method to get an iterator over the IP addresses
57/// or `port_iter()` to get an iterator over socket addresses with the given
58/// port.
59///
60/// The `canonical_name()` method returns the canonical name of the host for
61/// which the addresses were found.
62#[derive(Debug)]
63pub struct FoundHosts<R: Resolver> {
64/// The answer to the AAAA query.
65aaaa: Result<R::Answer, io::Error>,
6667/// The answer to the A query.
68a: Result<R::Answer, io::Error>,
69}
7071impl<R: Resolver> FoundHosts<R> {
72pub fn new(
73 aaaa: Result<R::Answer, io::Error>,
74 a: Result<R::Answer, io::Error>,
75 ) -> Result<Self, io::Error> {
76if aaaa.is_err() && a.is_err() {
77match aaaa {
78Err(err) => return Err(err),
79_ => unreachable!(),
80 }
81 }
8283Ok(FoundHosts { aaaa, a })
84 }
8586pub fn is_empty(&self) -> bool {
87if let Ok(ref aaaa) = self.aaaa {
88if aaaa.as_ref().header_counts().ancount() > 0 {
89return false;
90 }
91 }
92if let Ok(ref a) = self.a {
93if a.as_ref().header_counts().ancount() > 0 {
94return false;
95 }
96 }
97true
98}
99100/// Returns a reference to one of the answers.
101fn answer(&self) -> &R::Answer {
102match self.aaaa.as_ref() {
103Ok(answer) => answer,
104Err(_) => self.a.as_ref().unwrap(),
105 }
106 }
107}
108109impl<R: Resolver> FoundHosts<R>
110where
111R::Octets: Octets,
112{
113pub fn qname(&self) -> ParsedDname<<R::Octets as Octets>::Range<'_>> {
114self.answer()
115 .as_ref()
116 .first_question()
117 .unwrap()
118 .into_qname()
119 }
120121/// Returns a reference to the canonical name for the host.
122 ///
123 /// # Notes
124 ///
125 /// This method expects the canonical name to be same in both A/AAAA
126 /// responses, if it isn't, it's going to return a canonical name for
127 /// one of them.
128pub fn canonical_name(
129&self,
130 ) -> ParsedDname<<R::Octets as Octets>::Range<'_>> {
131self.answer().as_ref().canonical_name().unwrap()
132 }
133134/// Returns an iterator over the IP addresses returned by the lookup.
135pub fn iter(&self) -> FoundHostsIter {
136 FoundHostsIter {
137 aaaa_name: self
138.aaaa
139 .as_ref()
140 .ok()
141 .and_then(|msg| msg.as_ref().for_slice().canonical_name()),
142 a_name: self
143.a
144 .as_ref()
145 .ok()
146 .and_then(|msg| msg.as_ref().for_slice().canonical_name()),
147 aaaa: {
148self.aaaa
149 .as_ref()
150 .ok()
151 .and_then(|msg| msg.as_ref().for_slice().answer().ok())
152 .map(|answer| answer.limit_to::<Aaaa>())
153 },
154 a: {
155self.a
156 .as_ref()
157 .ok()
158 .and_then(|msg| msg.as_ref().for_slice().answer().ok())
159 .map(|answer| answer.limit_to::<A>())
160 },
161 }
162 }
163164/// Returns an iterator over socket addresses gained from the lookup.
165 ///
166 /// The socket addresses are gained by combining the IP addresses with
167 /// `port`. The returned iterator implements `ToSocketAddrs` and thus
168 /// can be used where `std::net` wants addresses right away.
169pub fn port_iter(&self, port: u16) -> FoundHostsSocketIter {
170 FoundHostsSocketIter {
171 iter: self.iter(),
172 port,
173 }
174 }
175}
176177//------------ FoundHostsIter ------------------------------------------------
178179/// An iterator over the IP addresses returned by a host lookup.
180#[derive(Clone)]
181pub struct FoundHostsIter<'a> {
182 aaaa_name: Option<ParsedDname<&'a [u8]>>,
183 a_name: Option<ParsedDname<&'a [u8]>>,
184 aaaa: Option<RecordIter<'a, [u8], Aaaa>>,
185 a: Option<RecordIter<'a, [u8], A>>,
186}
187188impl<'a> Iterator for FoundHostsIter<'a> {
189type Item = IpAddr;
190191fn next(&mut self) -> Option<IpAddr> {
192while let Some(res) = self.aaaa.as_mut().and_then(Iterator::next) {
193if let Ok(record) = res {
194if Some(record.owner()) == self.aaaa_name.as_ref() {
195return Some(record.data().addr().into());
196 }
197 }
198 }
199while let Some(res) = self.a.as_mut().and_then(Iterator::next) {
200if let Ok(record) = res {
201if Some(record.owner()) == self.a_name.as_ref() {
202return Some(record.data().addr().into());
203 }
204 }
205 }
206None
207}
208}
209210//------------ FoundHostsSocketIter ------------------------------------------
211212/// An iterator over socket addresses derived from a host lookup.
213#[derive(Clone)]
214pub struct FoundHostsSocketIter<'a> {
215 iter: FoundHostsIter<'a>,
216 port: u16,
217}
218219impl<'a> Iterator for FoundHostsSocketIter<'a> {
220type Item = SocketAddr;
221222fn next(&mut self) -> Option<SocketAddr> {
223self.iter
224 .next()
225 .map(|addr| SocketAddr::new(addr, self.port))
226 }
227}
228229impl<'a> ToSocketAddrs for FoundHostsSocketIter<'a> {
230type Iter = Self;
231232fn to_socket_addrs(&self) -> io::Result<Self> {
233Ok(self.clone())
234 }
235}