netdb/hosts/mod.rs
1/// The host name and IP address database.
2///
3/// This database provides queries for host names and IP addresses associated
4/// with network hosts. It allows lookups based on a given host name or a
5/// given IP address.
6
7use std::{io, mem};
8use std::net::IpAddr;
9use std::str::FromStr;
10use domain::bits::DNameBuf;
11use futures::{Async, Future, Poll};
12use tokio_core::reactor;
13
14
15//============ Low-level API =================================================
16//
17// Currently private.
18
19mod dns;
20mod files;
21
22
23//============ High-level API ================================================
24
25/// Returns host information for a given host name.
26///
27/// The name is either a hostname, an IPv4 or IPv6 address in its standard
28/// text notation. In the latter two cases, no lookups are performed and a
29/// `HostEnt` is returned with `name` as the canonical name, the parsed
30/// address as the sole address, and no aliases.
31///
32/// Otherwise the name is interpreted as a host name and lookups according to
33/// the system configuraition are performed.
34///
35/// The function waits for all necessary IO to resolve. Upon success, it
36/// returns a `HostEnt` value if a host for the given name was found or
37/// `Ok(None)` otherwise.
38///
39/// # Limitations
40///
41/// For this initial version of the crate, the lookup is a `files` lookup
42/// first and only if that does fail to yield a result, a DNS query for
43/// both A and AAAA records. This initial version also does not yet fill
44/// the aliases list of the returned `HostEnt`.
45pub fn get_host_by_name(name: &str) -> Result<Option<HostEnt>, io::Error> {
46 let mut core = reactor::Core::new()?;
47 let handle = core.handle();
48 core.run(poll_host_by_name(name, &handle))
49}
50
51/// Returns host information for a given IP address.
52///
53/// The IP address can either be an IPv4 or IPv6 address. The function waits
54/// for all necessary IO to resolve. Upon success, it
55/// returns a `HostEnt` value if a host for the given name was found or
56/// `Ok(None)` otherwise.
57///
58/// # Limitations
59///
60/// For this initial version of the crate, the lookup is a `files` lookup
61/// first and only if that does fail to yield a result, a DNS query for
62/// PTR records. This initial version also does not yet fill
63/// the aliases list of the returned `HostEnt`.
64pub fn get_host_by_addr(addr: IpAddr) -> Result<Option<HostEnt>, io::Error> {
65 let mut core = reactor::Core::new()?;
66 let handle = core.handle();
67 core.run(poll_host_by_addr(addr, &handle))
68}
69
70/// Returns host information for a given host name.
71///
72/// The name is either a hostname, an IPv4 or IPv6 address in its standard
73/// text notation. In the latter two cases, no lookups are performed and a
74/// `HostEnt` is returned with `name` as the canonical name, the parsed
75/// address as the sole address, and no aliases.
76///
77/// Otherwise the name is interpreted as a host name and lookups according to
78/// the system configuraition are performed.
79///
80/// The function returns a future that performes all necessary IO via the
81/// Tokio reactor given by `reactor`.
82///
83/// # Limitations
84///
85/// For this initial version of the crate, the lookup is a `files` lookup
86/// first and only if that does fail to yield a result, a DNS query for
87/// both A and AAAA records. This initial version also does not yet fill
88/// the aliases list of the returned `HostEnt`.
89pub fn poll_host_by_name(name: &str, reactor: &reactor::Handle)
90 -> HostByName {
91 HostByName::new(name, reactor)
92}
93
94/// Returns host information for a given IP address.
95///
96/// The IP address can either be an IPv4 or IPv6 address. The function returns
97/// a future performing all necessary IO via the Tokio reactor given by
98/// `reactor`.
99///
100/// # Limitations
101///
102/// For this initial version of the crate, the lookup is a `files` lookup
103/// first and only if that does fail to yield a result, a DNS query for
104/// PTR records. This initial version also does not yet fill
105/// the aliases list of the returned `HostEnt`.
106pub fn poll_host_by_addr(addr: IpAddr, reactor: &reactor::Handle)
107 -> HostByAddr {
108 HostByAddr::new(addr, reactor)
109}
110
111
112//------------ HostEnt -------------------------------------------------------
113
114/// The result of a host lookup.
115///
116/// > **Note.** This implementation is highly temporary. While will probably
117/// > keep the semantics, the actual types may change.
118pub struct HostEnt {
119 name: String,
120 aliases: Vec<String>,
121 addrs: Vec<IpAddr>,
122}
123
124impl HostEnt {
125 /// The canoncial name of the host.
126 pub fn name(&self) -> &str {
127 &self.name
128 }
129
130 /// The aliases of the host.
131 ///
132 /// > **Note.** Best to assume this is a slice of `str`.
133 pub fn aliases(&self) -> &[String] {
134 self.aliases.as_ref()
135 }
136
137 /// The addresses of the host.
138 pub fn addrs(&self) -> &[IpAddr] {
139 self.addrs.as_ref()
140 }
141}
142
143
144//------------ HostByName ----------------------------------------------------
145
146/// The future returned by `poll_host_by_name()`.
147///
148/// Resolves into a `HostEnt` value if the lookup is successful or `None` if
149/// there is no such name.
150pub struct HostByName(ByNameInner);
151
152enum ByNameInner {
153 Files(HostEnt),
154 Dns(dns::HostByName),
155 Error(io::Error),
156 Done,
157}
158
159impl HostByName {
160 pub fn new(name: &str, reactor: &reactor::Handle) -> Self {
161 if let Ok(addr) = IpAddr::from_str(name) {
162 return HostByName(ByNameInner::Files(HostEnt {
163 name: name.into(),
164 aliases: Vec::new(),
165 addrs: vec!(addr),
166 }))
167 }
168 let name = match DNameBuf::from_str(name) {
169 Ok(name) => name,
170 Err(e) => {
171 return HostByName(ByNameInner::Error(
172 io::Error::new(io::ErrorKind::Other, e)
173 ))
174 }
175 };
176 HostByName(match files::get_host_by_name(&name) {
177 Ok(Some(ent)) => ByNameInner::Files(ent),
178 Ok(None) => ByNameInner::Dns(dns::HostByName::new(name, reactor)),
179 Err(err) => ByNameInner::Error(err),
180 })
181 }
182}
183
184
185impl Future for HostByName {
186 type Item = Option<HostEnt>;
187 type Error = io::Error;
188
189 fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
190 if let ByNameInner::Dns(ref mut lookup) = self.0 {
191 return lookup.poll();
192 }
193 match mem::replace(&mut self.0, ByNameInner::Done) {
194 ByNameInner::Files(res) => Ok(Async::Ready(Some(res))),
195 ByNameInner::Error(err) => Err(err),
196 ByNameInner::Done => panic!("polling a resolved HostByName"),
197 _ => panic!()
198 }
199 }
200}
201
202
203//------------ HostByAddr ----------------------------------------------------
204
205/// The future returned by `poll_host_by_addr()`.
206///
207/// Resolves into a `HostEnt` value if the lookup is successful or `None` if
208/// there is no such address.
209pub struct HostByAddr(ByAddrInner);
210
211enum ByAddrInner {
212 Files(HostEnt),
213 Dns(dns::HostByAddr),
214 Error(io::Error),
215 Done
216}
217
218impl HostByAddr {
219 pub fn new(addr: IpAddr, reactor: &reactor::Handle) -> Self {
220 HostByAddr(match files::get_host_by_addr(addr) {
221 Ok(Some(ent)) => ByAddrInner::Files(ent),
222 Ok(None) => ByAddrInner::Dns(dns::HostByAddr::new(addr, reactor)),
223 Err(err) => ByAddrInner::Error(err),
224 })
225 }
226}
227
228impl Future for HostByAddr {
229 type Item = Option<HostEnt>;
230 type Error = io::Error;
231
232 fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
233 if let ByAddrInner::Dns(ref mut lookup) = self.0 {
234 return lookup.poll();
235 }
236 match mem::replace(&mut self.0, ByAddrInner::Done) {
237 ByAddrInner::Files(res) => Ok(Async::Ready(Some(res))),
238 ByAddrInner::Error(err) => Err(err),
239 ByAddrInner::Done => panic!("polling a resolved HostByAddr"),
240 _ => panic!()
241 }
242 }
243}
244