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