Skip to content

Commit 4dcd929

Browse files
bernardoamcbee-san
andauthored
Make address an optional instead of a positional argument (#271)
This has the benefit of making the input flexible and fixing an existing bug that happens when a single port is specified, see #211. Other benefits: - We are now parsing only failures as a file, reducing the amount of attempts to open a file. - We check if a file exists before trying to open it. Fixes #211 Co-authored-by: Bee <[email protected]>
1 parent 5b35a09 commit 4dcd929

File tree

2 files changed

+98
-79
lines changed

2 files changed

+98
-79
lines changed

src/input.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use serde_derive::Deserialize;
22
use std::collections::HashMap;
33
use std::fs;
4+
45
use structopt::{clap::arg_enum, StructOpt};
56

67
const LOWEST_PORT_NUMBER: u16 = 1;
@@ -57,7 +58,7 @@ fn parse_range(input: &str) -> Result<PortRange, String> {
5758
/// - GitHub https://github.com/RustScan/RustScan
5859
pub struct Opts {
5960
/// A list of comma separated CIDRs, IPs, or hosts to be scanned.
60-
#[structopt(use_delimiter = true)]
61+
#[structopt(short, long, use_delimiter = true)]
6162
pub addresses: Vec<String>,
6263

6364
/// A list of comma separed ports to be scanned. Example: 80,443,8080.

src/main.rs

Lines changed: 96 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,17 @@ mod benchmark;
1515
use benchmark::{Benchmark, NamedTimer};
1616

1717
use cidr_utils::cidr::IpCidr;
18-
use colorful::Color;
19-
use colorful::Colorful;
18+
use colorful::{Color, Colorful};
2019
use futures::executor::block_on;
21-
use rlimit::Resource;
22-
use rlimit::{getrlimit, setrlimit};
20+
use rlimit::{getrlimit, setrlimit, Resource};
2321
use std::collections::HashMap;
2422
use 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;
2826
use 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

3330
extern crate colorful;
3431
extern 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
257275
fn 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

303321
fn adjust_ulimit_size(opts: &Opts) -> rlimit::rlim {

0 commit comments

Comments
 (0)