如何将Rust编写的TCP反向Shell监听器改为类似Netcat的UDP实现
UDP是无连接协议,和TCP面向流的逻辑差异很大,
netcat -ul 55100的默认行为是:绑定指定UDP端口后,将收到的任意UDP数据输出到标准输出,同时将标准输入的内容发送给最近一次向本地端口发送数据的对端地址。修改后的完整实现代码如下: use std::net::{UdpSocket, SocketAddr}; use std::sync::{Arc, Mutex}; fn stdin_to_udp(socket: UdpSocket, peer_addr: Arc<Mutex<Option<SocketAddr>>>) -> std::thread::JoinHandle<()> { std::thread::spawn(move || { let mut buffer = [0; 1024]; loop { let len = std::io::stdin().read(&mut buffer).unwrap(); if len == 0 { std::process::exit(0x0100); } // 仅当已经收到过对端的包才发送 if let Some(addr) = *peer_addr.lock().unwrap() { socket.send_to(&buffer[..len], addr).unwrap(); } } }) } fn udp_to_stdout(socket: UdpSocket, peer_addr: Arc<Mutex<Option<SocketAddr>>>) -> std::thread::JoinHandle<()> { std::thread::spawn(move || { let mut buffer = [0; 1024]; loop { let (len, addr) = socket.recv_from(&mut buffer).unwrap(); if len == 0 { println!("Connection lost"); std::process::exit(0x0100); } // 更新最近一次通信的对端地址 *peer_addr.lock().unwrap() = Some(addr); std::io::stdout().write_all(&buffer[..len]).unwrap(); std::io::stdout().flush().unwrap(); } }) } fn listen() -> std::io::Result<()> { let socket = UdpSocket::bind("0.0.0.0:55100")?; println!("Started UDP listener on 0.0.0.0:55100"); // 用Arc<Mutex>共享对端地址,两个线程都可以读写 let peer_addr = Arc::new(Mutex::new(None)); let t1 = stdin_to_udp(socket.try_clone()?, peer_addr.clone()); let t2 = udp_to_stdout(socket, peer_addr); t1.join().unwrap(); t2.join().unwrap(); Ok(()) }
核心改动点
- 把原来的
TcpListener替换为UdpSocket,UDP没有监听-accept的连接建立步骤,直接绑定端口即可使用 - 移除了原来通用的
pipe_thread,拆分出两个单独的线程函数:一个负责把标准输入的数据发送到UDP对端,另一个负责把UDP收到的数据输出到标准输出 - 增加
Arc<Mutex<Option<SocketAddr>>>结构共享最近一次通信的对端地址,对齐netcat的行为:在收到第一个对端包之前,不会发送标准输入的内容 - 替换了原来的流读写
read/write,换成UDP数据报专用的recv_from/send_to方法适配无连接的读写逻辑
内容的提问来源于stack exchange,提问作者user16139080
相关产品推荐
相关产品推荐

