@@ -15,20 +15,17 @@ mod benchmark;
1515use benchmark:: { Benchmark , NamedTimer } ;
1616
1717use cidr_utils:: cidr:: IpCidr ;
18- use colorful:: Color ;
19- use colorful:: Colorful ;
18+ use colorful:: { Color , Colorful } ;
2019use futures:: executor:: block_on;
21- use rlimit:: Resource ;
22- use rlimit:: { getrlimit, setrlimit} ;
20+ use rlimit:: { getrlimit, setrlimit, Resource } ;
2321use std:: collections:: HashMap ;
2422use std:: fs:: File ;
25- use std:: io:: prelude:: * ;
26- use std:: io :: BufReader ;
27- use std:: net :: ToSocketAddrs ;
23+ use std:: io:: { prelude:: * , BufReader } ;
24+ use std:: net :: { IpAddr , ToSocketAddrs } ;
25+ use std:: path :: Path ;
2826use std:: process:: Command ;
29- use std:: { net:: IpAddr , time:: Duration } ;
30- use trust_dns_resolver:: config:: * ;
31- use trust_dns_resolver:: Resolver ;
27+ use std:: time:: Duration ;
28+ use trust_dns_resolver:: { config:: * , Resolver } ;
3229
3330extern crate colorful;
3431extern crate dirs;
@@ -188,85 +185,105 @@ Faster Nmap scanning with Rust."#;
188185 opts. accessible
189186 ) ;
190187}
191- #[ cfg( not( tarpaulin_include) ) ]
192- fn build_nmap_arguments < ' a > (
193- addr : & ' a str ,
194- ports : & ' a str ,
195- user_args : & ' a Vec < String > ,
196- is_ipv6 : bool ,
197- ) -> Vec < & ' a str > {
198- let mut arguments: Vec < & str > = user_args. iter ( ) . map ( AsRef :: as_ref) . collect ( ) ;
199- arguments. push ( "-vvv" ) ;
200-
201- if is_ipv6 {
202- arguments. push ( "-6" ) ;
203- }
204-
205- arguments. push ( "-p" ) ;
206- arguments. push ( ports) ;
207- arguments. push ( addr) ;
208-
209- arguments
210- }
211188
212189/// Goes through all possible IP inputs (files or via argparsing)
213190/// Parses the string(s) into IPs
214- fn parse_addresses ( opts : & Opts ) -> Vec < IpAddr > {
191+ fn parse_addresses ( input : & Opts ) -> Vec < IpAddr > {
215192 let mut ips: Vec < IpAddr > = Vec :: new ( ) ;
193+ let mut unresolved_addresses: Vec < & str > = Vec :: new ( ) ;
216194 let resolver =
217195 & Resolver :: new ( ResolverConfig :: cloudflare_tls ( ) , ResolverOpts :: default ( ) ) . unwrap ( ) ;
218196
219- for ip_or_host in & opts. addresses {
220- match read_ips_from_file ( ip_or_host. to_owned ( ) , & resolver) {
221- Ok ( x) => ips. extend ( x) ,
222- _ => match parse_to_ip ( ip_or_host. to_owned ( ) , & resolver) {
223- Ok ( x) => ips. extend ( x) ,
224- _ => {
225- warning ! (
226- format!( "Host {:?} could not be resolved." , ip_or_host) ,
227- opts. greppable,
228- opts. accessible
229- ) ;
197+ for address in & input. addresses {
198+ match parse_address ( address, resolver) {
199+ Ok ( parsed_ips) => {
200+ if !parsed_ips. is_empty ( ) {
201+ ips. extend ( parsed_ips) ;
202+ } else {
203+ unresolved_addresses. push ( address) ;
230204 }
231- } ,
205+ }
206+ _ => {
207+ warning ! (
208+ format!( "Host {:?} could not be resolved." , address) ,
209+ input. greppable,
210+ input. accessible
211+ ) ;
212+ }
232213 }
233214 }
234- ips
235- }
236215
237- /// Uses DNS to get the IPS assiocated with host
238- fn resolve_ips_from_host (
239- source : & String ,
240- resolver : & Resolver ,
241- ) -> Result < Vec < IpAddr > , std:: io:: Error > {
242- let mut ips: Vec < std:: net:: IpAddr > = Vec :: new ( ) ;
216+ // If we got to this point this can only be a file path or the wrong input.
217+ for file_path in unresolved_addresses {
218+ let file_path = Path :: new ( file_path) ;
243219
244- match resolver. lookup_ip ( & source) {
245- Ok ( x) => {
246- for ip in x. iter ( ) {
247- ips. push ( ip) ;
220+ if !file_path. is_file ( ) {
221+ warning ! (
222+ format!( "Host {:?} could not be resolved." , file_path) ,
223+ input. greppable,
224+ input. accessible
225+ ) ;
226+
227+ continue ;
228+ }
229+
230+ match read_ips_from_file ( file_path, & resolver) {
231+ Ok ( x) => ips. extend ( x) ,
232+ _ => {
233+ warning ! (
234+ format!( "Host {:?} could not be resolved." , file_path) ,
235+ input. greppable,
236+ input. accessible
237+ ) ;
248238 }
249239 }
250- _ => ( ) ,
240+ }
241+
242+ ips
243+ }
244+
245+ /// Given a string, parse it as an host, IP address, or CIDR.
246+ /// This allows us to pass files as hosts or cidr or IPs easily
247+ /// Call this everytime you have a possible IP_or_host
248+ fn parse_address ( address : & str , resolver : & Resolver ) -> Result < Vec < IpAddr > , std:: io:: Error > {
249+ let mut ips: Vec < IpAddr > = Vec :: new ( ) ;
250+
251+ match IpCidr :: from_str ( & address) {
252+ Ok ( cidr) => cidr. iter ( ) . for_each ( |ip| ips. push ( ip) ) ,
253+ _ => match format ! ( "{}:{}" , & address, 80 ) . to_socket_addrs ( ) {
254+ Ok ( mut iter) => ips. push ( iter. nth ( 0 ) . unwrap ( ) . ip ( ) ) ,
255+ _ => match resolve_ips_from_host ( address, resolver) {
256+ Ok ( hosts) => ips. extend ( hosts) ,
257+ _ => ( ) ,
258+ } ,
259+ } ,
251260 } ;
252- return Ok ( ips) ;
261+
262+ Ok ( ips)
263+ }
264+
265+ /// Uses DNS to get the IPS assiocated with host
266+ fn resolve_ips_from_host ( source : & str , resolver : & Resolver ) -> Result < Vec < IpAddr > , std:: io:: Error > {
267+ match resolver. lookup_ip ( & source) {
268+ Ok ( x) => Ok ( x. iter ( ) . collect ( ) ) ,
269+ _ => Ok ( Vec :: new ( ) ) ,
270+ }
253271}
254272
255273#[ cfg( not( tarpaulin_include) ) ]
256274/// Parses an input file of IPs and uses those
257275fn read_ips_from_file (
258- ips : String ,
276+ ips : & std :: path :: Path ,
259277 resolver : & Resolver ,
260278) -> Result < Vec < std:: net:: IpAddr > , std:: io:: Error > {
261- // if we cannot open it as a file, it is not a file so move on
262279 let file = File :: open ( ips) ?;
263280 let reader = BufReader :: new ( file) ;
264281
265282 let mut ips: Vec < std:: net:: IpAddr > = Vec :: new ( ) ;
266283
267- for str_ip in reader. lines ( ) {
268- match str_ip {
269- Ok ( x ) => match parse_to_ip ( x , resolver) {
284+ for address_line in reader. lines ( ) {
285+ match address_line {
286+ Ok ( address ) => match parse_address ( & address , resolver) {
270287 Ok ( result) => ips. extend ( result) ,
271288 Err ( e) => {
272289 debug ! ( "{} is not a valid IP or host" , e) ;
@@ -280,24 +297,25 @@ fn read_ips_from_file(
280297 Ok ( ips)
281298}
282299
283- /// Given a string, parse it as an host, IP address, or CIDR.
284- /// This allows us to pass files as hosts or cidr or IPs easily
285- /// Call this everytime you have a possible IP_or_host
286- fn parse_to_ip ( address : String , resolver : & Resolver ) -> Result < Vec < IpAddr > , std:: io:: Error > {
287- let mut ips: Vec < IpAddr > = Vec :: new ( ) ;
300+ #[ cfg( not( tarpaulin_include) ) ]
301+ fn build_nmap_arguments < ' a > (
302+ addr : & ' a str ,
303+ ports : & ' a str ,
304+ user_args : & ' a Vec < String > ,
305+ is_ipv6 : bool ,
306+ ) -> Vec < & ' a str > {
307+ let mut arguments: Vec < & str > = user_args. iter ( ) . map ( AsRef :: as_ref) . collect ( ) ;
308+ arguments. push ( "-vvv" ) ;
288309
289- match IpCidr :: from_str ( & address) {
290- Ok ( cidr) => cidr. iter ( ) . for_each ( |ip| ips. push ( ip) ) ,
291- _ => match format ! ( "{}:{}" , & address, 80 ) . to_socket_addrs ( ) {
292- Ok ( mut iter) => ips. push ( iter. nth ( 0 ) . unwrap ( ) . ip ( ) ) ,
293- _ => match resolve_ips_from_host ( & address, resolver) {
294- Ok ( hosts) => ips. extend ( hosts) ,
295- _ => ( ) ,
296- } ,
297- } ,
298- } ;
310+ if is_ipv6 {
311+ arguments. push ( "-6" ) ;
312+ }
299313
300- Ok ( ips)
314+ arguments. push ( "-p" ) ;
315+ arguments. push ( ports) ;
316+ arguments. push ( addr) ;
317+
318+ arguments
301319}
302320
303321fn adjust_ulimit_size ( opts : & Opts ) -> rlimit:: rlim {
0 commit comments