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
// 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.

//! Structs for creating and using a Resolver

use std::cell::RefCell;
use std::io;

use tokio_core::reactor::Core;

use config::{ResolverConfig, ResolverOpts};
use lookup_ip::LookupIp;
use ResolverFuture;

/// The Resolver is used for performing DNS queries.
///
/// For forward (A) lookups, hostname -> IP address, see: `Resolver::lookup_ip`
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, io_loop.handle());

        Ok(Resolver {
               resolver_future: RefCell::new(resolver),
               io_loop: RefCell::new(io_loop),
           })
    }

    // TODO: need to support ndot lookup options...
    /// 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. (*Note*: current release only queries A, IPv4)
    ///
    /// # Arguments
    /// * `host` - string hostname, if this is an invalid hostname, an error will be thrown. Currently this must be a FQDN, with a trailing `.`, e.g. `www.example.com.`. This will be fixed in a future release.
    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 std::net::{IpAddr, Ipv4Addr};

    use super::*;

    #[test]
    fn test_lookup() {
        let mut resolver = Resolver::new(ResolverConfig::default(), ResolverOpts::default()).unwrap();

        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)));
    }
}