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
128
129
130
131
132
133
134
135
136
137
use async_trait::async_trait;
use hickory_client::proto::runtime::TokioRuntimeProvider;
use hickory_resolver::{
name_server::{GenericConnector, TokioConnectionProvider},
Resolver as HickoryResolver,
};
use tokio::time;
use crate::{
interfaces::lookup::LookUpHostFuture,
types::{config::resolver::ResolverConfig, func::AsyncIPResolveFunc},
};
/// IP address resolver component
#[derive(Clone)]
pub struct Resolver {
pub config: ResolverConfig,
pub inner: HickoryResolver<GenericConnector<TokioRuntimeProvider>>,
}
impl Default for Resolver {
/// Create [`Resolver`] with defaults
///
/// # Examples
///
/// ```
/// use subscan::resolver::Resolver;
/// use subscan::constants::{
/// DEFAULT_RESOLVER_CONCURRENCY,
/// DEFAULT_RESOLVER_TIMEOUT
/// };
///
/// let resolver = Resolver::default();
///
/// assert!(!resolver.config.disabled);
///
/// assert_eq!(resolver.config.timeout, DEFAULT_RESOLVER_TIMEOUT);
/// assert_eq!(resolver.config.concurrency, DEFAULT_RESOLVER_CONCURRENCY);
/// ```
fn default() -> Self {
let config = ResolverConfig::default();
let provider = TokioConnectionProvider::default();
let inner = HickoryResolver::builder_with_config(config.clone().inner, provider).build();
Self { inner, config }
}
}
impl From<ResolverConfig> for Resolver {
fn from(config: ResolverConfig) -> Self {
let provider = TokioConnectionProvider::default();
let inner = HickoryResolver::builder_with_config(config.clone().inner, provider).build();
Self { inner, config }
}
}
impl Resolver {
pub fn boxed_from(config: ResolverConfig) -> Box<Self> {
let provider = TokioConnectionProvider::default();
let inner = HickoryResolver::builder_with_config(config.clone().inner, provider).build();
Box::new(Self { inner, config })
}
}
#[async_trait]
impl LookUpHostFuture for Resolver {
/// Returns future object that resolves IP address of any domain, if the
/// [`disabled`](crate::types::config::resolver::ResolverConfig::disabled)
/// option sets to [`true`] returns a future object that returns [`None`]
///
/// # Examples
///
/// ```
/// use subscan::types::config::resolver::ResolverConfig;
/// use subscan::resolver::Resolver;
/// use crate::subscan::interfaces::lookup::LookUpHostFuture;
///
/// #[tokio::main]
/// async fn main() {
/// let mut config = ResolverConfig::default();
///
/// assert!(!config.disabled);
///
/// config.disabled = true;
///
/// let resolver = Resolver::from(config.clone());
/// let lookup_ip = resolver.lookup_host_future().await;
///
/// assert!(lookup_ip("foo.com".into()).await.is_none());
/// }
/// ```
async fn lookup_host_future(&self) -> AsyncIPResolveFunc {
if !self.config.disabled {
let timeout = self.config.timeout;
let inner = self.inner.clone();
Box::new(move |domain: String| {
let resolver = inner.clone();
Box::pin({
async move {
time::timeout(timeout, resolver.lookup_ip(&domain))
.await
.ok()?
.ok()?
.iter()
.next()
}
})
})
} else {
Box::new(|_: String| Box::pin(async move { None }))
}
}
/// Returns resolver config
///
/// # Examples
///
/// ```
/// use subscan::resolver::Resolver;
/// use subscan::types::config::resolver::ResolverConfig;
/// use crate::subscan::interfaces::lookup::LookUpHostFuture;
///
/// #[tokio::main]
/// async fn main() {
/// let resolver = Resolver::from(ResolverConfig::default());
///
/// assert!(!resolver.config().await.disabled)
/// }
/// ```
async fn config(&self) -> ResolverConfig {
self.config.clone()
}
}