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
use std::net::*;
use std::str::FromStr;
use trust_dns::client::{Client, SyncClient};
use trust_dns::op::DnsResponse;
use trust_dns::rr::{DNSClass, Name, RData, Record, RecordType};
use trust_dns::udp::UdpClientConnection;
use failure::*;

mod dns_ip;
pub use dns_ip::{Provider as DnsIpProvider};

#[derive(Fail, Debug)]
enum Errors {
    #[fail(display = "No response.")]
    NoResponse,
}

pub enum Provider {
    OpenDNS,
}

impl Default for Provider {
    fn default() -> Provider {
        Provider::OpenDNS
    }
}

impl Provider {
    pub fn query_ipv4(&self) -> Result<Ipv4Addr, Error> {
        match self {
            Provider::OpenDNS => self.query_ipv4_opendns(),
        }
    }

    pub fn query_ipv6(&self) -> Result<Ipv6Addr, Error> {
        match self {
            Provider::OpenDNS => self.query_ipv6_opendns(),
        }
    }

    fn query_ipv4_opendns(&self) -> Result<Ipv4Addr, Error> {
        let address = "208.67.222.222:53".parse()?;
        let conn = UdpClientConnection::new(address)?;
        let client = SyncClient::new(conn);

        let name = Name::from_str("myip.opendns.com.")?;

        let response: DnsResponse = client.query(&name, DNSClass::IN, RecordType::A)?;

        let answers: &[Record] = response.answers();

        if let &RData::A(ref ip) = answers[0].rdata() {
            Ok(*ip)
        } else {
            bail!(Errors::NoResponse)
        }
    }

    fn query_ipv6_opendns(&self) -> Result<Ipv6Addr, Error> {
        let address = "[2620:119:35::35]:53".parse()?;
        let conn = UdpClientConnection::new(address)?;
        let client = SyncClient::new(conn);

        let name = Name::from_str("myip.opendns.com.")?;

        let response: DnsResponse = client.query(&name, DNSClass::IN, RecordType::AAAA)?;

        let answers: &[Record] = response.answers();

        if let &RData::AAAA(ref ip) = answers[0].rdata() {
            Ok(*ip)
        } else {
            bail!(Errors::NoResponse)
        }
    }
}