add a synchronous resolver

This commit is contained in:
Benjamin Fry 2017-06-05 23:10:21 -07:00
parent d446fedbf0
commit 22b137e333
10 changed files with 200 additions and 27 deletions

2
.gitignore vendored
View File

@ -13,4 +13,6 @@
# Generated by Cargo
/target/
**/target/
*.rs.bk
.rls.toml

4
Cargo.lock generated
View File

@ -820,8 +820,8 @@ name = "trust-dns-resolver"
version = "0.1.0"
dependencies = [
"futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"trust-dns 0.10.2",
"tokio-core 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"trust-dns 0.10.3",
]
[[package]]

View File

@ -1,5 +1,5 @@
[workspace]
members = ["client", "compatibility", "native-tls", "rustls", "resolver", "server"]
members = ["client", "compatibility", "native-tls", "resolver", "rustls", "server"]
[replace]
#"native-tls:0.1.1" = { path = "../rust-native-tls" }

View File

@ -400,7 +400,8 @@ impl ClientHandle for BasicClientHandle {
let (complete, receiver) = oneshot::channel();
let message_sender: &mut _ = &mut self.message_sender;
let receiver = match message_sender.send((message, complete)) {
// TODO: update to use Sink::send
let receiver = match UnboundedSender::send(message_sender, (message, complete)) {
Ok(()) => receiver,
Err(e) => {
let (complete, receiver) = oneshot::channel();

View File

@ -10,7 +10,7 @@ TRust-DNS is a safe and secure DNS library. This is the resolver library. It use
"""
# These URLs point to more information about the repository
documentation = "https://docs.rs/trust-dns"
documentation = "https://docs.rs/trust-dns-resolver"
homepage = "http://www.trust-dns.org/index.html"
repository = "https://github.com/bluejekyll/trust-dns"
@ -37,11 +37,12 @@ travis-ci = { repository = "bluejekyll/trust-dns" }
appveyor = { repository = "bluejekyll/trust-dns", branch = "master", service = "github" }
[lib]
name = "trust_dns_resolver"
name = "r2d2_trust_dns"
path = "src/lib.rs"
[dependencies]
futures = "^0.1.6"
tokio-core = "^0.1"
trust-dns = { version = "^0.10", path = "../client" }
[dev-dependencies]

View File

@ -6,31 +6,48 @@
// copied, modified, or distributed except according to those terms.
//! Configuration for a resolver
use std::collections::BTreeSet;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::time::Duration;
/// Configuration for the upstream nameservers to use for resolution
#[derive(Clone, Debug)]
pub struct ResolverConfig {
name_servers: Vec<NameServerConf>,
name_servers: Vec<NameServerConfig>,
}
impl ResolverConfig {
pub fn add_name_server(&mut self, name_server: NameServerConf) {
pub fn add_name_server(&mut self, name_server: NameServerConfig) {
self.name_servers.push(name_server);
}
pub fn name_servers(&self) -> &[NameServerConfig] {
&self.name_servers
}
}
impl Default for ResolverConfig {
fn default() -> Self {
let ns = NameServerConf{ socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8)), 53) };
let ns = NameServerConfig
{
socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8)), 53),
protocol: Protocol::Udp,
};
ResolverConfig { name_servers: vec![ns] }
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct NameServerConf {
#[derive(Clone, Debug, Eq, PartialEq)]
enum Protocol {
Udp,
Tcp,
// TODO: add client certificate for mTLS
Tls,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct NameServerConfig {
socket_addr: SocketAddr,
protocol: Protocol,
}
/// Configuration for the Resolver

View File

@ -12,15 +12,18 @@
#![deny(missing_docs)]
extern crate futures;
extern crate tokio_core;
extern crate trust_dns;
mod config;
mod lookup_ip;
mod pool;
mod resolver;
mod resolver_future;
pub use resolver::Resolver;
pub use resolver_future::ResolverFuture;
/// this exposes a version function which gives access to the access
include!(concat!(env!("OUT_DIR"), "/version.rs"));

75
resolver/src/pool.rs Normal file
View File

@ -0,0 +1,75 @@
// Copyright 2015-2017 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use std::collections::BinaryHeap;
use std::io;
use std::time::Duration;
use futures::{Future, Sink};
use trust_dns::error::*;
use trust_dns::client::{BasicClientHandle, ClientHandle};
use trust_dns::op::{Edns, Message};
use config::{NameServerConfig, ResolverConfig, ResolverOpts};
/// State of a connection with a remote NameServer.
#[derive(Clone, Debug)]
enum NameServerState {
/// Initial state, if Edns is not none, then Edns will be requested
Init { send_edns: Option<Edns> },
/// There has been successful communication with the remote.
/// if no Edns is associated, then the remote does not support Edns
Established { remote_edns: Option<Edns> },
/// For some reason the connection failed. For UDP this would only be a timeout
/// for TCP this could be either Connection could never be established, or it
/// failed at somepoint after. The Failed state should not be entered due to the
/// error contained in a Message recieved from the server.
Failed { error: ClientError, chrono: Duration },
}
#[derive(Clone)]
pub(crate) struct NameServer {
config: NameServerConfig,
client: BasicClientHandle,
state: NameServerState,
successes: usize,
failures: usize,
}
impl NameServer {
pub fn new(config: NameServerConfig) -> Self {
unimplemented!()
}
}
impl ClientHandle for NameServer {
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = ClientError>> {
self.client.send(message)
}
}
#[derive(Clone)]
pub(crate) struct NameServerPool {
conns: BinaryHeap<NameServer>,
}
impl NameServerPool {
pub fn from_config(config: &ResolverConfig, opts: &ResolverOpts) -> NameServerPool {
for ns_config in config.name_servers() {}
unimplemented!()
}
}
impl ClientHandle for NameServerPool {
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = ClientError>> {
// select the highest priority connection
unimplemented!()
}
}

View File

@ -7,7 +7,84 @@
//! Structs for creating and using a Resolver
use std::net::IpAddr;
use std::cell::RefCell;
use std::io;
use futures::Stream;
use tokio_core::reactor::Core;
use trust_dns::client::{BasicClientHandle, ClientConnection, ClientFuture};
use config::{ResolverConfig, ResolverOpts};
use lookup_ip::LookupIp;
use ResolverFuture;
/// The result of a Host (basic A or AAAA) query
pub struct Resolver {}
pub struct Resolver {
resolver_future: RefCell<ResolverFuture>,
io_loop: RefCell<Core>,
}
impl Resolver {
/// Construct a new Resolver with the given ClientConnection, see UdpClientConnection and/or TcpCLientConnection
///
/// # Arguments
/// * `config` - configuration for the resolver
/// * `options` - resolver options for performing lookups
/// * `client_connection` - ClientConnection for establishing the connection to the DNS server
///
/// # Returns
/// A new Resolver
pub fn new(config: ResolverConfig, options: ResolverOpts) -> io::Result<Self> {
let io_loop = Core::new()?;
let resolver = ResolverFuture::new(config, options);
Ok(Resolver {
resolver_future: RefCell::new(resolver),
io_loop: RefCell::new(io_loop),
})
}
/// Performs a DNS lookup for the IP for the given hostname.
///
/// Based on the configuration and options passed in, this may do either a A or a AAAA lookup,
/// returning IpV4 or IpV6 addresses.
///
/// # Arguments
/// * `host` - string hostname, if this is an invalid hostname, an error will be thrown.
pub fn lookup_ip(&mut self, host: &str) -> io::Result<LookupIp> {
self.io_loop
.borrow_mut()
.run(self.resolver_future.borrow_mut().lookup_ip(host))
}
}
#[cfg(test)]
mod tests {
extern crate tokio_core;
use futures::Future;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs};
use self::tokio_core::reactor::Core;
use trust_dns::client::ClientFuture;
use trust_dns::udp::UdpClientConnection;
use super::*;
#[test]
fn test_lookup() {
let addr: SocketAddr = ("8.8.8.8", 53)
.to_socket_addrs()
.unwrap()
.next()
.unwrap();
let conn = UdpClientConnection::new(addr).unwrap();
let mut resolver = Resolver::new(ResolverConfig::default(), ResolverOpts::default(), conn);
let mut response = resolver.lookup_ip("www.example.com.").unwrap();
println!("response records: {:?}", response);
let address = response.next().expect("no addresses returned");
assert_eq!(address, IpAddr::V4(Ipv4Addr::new(93, 184, 216, 34)));
}
}

View File

@ -11,30 +11,27 @@ use trust_dns::client::ClientHandle;
use trust_dns::rr::RecordType;
use config::{ResolverConfig, ResolverOpts};
use pool::NameServerPool;
use lookup_ip::LookupIpFuture;
/// A Recursive Resolver for DNS records.
pub struct ResolverFuture<C: ClientHandle> {
config: ResolverConfig,
options: ResolverOpts,
client: C,
pub struct ResolverFuture {
// config: ResolverConfig,
// options: ResolverOpts,
pool: NameServerPool,
}
impl<C: ClientHandle> ResolverFuture<C> {
impl ResolverFuture {
/// Construct a new ResolverFuture with the associated Client.
pub fn new(config: ResolverConfig, options: ResolverOpts, client: C) -> Self {
ResolverFuture {
config,
options,
client,
}
pub fn new(config: ResolverConfig, options: ResolverOpts) -> Self {
let pool = NameServerPool::from_config(&config, &options);
ResolverFuture { pool }
}
/// A basic host name lookup lookup
pub fn lookup_ip(&mut self, host: &str) -> LookupIpFuture {
// create the lookup
LookupIpFuture::lookup(host, RecordType::A, &mut self.client)
LookupIpFuture::lookup(host, RecordType::A, &mut self.pool)
}
}