Rust TCP扫描器

发布于:2022-12-17 ⋅ 阅读:(664) ⋅ 点赞:(0)

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

std::sync - Rust

structopt - Rust

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到