Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ sudo setcap 'cap_net_raw+ep' $(which armada)
Armada comes with help docs by running `armada -h`; however, if you want to get started immediately, the typical way to perform a port scan is the following:

```
armada -t <IP or CIDR> -p <PORT or PORT RANGE>
armada -t <IP, CIDR or Domain> -p <PORT or PORT RANGE>
```

e.g.
Expand All @@ -35,7 +35,7 @@ armada -t 8.8.8.0/24 -p 1-1000
```

### Targets
Armada supports two different kinds of targets at this time: IP addresses (e.g. `1.2.3.4`) and CIDR ranges (e.g. `8.8.8.0/24`). These different kinds of targets can be mix and matched.
Armada supports three different kinds of targets at this time: IP addresses (e.g. `1.2.3.4`), CIDR ranges (e.g. `8.8.8.0/24`), and domain names (e.g. `google.com`). These different kinds of targets can be mix and matched.

Additionally, Armada supports three ways of supplying targets:

Expand All @@ -46,7 +46,7 @@ armada -t 1.2.3.4,8.8.8.0/24 -p 1-1000

A newline delimited targets file
```
armada --target_file some_ips_and_cidrs.txt -p 1-1000
armada --target_file some_target_addresses.txt -p 1-1000
```

or via stdin
Expand Down
2 changes: 1 addition & 1 deletion armada/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ console = "0"
indicatif = "0"
rand = "0"
regex = "1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"]}
tokio = { version = "1", features = ["net", "macros", "rt-multi-thread"]}
toml = "0"
serde = { version = "1.0", features = ["derive"] }
57 changes: 42 additions & 15 deletions armada/src/args.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use std::collections::HashMap;
use std::fs::read_to_string;
use std::io::{stdin, BufRead};
use std::net::IpAddr;
use std::net::ToSocketAddrs;
use std::str::FromStr;
use std::time::Duration;

use armada_lib::{HostIterator, PortIterator};
use atty::Stream;
use cidr_utils::cidr::IpCidr;
use clap::{crate_version, Arg, ArgGroup, ArgMatches, Command};
use rand::Rng;

use crate::config::get_toml_config;

Expand All @@ -18,7 +19,9 @@ const DEFAULT_TIMEOUT_IN_MS: u64 = 1_000;

pub(crate) struct ArmadaConfig {
pub(crate) targets: HostIterator,
pub(crate) target_domains: HashMap<IpAddr, String>,
pub(crate) ports: PortIterator,
pub(crate) ip_only: bool,
pub(crate) quiet_mode: bool,
pub(crate) rate_limit: Option<usize>,
pub(crate) listening_port: u16,
Expand All @@ -35,8 +38,9 @@ pub(crate) fn get_armada_config() -> ArmadaConfig {
matches = app_config().get_matches_from(args);
}

let targets = get_targets(&matches);
let (targets, target_domains) = get_targets(&matches);
let ports = get_ports(&matches);
let ip_only = get_ip_only_mode(&matches);
let quiet_mode = get_quiet_mode(&matches);
let rate_limit = get_rate_limit(&matches);
let listening_port = get_listening_port(&matches);
Expand All @@ -53,7 +57,9 @@ pub(crate) fn get_armada_config() -> ArmadaConfig {

ArmadaConfig {
targets,
target_domains,
ports,
ip_only,
quiet_mode,
rate_limit,
listening_port,
Expand All @@ -64,7 +70,7 @@ pub(crate) fn get_armada_config() -> ArmadaConfig {
}
}

fn get_targets(matches: &ArgMatches) -> HostIterator {
fn get_targets(matches: &ArgMatches) -> (HostIterator, HashMap<IpAddr, String>) {
let targets: Vec<String> = if let Some(targets_cli) = matches.values_of("targets") {
// use targets passed in via cli
targets_cli.map(str::to_owned).collect()
Expand All @@ -80,18 +86,31 @@ fn get_targets(matches: &ArgMatches) -> HostIterator {
stdin().lock().lines().filter_map(Result::ok).collect()
};

targets
.into_iter()
.fold(HostIterator::new(), |host_iterator, target_str| {
if let Ok(ip_addr) = IpAddr::from_str(&target_str) {
host_iterator.add_ip(ip_addr)
} else {
// we'll force this to parse. If it fails, then an illegal value was placed into the target list and we should panic here.
let cidr = IpCidr::from_str(&target_str).expect(&format!("Unable to parse target '{}'.", target_str));
let mut target_domains = HashMap::new();
(
targets
.into_iter()
.fold(HostIterator::new(), |host_iterator, target_str| {
if let Ok(ip_addr) = IpAddr::from_str(&target_str) {
host_iterator.add_ip(ip_addr)
} else if let Some(ip_addr) = (target_str.clone(), 0) // resolve ip address of domain
.to_socket_addrs()
.ok()
.map(|mut addrs| addrs.next())
.flatten()
{
target_domains.insert(ip_addr.ip(), target_str); // store the domain name for this IP so we can print it later
host_iterator.add_ip(ip_addr.ip())
} else {
// we'll force this to parse. If it fails, then an illegal value was placed into the target list and we should panic here.
let cidr =
IpCidr::from_str(&target_str).expect(&format!("Unable to parse target '{}'.", target_str));

host_iterator.add_cidr(cidr)
}
})
host_iterator.add_cidr(cidr)
}
}),
target_domains,
)
}

fn get_ports(matches: &ArgMatches) -> PortIterator {
Expand Down Expand Up @@ -139,6 +158,10 @@ fn get_ports(matches: &ArgMatches) -> PortIterator {
})
}

fn get_ip_only_mode(matches: &ArgMatches) -> bool {
matches.is_present("ip_only")
}

fn get_quiet_mode(matches: &ArgMatches) -> bool {
matches.is_present("quiet")
}
Expand Down Expand Up @@ -167,7 +190,7 @@ fn get_listening_port(matches: &ArgMatches) -> u16 {
.parse::<u16>()
.expect(&format!("Unable to parse listening port value '{}'.", value))
})
.unwrap_or_else(|| rand::thread_rng().gen_range(50_000..60_000))
.unwrap_or_else(|| rand::random_range(50_000..60_000))
}

fn get_retries(matches: &ArgMatches) -> u8 {
Expand Down Expand Up @@ -237,6 +260,10 @@ fn app_config() -> Command<'static> {
.value_delimiter(',')
.conflicts_with_all(&["top100", "top1000"])
.required_unless_present_any(&["top100", "top1000", "toml_config"]))
.arg(Arg::new("ip_only")
.help("Outputs only resolved IP addresses instead of domain names.")
.long("ip-only")
.takes_value(false))
.arg(Arg::new("quiet")
.help("Disables any progress reporting during the scan.")
.short('q')
Expand Down
40 changes: 30 additions & 10 deletions armada/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
mod args;
mod config;
mod ranges;
mod run_variants;
mod config;

use std::net::{
IpAddr,
Ipv4Addr,
Ipv6Addr,
};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

use armada_lib::Armada;

Expand All @@ -17,14 +13,16 @@ use crate::args::ArmadaConfig;
async fn main() {
let ArmadaConfig {
targets,
target_domains,
ports,
ip_only,
quiet_mode,
rate_limit,
listening_port,
retries,
timeout,
source_ips,
stream_results
stream_results,
} = args::get_armada_config();

let armada = Armada::new(listening_port);
Expand All @@ -35,21 +33,43 @@ async fn main() {
use run_variants::QuietArmada;

armada
.run_quiet(targets, ports, source_ipv4, source_ipv6, retries, timeout, rate_limit, stream_results)
.run_quiet(
targets,
ports,
source_ipv4,
source_ipv6,
retries,
timeout,
rate_limit,
stream_results,
)
.await
} else {
use run_variants::ProgressArmada;

armada
.run_with_stats(targets, ports, source_ipv4, source_ipv6, retries, timeout, rate_limit, stream_results)
.run_with_stats(
targets,
ports,
source_ipv4,
source_ipv6,
retries,
timeout,
rate_limit,
stream_results,
)
.await
};

if !stream_results {
syn_scan_results.sort();

syn_scan_results.into_iter().for_each(|remote| {
println!("{}:{}", remote.ip(), remote.port());
let ip = match target_domains.get(&remote.ip()) {
Some(domain) if !ip_only => domain,
_ => &remote.ip().to_string()
};
println!("{}:{}", ip, remote.port());
});
}
}
Expand Down