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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::sources::interfaces::{Error, IpFuture, IpResult, Source};
use log::trace;
use std::net::IpAddr;
#[derive(Debug, Clone)]
pub enum QueryType {
TXT,
A,
}
#[derive(Debug, Clone)]
pub struct DNSSource {
server: String,
record_type: QueryType,
record: String,
}
impl DNSSource {
fn source<S: Into<String>, R: Into<String>>(
server: S,
record_type: QueryType,
record: R,
) -> Box<dyn Source> {
Box::new(DNSSource {
server: server.into(),
record_type: record_type,
record: record.into(),
})
}
}
impl std::fmt::Display for DNSSource {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"DnsSource: {} {:?} {}",
self.server, self.record_type, self.record
)
}
}
async fn resolve_server(
ares: &c_ares_resolver::FutureResolver,
server: &str,
) -> Result<String, Error> {
for query in ares
.query_a(server.into())
.await
.map_err(|x| Error::Dns(c_ares_resolver::Error::Ares(x)))?
.iter()
{
return Ok(query.ipv4().to_string());
}
Err(Error::DnsResolutionEmpty)
}
impl Source for DNSSource {
fn get_ip<'a>(&'a self) -> IpFuture<'a> {
async fn run(_self: &DNSSource) -> IpResult {
trace!("Contacting {} for {}", _self.server, _self.record);
let ares = c_ares_resolver::FutureResolver::new()?;
let server = resolve_server(&ares, &_self.server).await?;
trace!("DNS IP {}", server);
let ares = ares
.set_servers(&[&server])
.map_err(|x| Error::Dns(c_ares_resolver::Error::Ares(x)))?;
match _self.record_type {
QueryType::TXT => {
for query in ares
.query_txt(&_self.record)
.await
.map_err(|x| Error::Dns(c_ares_resolver::Error::Ares(x)))?
.iter()
{
let data = std::str::from_utf8(query.text());
if data.is_err() {
continue;
}
return Ok(data.unwrap().parse()?);
}
}
QueryType::A => {
for query in ares
.query_a(&_self.record)
.await
.map_err(|x| Error::Dns(c_ares_resolver::Error::Ares(x)))?
.iter()
{
return Ok(IpAddr::V4(query.ipv4()));
}
}
}
Err(Error::DnsResolutionEmpty)
};
Box::pin(run(self))
}
fn box_clone(&self) -> Box<dyn Source> {
Box::new(self.clone())
}
}
pub fn get_dns_sources<T>() -> T
where
T: std::iter::FromIterator<Box<dyn Source>>,
{
vec![
DNSSource::source("resolver1.opendns.com", QueryType::A, "myip.opendns.com"),
DNSSource::source("ns1.google.com", QueryType::TXT, "o-o.myaddr.l.google.com"),
DNSSource::source("ns2.google.com", QueryType::TXT, "o-o.myaddr.l.google.com"),
DNSSource::source("ns3.google.com", QueryType::TXT, "o-o.myaddr.l.google.com"),
DNSSource::source("ns4.google.com", QueryType::TXT, "o-o.myaddr.l.google.com"),
]
.into_iter()
.collect()
}