add a synchronous resolver
This commit is contained in:
parent
d446fedbf0
commit
22b137e333
2
.gitignore
vendored
2
.gitignore
vendored
@ -13,4 +13,6 @@
|
||||
# Generated by Cargo
|
||||
/target/
|
||||
**/target/
|
||||
|
||||
*.rs.bk
|
||||
.rls.toml
|
||||
|
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -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]]
|
||||
|
@ -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" }
|
||||
|
@ -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();
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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
75
resolver/src/pool.rs
Normal 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!()
|
||||
}
|
||||
}
|
@ -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)));
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user