use crate::bail;
use crate::clients::udp::Client as UdpClient;
use crate::clients::Exchanger;
use crate::types::*;
use crate::Extension;
use crate::Message;
use std::collections::HashSet;
use std::net::IpAddr;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
pub struct Resolver<E = UdpClient> {
client: E,
}
impl Default for Resolver {
fn default() -> Self {
Self::new()
}
}
impl Resolver {
pub fn new() -> Resolver<UdpClient> {
let servers = crate::clients::udp::GOOGLE
.iter()
.flat_map(|a| a.to_socket_addrs())
.flatten()
.collect::<Vec<SocketAddr>>();
let client = UdpClient::new(&servers[..]).unwrap(); Resolver::new_with_client(client)
}
}
impl<E> Resolver<E>
where
E: Exchanger,
{
pub fn new_with_client(client: E) -> Resolver<E> {
Resolver { client }
}
pub fn lookup(&self, name: &str) -> Result<Vec<IpAddr>, crate::Error> {
let mut results = HashSet::new();
for r#type in &[Type::A, Type::AAAA] {
let mut query = Message::default();
query.add_question(name, *r#type, Class::Internet);
query.add_extension(Extension {
payload_size: 4096,
..Default::default()
});
let response = self.client.exchange(&query)?;
println!(
"{}: Trying {} and got {}",
name,
r#type,
response.answers.len()
);
match response.rcode {
Rcode::NoError => (), _ => bail!(InvalidInput, "query failed with rcode: {}", response.rcode),
};
for answer in response.answers {
match answer.resource {
Resource::A(ip4) => results.insert(IpAddr::V4(ip4)),
Resource::AAAA(ip6) => results.insert(IpAddr::V6(ip6)),
_ => false, };
}
}
Ok(results.into_iter().collect())
}
}