@@ -30,33 +30,10 @@ use crate::warning;
30
30
pub fn parse_addresses ( input : & Opts ) -> Vec < IpAddr > {
31
31
let mut ips: Vec < IpAddr > = Vec :: new ( ) ;
32
32
let mut unresolved_addresses: Vec < & str > = Vec :: new ( ) ;
33
- let mut self_resolve = true ;
34
- let mut backup_resolver =
35
- Resolver :: new ( ResolverConfig :: cloudflare_tls ( ) , ResolverOpts :: default ( ) ) . unwrap ( ) ;
36
-
37
- if let Some ( resolver) = & input. resolver {
38
- let resolver_ips = if let Ok ( r) = read_resolver_from_file ( resolver) {
39
- r
40
- } else {
41
- // Get resolvers from the comma-delimited list string
42
- resolver
43
- . split ( ',' )
44
- . filter_map ( |r| IpAddr :: from_str ( r) . ok ( ) )
45
- . collect :: < Vec < _ > > ( )
46
- } ;
47
- let mut rc = ResolverConfig :: new ( ) ;
48
- for ip in resolver_ips {
49
- rc. add_name_server ( NameServerConfig :: new (
50
- SocketAddr :: new ( ip, 53 ) ,
51
- Protocol :: Udp ,
52
- ) ) ;
53
- }
54
- backup_resolver = Resolver :: new ( rc, ResolverOpts :: default ( ) ) . unwrap ( ) ;
55
- self_resolve = false ;
56
- }
33
+ let backup_resolver = get_resolver ( & input. resolver ) ;
57
34
58
35
for address in & input. addresses {
59
- let parsed_ips = parse_address ( address, & backup_resolver, self_resolve ) ;
36
+ let parsed_ips = parse_address ( address, & backup_resolver) ;
60
37
if !parsed_ips. is_empty ( ) {
61
38
ips. extend ( parsed_ips) ;
62
39
} else {
@@ -78,7 +55,7 @@ pub fn parse_addresses(input: &Opts) -> Vec<IpAddr> {
78
55
continue ;
79
56
}
80
57
81
- if let Ok ( x) = read_ips_from_file ( file_path, & backup_resolver, self_resolve ) {
58
+ if let Ok ( x) = read_ips_from_file ( file_path, & backup_resolver) {
82
59
ips. extend ( x) ;
83
60
} else {
84
61
warning ! (
@@ -103,17 +80,13 @@ pub fn parse_addresses(input: &Opts) -> Vec<IpAddr> {
103
80
/// ```rust
104
81
/// # use rustscan::address::parse_address;
105
82
/// # use hickory_resolver::Resolver;
106
- /// let ips = parse_address("127.0.0.1", &Resolver::default().unwrap(), false );
83
+ /// let ips = parse_address("127.0.0.1", &Resolver::default().unwrap());
107
84
/// ```
108
- pub fn parse_address ( address : & str , resolver : & Resolver , self_resolve : bool ) -> Vec < IpAddr > {
85
+ pub fn parse_address ( address : & str , resolver : & Resolver ) -> Vec < IpAddr > {
109
86
IpCidr :: from_str ( address)
110
87
. map ( |cidr| cidr. iter ( ) . collect ( ) )
111
88
. ok ( )
112
89
. or_else ( || {
113
- if !self_resolve {
114
- // This will trigger `unwrap_or_else` then call `resolve_ips_from_host` function
115
- return None ;
116
- } ;
117
90
format ! ( "{}:{}" , & address, 80 )
118
91
. to_socket_addrs ( )
119
92
. ok ( )
@@ -124,7 +97,7 @@ pub fn parse_address(address: &str, resolver: &Resolver, self_resolve: bool) ->
124
97
125
98
/// Uses DNS to get the IPS associated with host
126
99
fn resolve_ips_from_host ( source : & str , backup_resolver : & Resolver ) -> Vec < IpAddr > {
127
- let mut ips: Vec < std :: net :: IpAddr > = Vec :: new ( ) ;
100
+ let mut ips: Vec < IpAddr > = Vec :: new ( ) ;
128
101
129
102
if let Ok ( addrs) = source. to_socket_addrs ( ) {
130
103
for ip in addrs {
@@ -137,13 +110,51 @@ fn resolve_ips_from_host(source: &str, backup_resolver: &Resolver) -> Vec<IpAddr
137
110
ips
138
111
}
139
112
140
- fn read_resolver_from_file ( path : & str ) -> Result < Vec < std:: net:: IpAddr > , std:: io:: Error > {
141
- let mut ips = Vec :: new ( ) ;
142
- fs:: read_to_string ( path) ?. split ( '\n' ) . for_each ( |line| {
143
- if let Ok ( ip) = IpAddr :: from_str ( line) {
144
- ips. push ( ip)
113
+ /// Derive a DNS resolver.
114
+ ///
115
+ /// 1. if the `resolver` parameter has been set:
116
+ /// 1. assume the parameter is a path and attempt to read IPs.
117
+ /// 2. parse the input as a comma-separated list of IPs.
118
+ /// 2. if `resolver` is not set:
119
+ /// 1. attempt to derive a resolver from the system config. (e.g.
120
+ /// `/etc/resolv.conf` on *nix).
121
+ /// 2. finally, build a CloudFlare-based resolver (default
122
+ /// behaviour).
123
+ fn get_resolver ( resolver : & Option < String > ) -> Resolver {
124
+ match resolver {
125
+ Some ( r) => {
126
+ let mut config = ResolverConfig :: new ( ) ;
127
+ let resolver_ips = match read_resolver_from_file ( r) {
128
+ Ok ( ips) => ips,
129
+ Err ( _) => r
130
+ . split ( ',' )
131
+ . filter_map ( |r| IpAddr :: from_str ( r) . ok ( ) )
132
+ . collect :: < Vec < _ > > ( ) ,
133
+ } ;
134
+ for ip in resolver_ips {
135
+ config. add_name_server ( NameServerConfig :: new (
136
+ SocketAddr :: new ( ip, 53 ) ,
137
+ Protocol :: Udp ,
138
+ ) ) ;
139
+ }
140
+ Resolver :: new ( config, ResolverOpts :: default ( ) ) . unwrap ( )
145
141
}
146
- } ) ;
142
+ None => match Resolver :: from_system_conf ( ) {
143
+ Ok ( resolver) => resolver,
144
+ Err ( _) => {
145
+ Resolver :: new ( ResolverConfig :: cloudflare_tls ( ) , ResolverOpts :: default ( ) ) . unwrap ( )
146
+ }
147
+ } ,
148
+ }
149
+ }
150
+
151
+ /// Parses and input file of IPs for use in DNS resolution.
152
+ fn read_resolver_from_file ( path : & str ) -> Result < Vec < IpAddr > , std:: io:: Error > {
153
+ let ips = fs:: read_to_string ( path) ?
154
+ . lines ( )
155
+ . filter_map ( |line| IpAddr :: from_str ( line. trim ( ) ) . ok ( ) )
156
+ . collect ( ) ;
157
+
147
158
Ok ( ips)
148
159
}
149
160
@@ -152,16 +163,15 @@ fn read_resolver_from_file(path: &str) -> Result<Vec<std::net::IpAddr>, std::io:
152
163
fn read_ips_from_file (
153
164
ips : & std:: path:: Path ,
154
165
backup_resolver : & Resolver ,
155
- self_resolve : bool ,
156
- ) -> Result < Vec < std:: net:: IpAddr > , std:: io:: Error > {
166
+ ) -> Result < Vec < IpAddr > , std:: io:: Error > {
157
167
let file = File :: open ( ips) ?;
158
168
let reader = BufReader :: new ( file) ;
159
169
160
- let mut ips: Vec < std :: net :: IpAddr > = Vec :: new ( ) ;
170
+ let mut ips: Vec < IpAddr > = Vec :: new ( ) ;
161
171
162
172
for address_line in reader. lines ( ) {
163
173
if let Ok ( address) = address_line {
164
- ips. extend ( parse_address ( & address, backup_resolver, self_resolve ) ) ;
174
+ ips. extend ( parse_address ( & address, backup_resolver) ) ;
165
175
} else {
166
176
debug ! ( "Line in file is not valid" ) ;
167
177
}
@@ -172,7 +182,7 @@ fn read_ips_from_file(
172
182
173
183
#[ cfg( test) ]
174
184
mod tests {
175
- use super :: { parse_addresses, Opts } ;
185
+ use super :: { get_resolver , parse_addresses, Opts } ;
176
186
use std:: net:: Ipv4Addr ;
177
187
178
188
#[ test]
@@ -245,4 +255,27 @@ mod tests {
245
255
let ips = parse_addresses ( & opts) ;
246
256
assert_eq ! ( ips. len( ) , 0 ) ;
247
257
}
258
+
259
+ #[ test]
260
+ fn resolver_default_cloudflare ( ) {
261
+ let opts = Opts :: default ( ) ;
262
+
263
+ let resolver = get_resolver ( & opts. resolver ) ;
264
+ let lookup = resolver. lookup_ip ( "www.example.com." ) . unwrap ( ) ;
265
+
266
+ assert ! ( opts. resolver. is_none( ) ) ;
267
+ assert ! ( lookup. iter( ) . next( ) . is_some( ) ) ;
268
+ }
269
+
270
+ #[ test]
271
+ fn resolver_args_google_dns ( ) {
272
+ let mut opts = Opts :: default ( ) ;
273
+ // https://developers.google.com/speed/public-dns
274
+ opts. resolver = Some ( "8.8.8.8,8.8.4.4" . to_owned ( ) ) ;
275
+
276
+ let resolver = get_resolver ( & opts. resolver ) ;
277
+ let lookup = resolver. lookup_ip ( "www.example.com." ) . unwrap ( ) ;
278
+
279
+ assert ! ( lookup. iter( ) . next( ) . is_some( ) ) ;
280
+ }
248
281
}
0 commit comments