TCP的握手有三个过程。首先,客户端发送一个 syn 的包,表示建立回话的开始。如果客户端收到超时,说明端口可能在防火墙后面
第二,如果服务端应答 syn-ack 包,意味着这个端口是打开的,否则会返回 rst 包。最后,客户端需要另外发送一个 ack 包。从这时起,连接就已经建立。
访问scanme.nmap.org,是由nmap运营的服务,提供给人们测试扫描:http://scanme.nmap.org/
创建项目
编写cargo.toml:
[package]
name = "scanner"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
//项目依赖项
[dependencies]
crossbeam = "0.7.3"
structopt = "0.3"
may = "0.3.14"
编写main.rs源文件:
//调用may carte宏
#[macro_use]
extern crate may;
//std标准库
//导入net库的TcpStream,ToSocketAddrs,shutdown模块
use std::net::{TcpStream, ToSocketAddrs, Shutdown};
//导入time库的Duration模块
use std::time::Duration;
//导入crossbeam库的sync库内Waitgroup模块
use crossbeam::sync::WaitGroup;
//导入sync库的Arc,Mutex模块
use std::sync::{Arc, Mutex};
//导入structopt库的StructOpt
use structopt::StructOpt;
//利用structopt库,将命令行参数解析为struct
//告诉rust生成一个命令行解析器,并且各种属性仅用于其他参数
#[derive(Debug, StructOpt)]
#[structopt(name = "dail example", about = "An example of server ports scanning.")]
//将参数转换为给定类型
struct Opt {
#[structopt(long = "hostname", default_value = "", help = "hostname to test")]
hostname: String,
#[structopt(long = "start-port", default_value = "80", help = "the port on which the scanning starts" )]
start_port: u16,
#[structopt(long = "end-port", default_value = "100", help = "the port from which the scanning ends" )]
end_port: u16,
#[structopt(long = "timeout", default_value = "200", help = "timeout" )]
timeout: u64,
}
//主函数
fn main() {
//声明变量:let声明和定义一个变量
//定义opt、timeout、vec、arc_vec、wg变量
//opt调用from_args方法
let opt = Opt::from_args();
//timeout时间响应超时
let timeout = Duration::from_millis(opt.timeout);
let vec: Vec<u16> = Vec::new();
let arc_vec = Arc::new(Mutex::new(vec));
// create a new wait group.
let wg = WaitGroup::new();
for n in opt.start_port..opt.end_port{
// create another reference to the wait group.
let wg = wg.clone();
let arc_vec = arc_vec.clone();
//hostname变量:字符串格式数据来自引用参数opt.hostname
//& 表示这个参数是一个 引用(reference),它允许多处代码访问同一处数据,而无需在内存中多次拷贝
let hostname = String::from(&opt.hostname);
go!(move || {
let flag = is_open(hostname, n, timeout);
if flag {
arc_vec.lock().unwrap().push(n);
}
drop(arc_vec);
// Drop the reference to the wait group.
drop(wg);
});
}
// Block until all coroutines have finished their work.
wg.wait();
println!("opened ports: {:?}", arc_vec.lock().unwrap());
}
//自定义函数is_open,对变量进行操作、判断
fn is_open(hostname: String, port: u16, timeout: Duration) -> bool {
//server变量定义:调用format宏;"{}:{}"两占位符为IP/域名,端口;hostname,port为占位符进行值获取定义
let server = format!("{}:{}", hostname, port);
//数据流处理
let addrs: Vec<_> = server
.to_socket_addrs()
.expect("Unable to parse socket address")
.collect();
//stream请求连接判断
if let Ok(stream) = TcpStream::connect_timeout(&addrs[0], timeout) {
//println!("Connected to the server!");
stream.shutdown(Shutdown::Both).expect("shutdown call failed");
true
} else {
//println!("Couldn't connect to server...");
false
}
}
编译
cargo build
编译后,文件在target/Debug/scanner.exe
命令帮助
测试
源码参考
GitHub - honwhy/dial: An example of server ports scanning.
资料参考
net网络处理:std::net - Rust
time时间:std::time - Rust
sync同步线程:crossbeam::sync - Rust
本文含有隐藏内容,请 开通VIP 后查看