use rand::Rng;
use std::fmt;
use std::fs::File;
use std::io::{self, BufRead};
use std::sync::mpsc;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
};
use std::time::Duration;
use crate::device;
use crate::dns_resolver::{DnsResolveResult, DnsResolver};
use crate::input::parse_bandwidth;
use crate::model::StatusTable;
use crate::send::SendDog;
use crate::speed_test::{BandwidthLimiter, SpeedTester};
use crate::state::BruteForceState;
use crate::structs::RetryStruct;
use crate::subdata;
use crate::verify::{DomainVerifier, VerifyResult};
use crate::wildcard::WildcardDetector;
use crate::{handle, recv, send};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BruteForceProgressPhase {
SendingQueries,
WaitingForResponses,
Completed,
}
#[derive(Debug, Clone)]
pub struct BruteForceProgress {
pub phase: BruteForceProgressPhase,
pub sent_queries: usize,
pub total_queries: usize,
pub discovered_domains: usize,
pub current_target: Option<String>,
}
pub type ProgressCallback = Arc<dyn Fn(BruteForceProgress) + Send + Sync>;
#[derive(Clone)]
pub struct SubdomainBruteConfig {
pub domains: Vec<String>,
pub resolvers: Vec<String>,
pub dictionary_file: Option<String>,
pub dictionary: Option<Vec<String>>,
pub skip_wildcard: bool,
pub bandwidth_limit: Option<String>,
pub verify_mode: bool,
pub resolve_records: bool,
pub silent: bool,
pub device: Option<String>,
pub progress_callback: Option<ProgressCallback>,
}
impl fmt::Debug for SubdomainBruteConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SubdomainBruteConfig")
.field("domains", &self.domains)
.field("resolvers", &self.resolvers)
.field("dictionary_file", &self.dictionary_file)
.field("dictionary", &self.dictionary)
.field("skip_wildcard", &self.skip_wildcard)
.field("bandwidth_limit", &self.bandwidth_limit)
.field("verify_mode", &self.verify_mode)
.field("resolve_records", &self.resolve_records)
.field("silent", &self.silent)
.field("device", &self.device)
.field(
"progress_callback",
&self.progress_callback.as_ref().map(|_| "<callback>"),
)
.finish()
}
}
impl Default for SubdomainBruteConfig {
fn default() -> Self {
SubdomainBruteConfig {
domains: Vec::new(),
resolvers: Vec::new(),
dictionary_file: None,
dictionary: None,
skip_wildcard: true,
bandwidth_limit: Some("3M".to_string()),
verify_mode: false,
resolve_records: false,
silent: false,
device: None,
progress_callback: None,
}
}
}
#[derive(Debug, Clone)]
pub struct SubdomainResult {
pub domain: String,
pub ip: String,
pub record_type: String,
pub verified: Option<VerifyResult>,
pub dns_records: Option<DnsResolveResult>,
}
pub struct SubdomainBruteEngine {
config: SubdomainBruteConfig,
wildcard_detector: Option<WildcardDetector>,
verifier: Option<DomainVerifier>,
dns_resolver: Option<DnsResolver>,
_bandwidth_limiter: Option<BandwidthLimiter>,
state: BruteForceState,
}
impl SubdomainBruteEngine {
pub async fn new(config: SubdomainBruteConfig) -> Result<Self, Box<dyn std::error::Error>> {
let wildcard_detector = if config.skip_wildcard {
Some(WildcardDetector::new().await?)
} else {
None
};
let verifier = if config.verify_mode {
Some(DomainVerifier::new(10)?)
} else {
None
};
let dns_resolver = if config.resolve_records {
Some(DnsResolver::new().await?)
} else {
None
};
let bandwidth_limiter = if let Some(ref bandwidth) = config.bandwidth_limit {
let bytes_per_sec = parse_bandwidth(bandwidth)?;
Some(BandwidthLimiter::new(bytes_per_sec))
} else {
None
};
Ok(SubdomainBruteEngine {
config,
wildcard_detector,
verifier,
dns_resolver,
_bandwidth_limiter: bandwidth_limiter,
state: BruteForceState::new(),
})
}
pub async fn run_brute_force(
&self,
) -> Result<Vec<SubdomainResult>, Box<dyn std::error::Error>> {
let mut results = Vec::new();
let mut discovered_domains = Vec::new();
if let Some(ref detector) = self.wildcard_detector {
for domain in &self.config.domains {
if detector.detect_wildcard(domain).await? {
if !self.config.silent {
println!("检测到泛解析域名: {}", domain);
}
}
}
}
let core_results = self.run_core_brute_force().await?;
for result in core_results {
let should_skip = if let Some(ref detector) = self.wildcard_detector {
if let Ok(ip) = result.ip.parse() {
detector.is_wildcard_result(&result.domain, &ip)
} else {
false
}
} else {
false
};
if !should_skip {
discovered_domains.push(result.domain.clone());
results.push(result);
}
}
if let Some(ref verifier) = self.verifier {
let verify_results = verifier.verify_domains(discovered_domains.clone()).await;
let verify_map: std::collections::HashMap<String, VerifyResult> = verify_results
.into_iter()
.map(|r| (r.domain.clone(), r))
.collect();
for result in &mut results {
if let Some(verify_result) = verify_map.get(&result.domain) {
result.verified = Some(verify_result.clone());
}
}
}
if let Some(ref resolver) = self.dns_resolver {
let dns_results = resolver.resolve_domains(discovered_domains).await;
let dns_map: std::collections::HashMap<String, DnsResolveResult> = dns_results
.into_iter()
.map(|r| (r.domain.clone(), r))
.collect();
for result in &mut results {
if let Some(dns_result) = dns_map.get(&result.domain) {
result.dns_records = Some(dns_result.clone());
}
}
}
Ok(results)
}
async fn run_core_brute_force(
&self,
) -> Result<Vec<SubdomainResult>, Box<dyn std::error::Error>> {
self.state.clear_discovered_domains();
let ether = if let Some(device_name) = &self.config.device {
match device::get_device_by_name_for_dns(device_name, &self.config.resolvers) {
Ok(device) => {
if !self.config.silent {
println!("使用指定网络设备: {}", device_name);
}
device
}
Err(error) => {
if !self.config.silent {
eprintln!(
"指定网络设备 {} 不可用于原始以太网发包: {},尝试自动检测",
device_name, error
);
}
device::auto_get_devices_for_dns(&self.config.resolvers)
.await
.map_err(|detect_error| {
format!(
"自动检测网络设备失败: {}; 指定设备错误: {}",
detect_error, error
)
})?
}
}
} else {
device::auto_get_devices_for_dns(&self.config.resolvers).await?
};
if !self.config.silent {
println!("使用网络设备: {:?}", ether.device);
}
let mut rng: rand::prelude::ThreadRng = rand::thread_rng();
let flag_id: u16 = rng.gen_range(400..655);
let device_clone = ether.device.clone();
let running = Arc::new(AtomicBool::new(true));
let senddog = Arc::new(Mutex::new(SendDog::new(
ether,
self.config.resolvers.clone(),
flag_id,
)));
let sub_domain_list = if let Some(ref dictionary) = self.config.dictionary {
dictionary.clone()
} else if let Some(ref file_path) = self.config.dictionary_file {
Self::load_dictionary_from_file(file_path)?
} else {
subdata::get_default_sub_next_data()
.iter()
.map(|&s| s.to_string())
.collect()
};
let total_queries = sub_domain_list
.len()
.saturating_mul(self.config.domains.len());
let (dns_send, dns_recv) = mpsc::channel();
let (retry_send, retry_recv): (
mpsc::Sender<Arc<std::sync::RwLock<RetryStruct>>>,
mpsc::Receiver<Arc<std::sync::RwLock<RetryStruct>>>,
) = mpsc::channel();
let running_clone = running.clone();
let silent = self.config.silent;
let handle1 = tokio::task::spawn_blocking(move || {
recv::recv(device_clone, dns_send, running_clone);
});
let running_clone = running.clone();
let state_clone = self.state.clone();
let handle2 = tokio::task::spawn_blocking(move || {
handle::handle_dns_packet(dns_recv, flag_id, running_clone, silent, state_clone);
});
let running_clone = running.clone();
let senddog_clone = senddog.clone();
let state_clone = self.state.clone();
let handle3 = tokio::spawn(async move {
Self::handle_timeout_domains_with_state(
running_clone,
senddog_clone,
retry_send,
state_clone,
)
.await;
});
let running_clone = running.clone();
let senddog_clone = senddog.clone();
let handle4 = tokio::spawn(async move {
Self::handle_retry_domains_static(running_clone, senddog_clone, retry_recv).await;
});
let bandwidth_limiter = if let Some(ref limit_str) = self.config.bandwidth_limit {
if let Ok(limit) = crate::input::parse_bandwidth(limit_str) {
Some(crate::speed_test::BandwidthLimiter::new(limit))
} else {
None
}
} else {
None
};
let query_count = self
.send_dns_queries(
&senddog,
&sub_domain_list,
&bandwidth_limiter,
total_queries,
)
.await?;
if !self.config.silent {
println!("子域名查询数量: {}", query_count);
}
self.wait_for_completion(query_count).await;
running.store(false, Ordering::Relaxed);
let _ = tokio::join!(handle1, handle2, handle3, handle4);
drop(senddog);
let discovered = self.state.get_discovered_domains();
let results: Vec<SubdomainResult> = discovered
.into_iter()
.map(|d| SubdomainResult {
domain: d.domain,
ip: d.ip,
record_type: d.record_type,
verified: None,
dns_records: None,
})
.collect();
self.emit_progress(BruteForceProgress {
phase: BruteForceProgressPhase::Completed,
sent_queries: query_count,
total_queries: query_count.max(total_queries),
discovered_domains: results.len(),
current_target: None,
});
self.cleanup_resources();
Ok(results)
}
fn load_dictionary_from_file(
file_path: &str,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
let file = File::open(file_path)?;
let reader = io::BufReader::new(file);
let mut dictionary = Vec::new();
for line in reader.lines() {
if let Ok(word) = line {
dictionary.push(word.trim().to_string());
}
}
Ok(dictionary)
}
async fn send_dns_queries(
&self,
senddog: &Arc<Mutex<SendDog>>,
sub_domain_list: &[String],
bandwidth_limiter: &Option<crate::speed_test::BandwidthLimiter>,
total_queries: usize,
) -> Result<usize, Box<dyn std::error::Error>> {
if let Some(ref file_path) = self.config.dictionary_file {
self.send_queries_from_file(file_path, senddog, bandwidth_limiter, total_queries)
.await
} else {
self.send_queries_from_list(sub_domain_list, senddog, bandwidth_limiter, total_queries)
.await
}
}
async fn send_queries_from_file(
&self,
path: &str,
senddog: &Arc<Mutex<SendDog>>,
bandwidth_limiter: &Option<crate::speed_test::BandwidthLimiter>,
total_queries: usize,
) -> Result<usize, Box<dyn std::error::Error>> {
let file = File::open(path)?;
let reader = io::BufReader::new(file);
let mut count = 0;
for line in reader.lines() {
if let Ok(sub) = line {
for domain in &self.config.domains {
if let Some(ref limiter) = bandwidth_limiter {
limiter.can_send(64).await;
}
let mut senddog = match senddog.lock() {
Ok(guard) => guard,
Err(e) => {
eprintln!("错误:无法锁定 senddog: {}", e);
continue;
}
};
let mut final_domain = sub.clone();
final_domain.push_str(".");
final_domain = final_domain + domain;
let dns_name = senddog.chose_dns();
let (flagid2, scr_port) =
senddog.build_status_table(final_domain.as_str(), dns_name.as_str(), 1);
record_query_status(
&self.state,
&final_domain,
&dns_name,
flagid2,
scr_port,
1,
);
senddog.send(final_domain, dns_name, scr_port, flagid2);
count += 1;
self.emit_query_progress(count, total_queries, Some(domain));
}
}
}
Ok(count)
}
async fn send_queries_from_list(
&self,
sub_domain_list: &[String],
senddog: &Arc<Mutex<SendDog>>,
bandwidth_limiter: &Option<crate::speed_test::BandwidthLimiter>,
total_queries: usize,
) -> Result<usize, Box<dyn std::error::Error>> {
let mut count = 0;
for sub in sub_domain_list {
for domain in &self.config.domains {
if let Some(ref limiter) = bandwidth_limiter {
limiter.can_send(64).await;
}
let mut senddog = match senddog.lock() {
Ok(guard) => guard,
Err(e) => {
eprintln!("错误:无法锁定 senddog: {}", e);
continue;
}
};
let mut final_domain = sub.clone();
final_domain.push_str(".");
final_domain = final_domain + domain;
let dns_name = senddog.chose_dns();
let (flagid2, scr_port) =
senddog.build_status_table(final_domain.as_str(), dns_name.as_str(), 1);
record_query_status(&self.state, &final_domain, &dns_name, flagid2, scr_port, 1);
senddog.send(final_domain, dns_name, scr_port, flagid2);
count += 1;
self.emit_query_progress(count, total_queries, Some(domain));
}
}
Ok(count)
}
async fn handle_timeout_domains_with_state(
running: Arc<AtomicBool>,
senddog: Arc<Mutex<SendDog>>,
retry_send: mpsc::Sender<Arc<std::sync::RwLock<RetryStruct>>>,
state: BruteForceState,
) {
while running.load(Ordering::Relaxed) {
let max_length = (1000000 / 10) as usize;
let datas = state.get_timeout_data(max_length);
let is_delay = datas.len() > 100;
for local_data in &datas {
let index = local_data.index;
let mut value = local_data.v.clone();
if value.retry >= 5 {
match state.search_from_index_and_delete(index as u32) {
Ok(_data) => {
}
Err(_) => (),
}
continue;
}
let dns_name = {
match senddog.lock() {
Ok(guard) => guard.chose_dns(),
Err(e) => {
eprintln!("错误:无法锁定 senddog: {}", e);
continue;
}
}
};
value.retry += 1;
value.time = chrono::Utc::now().timestamp() as u64;
value.dns = dns_name;
let value_c = value.clone();
let _ = state.search_from_index_and_delete(index as u32);
state.append_status(value_c, index as u32);
let (flag_id, src_port) = send::generate_flag_index_from_map(index as usize);
let retry_struct = RetryStruct {
domain: value.domain,
dns: value.dns,
src_port,
flag_id,
domain_level: value.domain_level as usize,
};
if let Err(e) = retry_send.send(Arc::new(std::sync::RwLock::new(retry_struct))) {
eprintln!("警告:重试队列已关闭,无法发送重试数据: {}", e);
}
if is_delay {
let sleep_duration = rand::thread_rng().gen_range(100..=400);
tokio::time::sleep(Duration::from_micros(sleep_duration)).await;
}
}
if datas.is_empty() {
tokio::time::sleep(Duration::from_millis(500)).await;
}
}
}
async fn handle_retry_domains_static(
running: Arc<AtomicBool>,
senddog: Arc<Mutex<SendDog>>,
retry_recv: mpsc::Receiver<Arc<std::sync::RwLock<RetryStruct>>>,
) {
while running.load(Ordering::Relaxed) {
match retry_recv.recv_timeout(Duration::from_millis(1000)) {
Ok(res) => match res.read() {
Ok(rety_data) => match senddog.lock() {
Ok(senddog) => senddog.send(
rety_data.domain.clone(),
rety_data.dns.clone(),
rety_data.src_port,
rety_data.flag_id,
),
Err(_) => {
println!("警告: 无法获取senddog锁");
}
},
Err(_) => {
println!("警告: 无法读取重试数据");
}
},
Err(mpsc::RecvTimeoutError::Timeout) => {
continue;
}
Err(mpsc::RecvTimeoutError::Disconnected) => {
break;
}
}
}
}
async fn wait_for_completion(&self, total_queries: usize) {
let start_time = std::time::Instant::now();
let max_wait_time = Duration::from_secs(300); let mut consecutive_empty_checks = 0;
let required_consecutive_checks = 5;
loop {
if start_time.elapsed() > max_wait_time {
if !self.config.silent {
println!("警告: 等待超时,强制退出等待循环");
}
break;
}
if self.state.is_local_status_empty() {
consecutive_empty_checks += 1;
if consecutive_empty_checks >= required_consecutive_checks {
if !self.config.silent {
println!("所有查询已完成");
}
break;
}
} else {
consecutive_empty_checks = 0;
}
self.emit_progress(BruteForceProgress {
phase: BruteForceProgressPhase::WaitingForResponses,
sent_queries: total_queries,
total_queries,
discovered_domains: self.state.discovered_domain_count(),
current_target: self.config.domains.first().cloned(),
});
tokio::time::sleep(Duration::from_millis(1000)).await;
}
}
fn emit_query_progress(
&self,
sent_queries: usize,
total_queries: usize,
current_target: Option<&str>,
) {
if sent_queries != 1 && sent_queries % 100 != 0 && sent_queries < total_queries {
return;
}
self.emit_progress(BruteForceProgress {
phase: BruteForceProgressPhase::SendingQueries,
sent_queries,
total_queries,
discovered_domains: self.state.discovered_domain_count(),
current_target: current_target.map(|target| target.to_string()),
});
}
fn emit_progress(&self, progress: BruteForceProgress) {
if let Some(callback) = self.config.progress_callback.as_ref() {
callback(progress);
}
}
fn cleanup_resources(&self) {
self.state.clear_discovered_domains();
self.state.clear_verification_results();
Self::cleanup_global_state();
}
fn cleanup_global_state() {
if let Ok(mut status) = crate::structs::LOCAL_STATUS.write() {
*status = crate::local_struct::LocalStruct::new();
}
if let Ok(mut stack) = crate::structs::LOCAL_STACK.write() {
*stack = crate::stack::Stack::new();
}
crate::handle::cleanup_global_state();
}
}
fn record_query_status(
state: &BruteForceState,
domain: &str,
dns: &str,
flag_id: u16,
src_port: u16,
domain_level: isize,
) {
let index = send::generate_map_index(flag_id, src_port);
let status = StatusTable {
domain: domain.to_string(),
dns: dns.to_string(),
time: chrono::Utc::now().timestamp() as u64,
retry: 0,
domain_level,
};
state.append_status(status, index as u32);
}
pub async fn brute_force_subdomains(
domains: Vec<String>,
dictionary_file: Option<String>,
resolvers: Option<Vec<String>>,
skip_wildcard: bool,
bandwidth_limit: Option<String>,
verify_mode: bool,
resolve_records: bool,
silent: bool,
device: Option<String>,
) -> Result<Vec<SubdomainResult>, Box<dyn std::error::Error>> {
let config = SubdomainBruteConfig {
domains,
dictionary_file,
dictionary: None,
resolvers: resolvers.unwrap_or_else(|| vec!["8.8.8.8".to_string()]),
skip_wildcard,
bandwidth_limit,
verify_mode,
resolve_records,
silent,
device,
progress_callback: None,
};
let engine = SubdomainBruteEngine::new(config).await?;
engine.run_brute_force().await
}
pub async fn brute_force_subdomains_with_dict(
domains: Vec<String>,
dictionary: Vec<String>,
resolvers: Option<Vec<String>>,
skip_wildcard: bool,
bandwidth_limit: Option<String>,
verify_mode: bool,
resolve_records: bool,
silent: bool,
device: Option<String>,
) -> Result<Vec<SubdomainResult>, Box<dyn std::error::Error>> {
let config = SubdomainBruteConfig {
domains,
dictionary_file: None,
dictionary: Some(dictionary),
resolvers: resolvers.unwrap_or_else(|| vec!["8.8.8.8".to_string()]),
skip_wildcard,
bandwidth_limit,
verify_mode,
resolve_records,
silent,
device,
progress_callback: None,
};
let engine = SubdomainBruteEngine::new(config).await?;
engine.run_brute_force().await
}
pub async fn brute_force_subdomains_with_config(
domains: Vec<String>,
dictionary_file: Option<String>,
dictionary: Option<Vec<String>>,
resolvers: Option<Vec<String>>,
skip_wildcard: bool,
bandwidth_limit: Option<String>,
verify_mode: bool,
resolve_records: bool,
silent: bool,
device: Option<String>,
) -> Result<Vec<SubdomainResult>, Box<dyn std::error::Error>> {
let config = SubdomainBruteConfig {
domains,
dictionary_file,
dictionary,
resolvers: resolvers.unwrap_or_else(|| vec!["8.8.8.8".to_string()]),
skip_wildcard,
bandwidth_limit,
verify_mode,
resolve_records,
silent,
device,
progress_callback: None,
};
let engine = SubdomainBruteEngine::new(config).await?;
engine.run_brute_force().await
}
pub async fn run_speed_test(duration_secs: u64) -> Result<(), Box<dyn std::error::Error>> {
let tester = SpeedTester::new().await?;
let result = tester.run_speed_test(duration_secs).await;
tester.display_result(&result);
Ok(())
}