1use std::future::Future;
13use std::iter::FusedIterator;
14use std::net::IpAddr;
15use std::pin::Pin;
16use std::slice;
17use std::sync::Arc;
18use std::task::{Context, Poll};
19use std::time::Instant;
20
21use futures_util::{
22 FutureExt,
23 future::{self, BoxFuture},
24};
25use tracing::debug;
26
27use crate::cache::MAX_TTL;
28use crate::caching_client::CachingClient;
29use crate::config::LookupIpStrategy;
30use crate::hosts::Hosts;
31use crate::lookup::Lookup;
32use crate::net::NetError;
33use crate::net::xfer::DnsHandle;
34use crate::proto::op::{DnsRequestOptions, Message, Query};
35use crate::proto::rr::{Name, RData, Record, RecordType};
36
37#[derive(Debug, Clone)]
41pub struct LookupIp(Lookup);
42
43impl LookupIp {
44 pub fn iter(&self) -> LookupIpIter<'_> {
48 LookupIpIter(self.0.answers().iter())
49 }
50
51 pub fn query(&self) -> &Query {
53 self.0.query()
54 }
55
56 pub fn valid_until(&self) -> Instant {
58 self.0.valid_until()
59 }
60
61 pub fn as_lookup(&self) -> &Lookup {
65 &self.0
66 }
67}
68
69impl From<Lookup> for LookupIp {
70 fn from(lookup: Lookup) -> Self {
71 Self(lookup)
72 }
73}
74
75impl From<LookupIp> for Lookup {
76 fn from(lookup: LookupIp) -> Self {
77 lookup.0
78 }
79}
80
81impl IntoIterator for LookupIp {
82 type Item = IpAddr;
83 type IntoIter = LookupIpIntoIter;
84
85 fn into_iter(self) -> Self::IntoIter {
86 let message = Message::from(self.0);
87 LookupIpIntoIter(message.answers.into_iter())
88 }
89}
90
91pub struct LookupIpIter<'a>(slice::Iter<'a, Record>);
93
94impl Iterator for LookupIpIter<'_> {
95 type Item = IpAddr;
96
97 fn next(&mut self) -> Option<Self::Item> {
98 self.0.find_map(|record| record.data.ip_addr())
99 }
100}
101
102impl FusedIterator for LookupIpIter<'_> {}
103
104pub struct LookupIpIntoIter(std::vec::IntoIter<Record>);
106
107impl Iterator for LookupIpIntoIter {
108 type Item = IpAddr;
109
110 fn next(&mut self) -> Option<Self::Item> {
111 self.0.find_map(|record| record.data.ip_addr())
112 }
113}
114
115impl FusedIterator for LookupIpIntoIter {}
116
117pub struct LookupIpFuture<C: DnsHandle + 'static> {
121 client_cache: CachingClient<C>,
122 names: Vec<Name>,
123 strategy: LookupIpStrategy,
124 options: DnsRequestOptions,
125 query: BoxFuture<'static, Result<Lookup, NetError>>,
126 hosts: Arc<Hosts>,
127 finally_ip_addr: Option<RData>,
128}
129
130impl<C: DnsHandle + 'static> LookupIpFuture<C> {
131 pub fn lookup(
139 names: Vec<Name>,
140 strategy: LookupIpStrategy,
141 client_cache: CachingClient<C>,
142 options: DnsRequestOptions,
143 hosts: Arc<Hosts>,
144 finally_ip_addr: Option<RData>,
145 ) -> Self {
146 Self {
147 names,
148 strategy,
149 client_cache,
150 query: future::err("can not lookup IPs for no names".into()).boxed(),
153 options,
154 hosts,
155 finally_ip_addr,
156 }
157 }
158}
159
160impl<C: DnsHandle + 'static> Future for LookupIpFuture<C> {
161 type Output = Result<LookupIp, NetError>;
162
163 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
164 loop {
165 let query = self.query.as_mut().poll(cx);
167
168 let should_retry = match &query {
170 Poll::Pending => return Poll::Pending,
172 Poll::Ready(Ok(lookup)) => lookup.answers().is_empty(),
176 Poll::Ready(Err(_)) => true,
178 };
179
180 if !should_retry {
181 return query.map(|f| f.map(LookupIp::from));
185 }
186
187 if let Some(name) = self.names.pop() {
188 self.query = LookupContext {
191 client: self.client_cache.clone(),
192 options: self.options,
193 hosts: self.hosts.clone(),
194 }
195 .strategic_lookup(name, self.strategy)
196 .boxed();
197 continue;
200 } else if let Some(ip_addr) = self.finally_ip_addr.take() {
201 let record = Record::from_rdata(Name::new(), MAX_TTL, ip_addr);
204 let lookup = Lookup::new_with_max_ttl(Query::new(), [record]);
205 return Poll::Ready(Ok(lookup.into()));
206 }
207
208 return query.map(|f| f.map(LookupIp::from));
213 }
214 }
215}
216
217#[derive(Clone)]
218struct LookupContext<C: DnsHandle> {
219 client: CachingClient<C>,
220 options: DnsRequestOptions,
221 hosts: Arc<Hosts>,
222}
223
224impl<C: DnsHandle> LookupContext<C> {
225 async fn strategic_lookup(
227 self,
228 name: Name,
229 strategy: LookupIpStrategy,
230 ) -> Result<Lookup, NetError> {
231 match strategy {
232 LookupIpStrategy::Ipv4Only => self.ipv4_only(name).await,
233 LookupIpStrategy::Ipv6Only => self.ipv6_only(name).await,
234 LookupIpStrategy::Ipv4AndIpv6 => self.ipv4_and_ipv6(name).await,
235 LookupIpStrategy::Ipv6AndIpv4 => self.ipv6_and_ipv4(name).await,
236 LookupIpStrategy::Ipv6thenIpv4 => self.ipv6_then_ipv4(name).await,
237 LookupIpStrategy::Ipv4thenIpv6 => self.ipv4_then_ipv6(name).await,
238 }
239 }
240
241 async fn ipv4_only(&self, name: Name) -> Result<Lookup, NetError> {
243 self.hosts_lookup(Query::query(name, RecordType::A)).await
244 }
245
246 async fn ipv6_only(&self, name: Name) -> Result<Lookup, NetError> {
248 self.hosts_lookup(Query::query(name, RecordType::AAAA))
249 .await
250 }
251
252 async fn ipv4_and_ipv6(&self, name: Name) -> Result<Lookup, NetError> {
255 self.multi_lookup(name, RecordType::A, RecordType::AAAA)
256 .await
257 }
258
259 async fn ipv6_and_ipv4(&self, name: Name) -> Result<Lookup, NetError> {
262 self.multi_lookup(name, RecordType::AAAA, RecordType::A)
263 .await
264 }
265
266 async fn multi_lookup(
268 &self,
269 name: Name,
270 first_type: RecordType,
271 second_type: RecordType,
272 ) -> Result<Lookup, NetError> {
273 let joined_res = future::join(
274 self.hosts_lookup(Query::query(name.clone(), first_type)),
275 self.hosts_lookup(Query::query(name, second_type)),
276 )
277 .await;
278
279 match joined_res {
280 (Ok(first), Ok(second)) => {
281 let ips = first.append(second);
283 Ok(ips)
284 }
285 (Ok(ips), Err(e)) | (Err(e), Ok(ips)) => {
286 debug!("one of ipv4 or ipv6 lookup failed: {e}");
287 Ok(ips)
288 }
289 (Err(e1), Err(e2)) => {
290 debug!("both of ipv4 or ipv6 lookup failed e1: {e1}, e2: {e2}");
291 Err(e1)
292 }
293 }
294 }
295
296 async fn ipv6_then_ipv4(&self, name: Name) -> Result<Lookup, NetError> {
298 self.rt_then_swap(name, RecordType::AAAA, RecordType::A)
299 .await
300 }
301
302 async fn ipv4_then_ipv6(&self, name: Name) -> Result<Lookup, NetError> {
304 self.rt_then_swap(name, RecordType::A, RecordType::AAAA)
305 .await
306 }
307
308 async fn rt_then_swap(
310 &self,
311 name: Name,
312 first_type: RecordType,
313 second_type: RecordType,
314 ) -> Result<Lookup, NetError> {
315 let res = self
316 .hosts_lookup(Query::query(name.clone(), first_type))
317 .await;
318
319 match res {
320 Ok(ips) if !ips.answers().is_empty() => Ok(ips),
321 _ => self.hosts_lookup(Query::query(name, second_type)).await,
323 }
324 }
325
326 async fn hosts_lookup(&self, query: Query) -> Result<Lookup, NetError> {
328 match self.hosts.lookup_static_host(&query) {
329 Some(lookup) => Ok(lookup),
330 None => self.client.lookup(query, self.options).await,
331 }
332 }
333}
334
335#[cfg(test)]
336pub(crate) mod tests {
337 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
338 use std::str::FromStr;
339 use std::sync::{Arc, Mutex};
340 use std::thread;
341
342 use futures_executor::block_on;
343 use futures_util::future;
344 use futures_util::stream::{Stream, once};
345 use test_support::subscribe;
346
347 use super::*;
348 use crate::net::runtime::TokioRuntimeProvider;
349 use crate::net::xfer::DnsHandle;
350 use crate::proto::op::{DnsRequest, DnsResponse, Message};
351 use crate::proto::rr::rdata::NS;
352 use crate::proto::rr::{Name, RData, Record};
353
354 #[derive(Clone)]
355 pub(crate) struct MockDnsHandle {
356 messages: Arc<Mutex<Vec<Result<DnsResponse, NetError>>>>,
357 }
358
359 impl DnsHandle for MockDnsHandle {
360 type Response = Pin<Box<dyn Stream<Item = Result<DnsResponse, NetError>> + Send + Unpin>>;
361 type Runtime = TokioRuntimeProvider;
362
363 fn send(&self, _: DnsRequest) -> Self::Response {
364 Box::pin(once(future::ready(
365 self.messages.lock().unwrap().pop().unwrap_or_else(empty),
366 )))
367 }
368 }
369
370 pub(crate) fn v4_message() -> Result<DnsResponse, NetError> {
371 let mut message = Message::query();
372 message.add_query(Query::query(Name::root(), RecordType::A));
373 message.insert_answers(vec![Record::from_rdata(
374 Name::root(),
375 86400,
376 RData::A(Ipv4Addr::LOCALHOST.into()),
377 )]);
378
379 let resp = DnsResponse::from_message(message.into_response()).unwrap();
380 assert!(resp.contains_answer());
381 Ok(resp)
382 }
383
384 pub(crate) fn v6_message() -> Result<DnsResponse, NetError> {
385 let mut message = Message::query();
386 message.add_query(Query::query(Name::root(), RecordType::AAAA));
387 message.insert_answers(vec![Record::from_rdata(
388 Name::root(),
389 86400,
390 RData::AAAA(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).into()),
391 )]);
392
393 let resp = DnsResponse::from_message(message.into_response()).unwrap();
394 assert!(resp.contains_answer());
395 Ok(resp)
396 }
397
398 pub(crate) fn empty() -> Result<DnsResponse, NetError> {
399 Ok(DnsResponse::from_message(Message::query().into_response()).unwrap())
400 }
401
402 pub(crate) fn error() -> Result<DnsResponse, NetError> {
403 Err(NetError::from("forced test failure"))
404 }
405
406 pub(crate) fn mock(messages: Vec<Result<DnsResponse, NetError>>) -> MockDnsHandle {
407 MockDnsHandle {
408 messages: Arc::new(Mutex::new(messages)),
409 }
410 }
411
412 fn assert_static<T: 'static>() {}
413
414 #[test]
415 fn test_iterator_static() {
416 assert_static::<LookupIpIntoIter>();
417 }
418
419 #[test]
420 fn test_lookup_ip_into_iter_returns_ip_addresses() {
421 let mut message = Message::query();
422 message.add_query(Query::query(Name::root(), RecordType::A));
423 message.add_answers(vec![
424 Record::from_rdata(
425 Name::root(),
426 86400,
427 RData::A(Ipv4Addr::new(192, 0, 2, 1).into()),
428 ),
429 Record::from_rdata(
430 Name::root(),
431 86400,
432 RData::NS(NS(Name::from_str("ns.example.").unwrap())),
433 ),
434 Record::from_rdata(Name::root(), 86400, RData::AAAA(Ipv6Addr::LOCALHOST.into())),
435 ]);
436
437 let lookup = LookupIp::from(Lookup::new(message, Instant::now()));
438
439 assert_eq!(
440 lookup.into_iter().collect::<Vec<_>>(),
441 vec![
442 IpAddr::V4(Ipv4Addr::new(192, 0, 2, 1)),
443 IpAddr::V6(Ipv6Addr::LOCALHOST),
444 ]
445 );
446 }
447
448 #[test]
449 fn test_lookup_ip_into_iter_can_move_across_threads() {
450 let mut message = Message::query();
451 message.add_query(Query::query(Name::root(), RecordType::A));
452 message.add_answers(vec![
453 Record::from_rdata(
454 Name::root(),
455 86400,
456 RData::A(Ipv4Addr::new(192, 0, 2, 1).into()),
457 ),
458 Record::from_rdata(Name::root(), 86400, RData::AAAA(Ipv6Addr::LOCALHOST.into())),
459 ]);
460
461 let lookup = LookupIp::from(Lookup::new(message, Instant::now()));
462 let iter = lookup.into_iter();
463
464 let ips = thread::spawn(move || iter.collect::<Vec<_>>())
465 .join()
466 .unwrap();
467
468 assert_eq!(
469 ips,
470 vec![
471 IpAddr::V4(Ipv4Addr::new(192, 0, 2, 1)),
472 IpAddr::V6(Ipv6Addr::LOCALHOST),
473 ]
474 );
475 }
476
477 #[test]
478 fn test_ipv4_only_strategy() {
479 subscribe();
480
481 let cx = LookupContext {
482 client: CachingClient::new(0, mock(vec![v4_message()]), false),
483 options: DnsRequestOptions::default(),
484 hosts: Arc::new(Hosts::default()),
485 };
486
487 assert_eq!(
488 block_on(cx.ipv4_only(Name::root()))
489 .unwrap()
490 .answers()
491 .iter()
492 .map(|r| r.data.ip_addr().unwrap())
493 .collect::<Vec<IpAddr>>(),
494 vec![Ipv4Addr::LOCALHOST]
495 );
496 }
497
498 #[test]
499 fn test_ipv6_only_strategy() {
500 subscribe();
501
502 let cx = LookupContext {
503 client: CachingClient::new(0, mock(vec![v6_message()]), false),
504 options: DnsRequestOptions::default(),
505 hosts: Arc::new(Hosts::default()),
506 };
507
508 assert_eq!(
509 block_on(cx.ipv6_only(Name::root()))
510 .unwrap()
511 .answers()
512 .iter()
513 .map(|r| r.data.ip_addr().unwrap())
514 .collect::<Vec<IpAddr>>(),
515 vec![Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)]
516 );
517 }
518
519 #[test]
520 fn test_ipv4_and_ipv6_strategy() {
521 subscribe();
522
523 let mut cx = LookupContext {
524 client: CachingClient::new(0, mock(vec![v6_message(), v4_message()]), false),
525 options: DnsRequestOptions::default(),
526 hosts: Arc::new(Hosts::default()),
527 };
528
529 assert_eq!(
532 block_on(cx.ipv4_and_ipv6(Name::root()))
533 .unwrap()
534 .answers()
535 .iter()
536 .map(|r| r.data.ip_addr().unwrap())
537 .collect::<Vec<IpAddr>>(),
538 vec![
539 IpAddr::V4(Ipv4Addr::LOCALHOST),
540 IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)),
541 ]
542 );
543
544 cx.client = CachingClient::new(0, mock(vec![empty(), v4_message()]), false);
546 assert_eq!(
547 block_on(cx.ipv4_and_ipv6(Name::root()))
548 .unwrap()
549 .answers()
550 .iter()
551 .map(|r| r.data.ip_addr().unwrap())
552 .collect::<Vec<IpAddr>>(),
553 vec![IpAddr::V4(Ipv4Addr::LOCALHOST)]
554 );
555
556 cx.client = CachingClient::new(0, mock(vec![error(), v4_message()]), false);
558 assert_eq!(
559 block_on(cx.ipv4_and_ipv6(Name::root()))
560 .unwrap()
561 .answers()
562 .iter()
563 .map(|r| r.data.ip_addr().unwrap())
564 .collect::<Vec<IpAddr>>(),
565 vec![IpAddr::V4(Ipv4Addr::LOCALHOST)]
566 );
567
568 cx.client = CachingClient::new(0, mock(vec![v6_message(), empty()]), false);
570 assert_eq!(
571 block_on(cx.ipv4_and_ipv6(Name::root()))
572 .unwrap()
573 .answers()
574 .iter()
575 .map(|r| r.data.ip_addr().unwrap())
576 .collect::<Vec<IpAddr>>(),
577 vec![IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))]
578 );
579
580 cx.client = CachingClient::new(0, mock(vec![v6_message(), error()]), false);
582 assert_eq!(
583 block_on(cx.ipv4_and_ipv6(Name::root()))
584 .unwrap()
585 .answers()
586 .iter()
587 .map(|r| r.data.ip_addr().unwrap())
588 .collect::<Vec<IpAddr>>(),
589 vec![IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))]
590 );
591 }
592
593 #[test]
594 fn test_ipv6_and_ipv4_strategy() {
595 subscribe();
596
597 let mut cx = LookupContext {
598 client: CachingClient::new(0, mock(vec![v4_message(), v6_message()]), false),
599 options: DnsRequestOptions::default(),
600 hosts: Arc::new(Hosts::default()),
601 };
602
603 assert_eq!(
606 block_on(cx.ipv6_and_ipv4(Name::root()))
607 .unwrap()
608 .answers()
609 .iter()
610 .map(|r| r.data.ip_addr().unwrap())
611 .collect::<Vec<IpAddr>>(),
612 vec![
613 IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)),
614 IpAddr::V4(Ipv4Addr::LOCALHOST),
615 ]
616 );
617
618 cx.client = CachingClient::new(0, mock(vec![v4_message(), empty()]), false);
620 assert_eq!(
621 block_on(cx.ipv6_and_ipv4(Name::root()))
622 .unwrap()
623 .answers()
624 .iter()
625 .map(|r| r.data.ip_addr().unwrap())
626 .collect::<Vec<IpAddr>>(),
627 vec![IpAddr::V4(Ipv4Addr::LOCALHOST)]
628 );
629
630 cx.client = CachingClient::new(0, mock(vec![v4_message(), error()]), false);
632 assert_eq!(
633 block_on(cx.ipv6_and_ipv4(Name::root()))
634 .unwrap()
635 .answers()
636 .iter()
637 .map(|r| r.data.ip_addr().unwrap())
638 .collect::<Vec<IpAddr>>(),
639 vec![IpAddr::V4(Ipv4Addr::LOCALHOST)]
640 );
641
642 cx.client = CachingClient::new(0, mock(vec![empty(), v6_message()]), false);
644 assert_eq!(
645 block_on(cx.ipv6_and_ipv4(Name::root()))
646 .unwrap()
647 .answers()
648 .iter()
649 .map(|r| r.data.ip_addr().unwrap())
650 .collect::<Vec<IpAddr>>(),
651 vec![IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))]
652 );
653
654 cx.client = CachingClient::new(0, mock(vec![error(), v6_message()]), false);
656 assert_eq!(
657 block_on(cx.ipv6_and_ipv4(Name::root()))
658 .unwrap()
659 .answers()
660 .iter()
661 .map(|r| r.data.ip_addr().unwrap())
662 .collect::<Vec<IpAddr>>(),
663 vec![IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))]
664 );
665 }
666
667 #[test]
668 fn test_ipv6_then_ipv4_strategy() {
669 subscribe();
670
671 let mut cx = LookupContext {
672 client: CachingClient::new(0, mock(vec![v6_message()]), false),
673 options: DnsRequestOptions::default(),
674 hosts: Arc::new(Hosts::default()),
675 };
676
677 assert_eq!(
679 block_on(cx.ipv6_then_ipv4(Name::root()))
680 .unwrap()
681 .answers()
682 .iter()
683 .map(|r| r.data.ip_addr().unwrap())
684 .collect::<Vec<IpAddr>>(),
685 vec![Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)]
686 );
687
688 cx.client = CachingClient::new(0, mock(vec![v4_message(), empty()]), false);
690 assert_eq!(
691 block_on(cx.ipv6_then_ipv4(Name::root()))
692 .unwrap()
693 .answers()
694 .iter()
695 .map(|r| r.data.ip_addr().unwrap())
696 .collect::<Vec<IpAddr>>(),
697 vec![Ipv4Addr::LOCALHOST]
698 );
699
700 cx.client = CachingClient::new(0, mock(vec![v4_message(), error()]), false);
702 assert_eq!(
703 block_on(cx.ipv6_then_ipv4(Name::root()))
704 .unwrap()
705 .answers()
706 .iter()
707 .map(|r| r.data.ip_addr().unwrap())
708 .collect::<Vec<IpAddr>>(),
709 vec![Ipv4Addr::LOCALHOST]
710 );
711 }
712
713 #[test]
714 fn test_ipv4_then_ipv6_strategy() {
715 subscribe();
716
717 let mut cx = LookupContext {
718 client: CachingClient::new(0, mock(vec![v4_message()]), false),
719 options: DnsRequestOptions::default(),
720 hosts: Arc::new(Hosts::default()),
721 };
722
723 assert_eq!(
725 block_on(cx.ipv4_then_ipv6(Name::root()))
726 .unwrap()
727 .answers()
728 .iter()
729 .map(|r| r.data.ip_addr().unwrap())
730 .collect::<Vec<IpAddr>>(),
731 vec![Ipv4Addr::LOCALHOST]
732 );
733
734 cx.client = CachingClient::new(0, mock(vec![v6_message(), empty()]), false);
736 assert_eq!(
737 block_on(cx.ipv4_then_ipv6(Name::root()))
738 .unwrap()
739 .answers()
740 .iter()
741 .map(|r| r.data.ip_addr().unwrap())
742 .collect::<Vec<IpAddr>>(),
743 vec![Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)]
744 );
745
746 cx.client = CachingClient::new(0, mock(vec![v6_message(), error()]), false);
748 assert_eq!(
749 block_on(cx.ipv4_then_ipv6(Name::root()))
750 .unwrap()
751 .answers()
752 .iter()
753 .map(|r| r.data.ip_addr().unwrap())
754 .collect::<Vec<IpAddr>>(),
755 vec![Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)]
756 );
757 }
758}