Description:

For the past few months, I have been building Reconx, an open-source CLI tool designed for mapping external infrastructure and gathering threat intelligence. If you have ever done penetration testing or bug bounty hunting, you know the standard workflow: run five different Go or Python tools, pipe the outputs together, and write bash scripts to parse the mess. I wanted a single, unified engine that could handle dozens of sources concurrently, track state changes, and output clean data. Here is a look under the hood at how I built the network and concurrency architecture in Rust.

The Problem: Socket Exhaustion in Async Rust

When I first started building Reconx, I made a classic mistake. I had over 35 OSINT collectors (querying Shodan, Censys, VirusTotal, etc.), and every time a collector fired, it instantiated a new HTTP client.

When you run that at scale using tokio, you immediately run into ephemeral port exhaustion and get slammed by API rate limits. Target servers drop connections, and the OS runs out of file descriptors.