Skip to content

Instantly share code, notes, and snippets.

@rust-play
Created November 6, 2025 13:41
Show Gist options
  • Select an option

  • Save rust-play/04022c1a9e0e7bcbc8bbab161368b69d to your computer and use it in GitHub Desktop.

Select an option

Save rust-play/04022c1a9e0e7bcbc8bbab161368b69d to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
use std::net::{TcpListener, TcpStream, /*ToSocketAddrs, */SocketAddr};
use std::time::Duration;
use std::thread;
use std::io::{self, Read, Write};
// --- Configuration ---
const TARGET_IP: &str = "127.0.0.1"; // The IP the scanner checks
const TIMEOUT_MS: u64 = 500; // Connection timeout in milliseconds
// ---------------------
fn main() -> io::Result<()> {
println!("--- πŸ¦€ Combined Bind and Scan Script ---");
let timeout = Duration::from_millis(TIMEOUT_MS);
// Create a channel to pass the dynamically chosen port from the server thread to the main thread
let (tx, rx) = std::sync::mpsc::channel();
// 1. START THE SERVER THREAD (BIND)
let server_handle = thread::spawn(move || {
// The fix: explicitly annotating the type as SocketAddr
let bind_addr: SocketAddr = "0.0.0.0:0".parse().unwrap();
println!("\n[SERVER] Attempting to bind to: {}", bind_addr);
let listener = match TcpListener::bind(bind_addr) {
Ok(l) => l,
Err(e) => {
eprintln!("[SERVER] ❌ Failed to bind: {}", e);
// Return an error to stop the thread and cause join() to fail
return Err(e);
}
};
let local_addr = listener.local_addr()?;
let chosen_port = local_addr.port();
println!("[SERVER] βœ… Listener bound to: {}", local_addr);
println!("[SERVER] πŸ”‘ Dynamic port chosen: {}", chosen_port);
// Send the chosen port to the main thread for the scanner
tx.send(chosen_port).unwrap();
// Server waits for and handles a single connection
println!("[SERVER] Waiting for a connection...");
match listener.accept() {
Ok((mut stream, addr)) => {
println!("[SERVER] 🀝 Connection accepted from: {}", addr);
let mut buffer = [0; 128];
let bytes_read = stream.read(&mut buffer).expect("Failed to read");
let message = String::from_utf8_lossy(&buffer[..bytes_read]);
println!("[SERVER] Received: \"{}\"", message);
stream.write_all(b"ACK from server").expect("Failed to write");
println!("[SERVER] Sent 'ACK from server' and closing connection.");
}
Err(e) => eprintln!("[SERVER] Connection error: {}", e),
}
// Return a successful result for the thread
Ok(())
});
// 2. WAIT FOR THE DYNAMIC PORT
let server_port = rx.recv().expect("Failed to receive port from server thread.");
// 3. START THE CLIENT/SCANNER (SCAN)
let scanner_handle = thread::spawn(move || {
// Give the server a moment to enter the accept loop
thread::sleep(Duration::from_millis(100));
println!("\n[SCANNER] Starting connection attempt...");
let address = format!("{}:{}", TARGET_IP, server_port);
match TcpStream::connect_timeout(&address.parse().unwrap(), timeout) {
Ok(mut stream) => {
println!("[SCANNER] [+] Port {} is OPEN on {}", server_port, TARGET_IP);
stream.write_all(b"Hello Server!").expect("Client failed to send data");
let mut response = [0; 128];
let bytes_read = stream.read(&mut response).expect("Client failed to read response");
let message = String::from_utf8_lossy(&response[..bytes_read]);
println!("[SCANNER] Received response: \"{}\"", message);
},
Err(e) if e.kind() == io::ErrorKind::TimedOut => {
println!("[SCANNER] [-] Port {} Timed Out.", server_port);
},
Err(e) => {
println!("[SCANNER] [-] Port {} Closed/Error: {}", server_port, e);
}
}
});
// 4. WAIT FOR BOTH THREADS TO FINISH
scanner_handle.join().expect("Scanner thread panicked!");
// The ? propagates the io::Result<()>, handling any bind error from the server thread
server_handle.join().expect("Server thread panicked!")?;
println!("\n--- Script Finished ---");
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment