domain/resolv/lookup/
host.rs1use crate::base::iana::Rtype;
4use crate::base::message::RecordIter;
5use crate::base::name::{ParsedName, ToName, ToRelativeName};
6use crate::rdata::{Aaaa, A};
7use crate::resolv::resolver::{Resolver, SearchNames};
8use octseq::octets::Octets;
9use std::io;
10use std::net::{IpAddr, SocketAddr, ToSocketAddrs};
11
12pub async fn lookup_host<R: Resolver>(
24 resolver: &R,
25 qname: impl ToName,
26) -> Result<FoundHosts<R>, io::Error> {
27 let (a, aaaa) = tokio::join!(
28 resolver.query((&qname, Rtype::A)),
29 resolver.query((&qname, Rtype::AAAA)),
30 );
31 FoundHosts::new(aaaa, a)
32}
33
34pub async fn search_host<R: Resolver + SearchNames>(
37 resolver: &R,
38 qname: impl ToRelativeName,
39) -> Result<FoundHosts<R>, io::Error> {
40 for suffix in resolver.search_iter() {
41 if let Ok(name) = (&qname).chain(suffix) {
42 if let Ok(answer) = lookup_host(resolver, name).await {
43 if !answer.is_empty() {
44 return Ok(answer);
45 }
46 }
47 }
48 }
49 lookup_host(resolver, qname.chain_root()).await
50}
51
52#[derive(Debug)]
63pub struct FoundHosts<R: Resolver> {
64 aaaa: Result<R::Answer, io::Error>,
66
67 a: Result<R::Answer, io::Error>,
69}
70
71impl<R: Resolver> FoundHosts<R> {
72 pub fn new(
73 aaaa: Result<R::Answer, io::Error>,
74 a: Result<R::Answer, io::Error>,
75 ) -> Result<Self, io::Error> {
76 if aaaa.is_err() && a.is_err() {
77 match aaaa {
78 Err(err) => return Err(err),
79 _ => unreachable!(),
80 }
81 }
82
83 Ok(FoundHosts { aaaa, a })
84 }
85
86 pub fn is_empty(&self) -> bool {
87 if let Ok(ref aaaa) = self.aaaa {
88 if aaaa.as_ref().header_counts().ancount() > 0 {
89 return false;
90 }
91 }
92 if let Ok(ref a) = self.a {
93 if a.as_ref().header_counts().ancount() > 0 {
94 return false;
95 }
96 }
97 true
98 }
99
100 fn answer(&self) -> &R::Answer {
102 match self.aaaa.as_ref() {
103 Ok(answer) => answer,
104 Err(_) => self.a.as_ref().unwrap(),
105 }
106 }
107}
108
109impl<R: Resolver> FoundHosts<R>
110where
111 R::Octets: Octets,
112{
113 pub fn qname(&self) -> ParsedName<<R::Octets as Octets>::Range<'_>> {
114 self.answer()
115 .as_ref()
116 .first_question()
117 .unwrap()
118 .into_qname()
119 }
120
121 pub fn canonical_name(
129 &self,
130 ) -> ParsedName<<R::Octets as Octets>::Range<'_>> {
131 self.answer().as_ref().canonical_name().unwrap()
132 }
133
134 pub 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: {
148 self.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: {
155 self.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 }
163
164 pub fn port_iter(&self, port: u16) -> FoundHostsSocketIter {
170 FoundHostsSocketIter {
171 iter: self.iter(),
172 port,
173 }
174 }
175}
176
177#[derive(Clone)]
181pub struct FoundHostsIter<'a> {
182 aaaa_name: Option<ParsedName<&'a [u8]>>,
183 a_name: Option<ParsedName<&'a [u8]>>,
184 aaaa: Option<RecordIter<'a, [u8], Aaaa>>,
185 a: Option<RecordIter<'a, [u8], A>>,
186}
187
188impl Iterator for FoundHostsIter<'_> {
189 type Item = IpAddr;
190
191 fn next(&mut self) -> Option<IpAddr> {
192 while let Some(res) = self.aaaa.as_mut().and_then(Iterator::next) {
193 if let Ok(record) = res {
194 if Some(record.owner()) == self.aaaa_name.as_ref() {
195 return Some(record.data().addr().into());
196 }
197 }
198 }
199 while let Some(res) = self.a.as_mut().and_then(Iterator::next) {
200 if let Ok(record) = res {
201 if Some(record.owner()) == self.a_name.as_ref() {
202 return Some(record.data().addr().into());
203 }
204 }
205 }
206 None
207 }
208}
209
210#[derive(Clone)]
214pub struct FoundHostsSocketIter<'a> {
215 iter: FoundHostsIter<'a>,
216 port: u16,
217}
218
219impl Iterator for FoundHostsSocketIter<'_> {
220 type Item = SocketAddr;
221
222 fn next(&mut self) -> Option<SocketAddr> {
223 self.iter
224 .next()
225 .map(|addr| SocketAddr::new(addr, self.port))
226 }
227}
228
229impl ToSocketAddrs for FoundHostsSocketIter<'_> {
230 type Iter = Self;
231
232 fn to_socket_addrs(&self) -> io::Result<Self> {
233 Ok(self.clone())
234 }
235}