domain/resolv/lookup/
addr.rs

1//! Looking up host names for addresses.
2
3use crate::base::iana::Rtype;
4use crate::base::message::RecordIter;
5use crate::base::name::{Name, ParsedName};
6use crate::rdata::Ptr;
7use crate::resolv::resolver::Resolver;
8use octseq::octets::Octets;
9use std::io;
10use std::net::IpAddr;
11
12//------------ Octets128 -----------------------------------------------------
13
14type Octets128 = octseq::array::Array<128>;
15
16//------------ lookup_addr ---------------------------------------------------
17
18/// Resolves the host names of an IP address.
19///
20/// The function will query DNS using the resolver represented by `resolv`.
21/// It will query DNS only and not consider any other database the system
22/// may have.
23///
24/// The value returned upon success can be turned into an iterator over
25/// host names via its `iter()` method. This is due to lifetime issues.
26pub async fn lookup_addr<R: Resolver>(
27    resolv: &R,
28    addr: IpAddr,
29) -> Result<FoundAddrs<R>, io::Error> {
30    let name = Name::<Octets128>::reverse_from_addr(addr)
31        .expect("address domain name too long");
32    resolv.query((name, Rtype::PTR)).await.map(FoundAddrs)
33}
34
35//------------ FoundAddrs ----------------------------------------------------
36
37/// The success type of the `lookup_addr()` function.
38///
39/// The only purpose of this type is to return an iterator over host names
40/// via its `iter()` method.
41pub struct FoundAddrs<R: Resolver>(R::Answer);
42
43impl<R: Resolver> FoundAddrs<R> {
44    /// Returns an iterator over the host names.
45    pub fn iter(&self) -> FoundAddrsIter<'_, R::Octets>
46    where
47        R::Octets: Octets,
48    {
49        FoundAddrsIter {
50            name: self.0.as_ref().canonical_name(),
51            answer: {
52                self.0
53                    .as_ref()
54                    .answer()
55                    .ok()
56                    .map(|sec| sec.limit_to::<Ptr<_>>())
57            },
58        }
59    }
60}
61
62impl<'a, R: Resolver> IntoIterator for &'a FoundAddrs<R>
63where
64    R::Octets: Octets,
65{
66    type Item = ParsedName<<<R as Resolver>::Octets as Octets>::Range<'a>>;
67    type IntoIter = FoundAddrsIter<'a, R::Octets>;
68
69    fn into_iter(self) -> Self::IntoIter {
70        self.iter()
71    }
72}
73
74//------------ FoundAddrsIter ------------------------------------------------
75
76/// An iterator over host names returned by address lookup.
77pub struct FoundAddrsIter<'a, Octs: Octets> {
78    name: Option<ParsedName<Octs::Range<'a>>>,
79    answer: Option<RecordIter<'a, Octs, Ptr<ParsedName<Octs::Range<'a>>>>>,
80}
81
82impl<'a, Octs: Octets> Iterator for FoundAddrsIter<'a, Octs> {
83    type Item = ParsedName<Octs::Range<'a>>;
84
85    fn next(&mut self) -> Option<Self::Item> {
86        let name = self.name.as_ref()?;
87        let answer = self.answer.as_mut()?;
88        while let Some(Ok(record)) = answer.next() {
89            if record.owner() == name {
90                return Some(record.into_data().into_ptrdname());
91            }
92        }
93        None
94    }
95}