Skip to content

Commit 73fdfed

Browse files
committed
更新版本至1.5.0
1 parent 948f6f1 commit 73fdfed

File tree

5 files changed

+54
-9
lines changed

5 files changed

+54
-9
lines changed

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
[package]
22
name = "windfire"
3-
version = "1.4.0"
3+
version = "1.5.0"
44
authors = ["muddlelife <[email protected]>"]
55
edition = "2021"
66

77
[dependencies]
88
clap = { version = "4.5.17",features = ["derive"] }
9+
crossbeam = "0.8.4"
10+
csv = "1.3.0"
911
futures = "0.3.30"
1012
lazy_static = "1.5.0"
1113
regex = "1.10.6"
1214
reqwest = { version = "0.12.7" ,features = ["socks"]}
15+
serde = { version = "1.0.210", features = ["derive"] }
1316
tokio = { version = "1.40.0", features = ["full"] }
1417

1518
[profile.release]

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Options:
1616
-c, --status-code <STATUS_CODE> Display the specified status code [default: 200]
1717
-p, --path <PATH> Designated path scan [default: ]
1818
-x, --proxy <PROXY> Supported Proxy socks5, http, and https, Example: -x socks5://127.0.0.1:1080
19+
-o, --output <OUTPUT> Output is an csv document, Example: -o result.csv
1920
-h, --help Print help (see more with '--help')
2021
-V, --version Print version
2122
```
@@ -51,6 +52,10 @@ windfire -f urls.txt > result.txt
5152
```shell
5253
windfire -f urls.txt -x socks5://127.0.0.1:1080
5354
```
55+
6. 批量执行,可保存为csv文件
56+
```shell
57+
windfire -f urls.txt -o result.csv
58+
```
5459
## 默认打印信息
5560
```shell
5661
https://www.baidu.com [200] [百度一下,你就知道] [BWS/1.1] [https://www.baidu.com/] [414219]

src/httpclient.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
use crate::utils::get_format_info;
1+
use crate::utils::{get_format_info, ScanInfo};
22
use reqwest::{header, Client};
33
use std::time::Duration;
4+
use crossbeam::queue::SegQueue;
45

56
pub const USER_AGENT: &str =
67
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:128.0) Gecko/20100101 Firefox/128.0";
@@ -62,6 +63,7 @@ pub async fn send_request(
6263
url: &str,
6364
u16_vec: Vec<u16>,
6465
path: &str,
66+
seg_queue: &SegQueue<ScanInfo>,
6567
) -> Result<String, reqwest::Error> {
6668
// 解析URL,如果path为空,则默认为/,如果有值,则加上,还需要处理url有没有/
6769
let url = if path.is_empty() {
@@ -77,16 +79,25 @@ pub async fn send_request(
7779

7880
let response = client.get(url.as_str()).send().await?;
7981

80-
let scan_info = get_format_info(response);
82+
let scan_info = get_format_info(response,url);
8183
let scan_info = scan_info.await;
8284

85+
let url = scan_info.url;
8386
let status_code = scan_info.status_code;
8487
let title = scan_info.title;
8588
let content_length = scan_info.content_length;
8689
let server = scan_info.server;
8790
let jump_url = scan_info.jump_url;
8891

8992
if u16_vec.contains(&status_code) {
93+
seg_queue.push(ScanInfo {
94+
url: url.to_string(),
95+
status_code,
96+
title: title.to_string(),
97+
server: server.to_string(),
98+
jump_url: jump_url.to_string(),
99+
content_length,
100+
});
90101
Ok(format!(
91102
"{} [{}] [{}] [{}] [{}] [{}]",
92103
url, status_code, title, server, jump_url, content_length

src/main.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use crate::httpclient::{create_http_client, send_request};
2-
use crate::utils::read_file;
2+
use crate::utils::{queue_to_csv, read_file, ScanInfo};
33
use clap::Parser;
44
use futures::future::join_all;
55
use reqwest::Client;
66
use std::sync::Arc;
7+
use crossbeam::queue::SegQueue;
78
use tokio::sync::Semaphore;
89
use tokio::task;
910

@@ -12,7 +13,7 @@ mod utils;
1213

1314
#[derive(Parser, Debug)]
1415
#[command(
15-
version = "1.4.0",
16+
version = "1.5.0",
1617
about = "An efficient and fast url survival detection tool",
1718
long_about = "Efficient URL activity tester written in Rust. Fast, batch, and lightweight"
1819
)]
@@ -44,6 +45,10 @@ struct Args {
4445
/// Supported Proxy socks5, http, and https, Example: -x socks5://127.0.0.1:1080
4546
#[arg(short = 'x', long)]
4647
proxy: Option<String>,
48+
49+
/// Output is an csv document, Example: -o result.csv
50+
#[arg(short = 'o', long)]
51+
output: Option<String>,
4752
}
4853

4954
#[tokio::main]
@@ -59,10 +64,11 @@ async fn main() {
5964

6065
let path = args.path;
6166
let proxy = args.proxy;
67+
let seg_queue: Arc<SegQueue<ScanInfo>> = Arc::new(SegQueue::new());
6268

6369
if let Some(url) = args.url {
6470
let client = create_http_client(args.timeout, proxy);
65-
let result = send_request(client, &url, u16_vec, &path).await;
71+
let result = send_request(client, &url, u16_vec, &path, &seg_queue).await;
6672
match result {
6773
Ok(result) => {
6874
if result != "" {
@@ -85,9 +91,10 @@ async fn main() {
8591
let client: Client = client.clone();
8692
let u16_vec = u16_vec.clone();
8793
let path = path.clone();
94+
let seg_queue = Arc::clone(&seg_queue);
8895
futures.push(task::spawn(async move {
8996
let permit = semaphore.acquire().await.unwrap();
90-
let result = send_request(client, url.as_str(), u16_vec, &path).await;
97+
let result = send_request(client, url.as_str(), u16_vec, &path, &seg_queue).await;
9198
match result {
9299
Ok(result) => {
93100
if result != "" {
@@ -100,6 +107,10 @@ async fn main() {
100107
}));
101108
}
102109
join_all(futures).await;
110+
// 保存结果为CSV
111+
if let Some(output) = args.output {
112+
queue_to_csv(&seg_queue, output.as_str()).ok();
113+
}
103114
}
104115
Err(e) => {
105116
println!("{}", e)

src/utils.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ use reqwest::Response;
44
use std::net::Ipv4Addr;
55
use std::str::FromStr;
66
use tokio::fs::File;
7+
use crossbeam::queue::SegQueue;
8+
use csv::WriterBuilder;
9+
use serde::{Deserialize, Serialize};
710
use tokio::io::{AsyncBufReadExt, BufReader};
811

912
lazy_static! {
@@ -59,16 +62,18 @@ pub(crate) async fn read_file(path: &str) -> Result<Vec<String>, tokio::io::Erro
5962
}
6063

6164
// 获取目标结果
65+
#[derive(Debug, Serialize, Deserialize, Clone)]
6266
pub struct ScanInfo {
67+
pub url: String,
6368
pub status_code: u16,
6469
pub title: String,
65-
pub content_length: usize,
6670
pub server: String,
6771
pub jump_url: String, // 跳转后的url
72+
pub content_length: usize,
6873
}
6974

7075
// 根据响应获取响应结果
71-
pub async fn get_format_info(response: Response) -> ScanInfo {
76+
pub async fn get_format_info(response: Response, url: String) -> ScanInfo {
7277
let status_code = response.status().as_u16();
7378
let jump_url = response.url().to_string();
7479

@@ -85,6 +90,7 @@ pub async fn get_format_info(response: Response) -> ScanInfo {
8590
let title = extract_title(&content).unwrap_or("".to_string());
8691

8792
ScanInfo {
93+
url,
8894
status_code,
8995
title,
9096
content_length,
@@ -140,3 +146,12 @@ pub fn cidr_to_ip_range(cidr: &str) -> Vec<String> {
140146

141147
ip_list
142148
}
149+
150+
// 将结果转为csv表格
151+
pub fn queue_to_csv(scan_info_queue: &SegQueue<ScanInfo>, path: &str) -> Result<(), Box<dyn std::error::Error>>{
152+
let mut wtr = WriterBuilder::new().from_path(path)?;
153+
while let Some(info) = scan_info_queue.pop() {
154+
wtr.serialize(info)?;
155+
}
156+
Ok(())
157+
}

0 commit comments

Comments
 (0)