MassDNS: Resolving 350,000 Domains Per Second with a Custom DNS Stack
Hook
While most DNS libraries resolve domains one at a time, MassDNS can blast through 350,000+ queries per second using public resolvers. The secret? Throwing out everything you don’t need.
Context
DNS resolution is typically treated as a solved problem—you import a library, make a query, get a response. But this approach breaks down when you need to resolve millions of domains for reconnaissance, security research, or subdomain enumeration. Traditional DNS clients serialize requests, respect timeouts religiously, and include comprehensive protocol support that adds overhead. For researchers brute-forcing subdomains or mapping networks at scale, these niceties become bottlenecks.
MassDNS takes a radically different approach: it’s a DNS stub resolver built from scratch in C, optimized exclusively for bulk operations. Created for scenarios where you’re churning through wordlists of potential subdomains or validating massive datasets, it strips away everything that doesn’t contribute to raw throughput. The tool emerged from the reconnaissance community’s need to enumerate attack surfaces quickly, where resolving ten million potential subdomain combinations in hours instead of days makes the difference between feasible and impossible.
Technical Insight
The performance breakthrough comes from architectural decisions that most DNS tools avoid. First, MassDNS implements asynchronous I/O using epoll on Linux (with busy-wait polling available via --busy-poll flag) to manage thousands of concurrent queries across multiple UDP sockets. Instead of waiting for responses serially, it fires off queries as fast as resolvers can accept them, maintaining a configurable hashmap of in-flight lookups (default 10,000 concurrent via -s parameter).
Second, the tool rotates through a list of resolver IPs, distributing load and working around rate limits. Each query can be sent to different resolvers, and the output includes which resolver provided each answer in the packet header:
./bin/massdns -r lists/resolvers.txt -t A -o Sqi domains.txt
The -o Sqi flags demonstrate the granular output control: S for simple mode, q to print the question, i to indent records. Based on the README’s example output format, responses include resolver information in headers like:
;; Server: 77.41.229.2:53
;; Size: 93
;; Unix time: 1513458347
Third—and most unusual—MassDNS uses a custom, malloc-free DNS implementation. The README notes this means it “currently only supports the most common record types,” but when you’re doing reconnaissance, you rarely need DNSSEC signatures or exotic record types. This trade-off—completeness for speed—contributes to the 350,000 queries per second capability.
The tool also supports horizontal scaling through multi-process operation. Each process can maintain multiple sockets (--socket-count), and you can run multiple processes (--processes) to saturate available bandwidth:
./bin/massdns -r resolvers.txt -t A --processes 4 --socket-count 3 \
-s 20000 domains.txt > results.txt
This configuration runs 4 processes, each with 3 sockets, maintaining 20,000 concurrent lookups in the hashmap. For large-scale enumeration, this parallelism is essential.
The resolver retry logic is equally thoughtful. By default, MassDNS retries queries up to 50 times (-c 50), waiting 500ms between attempts (-i 500), and only accepts NOERROR or NXDOMAIN responses (per the --retry default: “All codes but NOERROR or NXDOMAIN”). You can customize which response codes trigger retries with --retry, crucial when dealing with unreliable public resolvers that return SERVFAIL intermittently. The --sticky flag keeps retries on the same resolver instead of rotating, useful for debugging resolver-specific issues.
Gotcha
The biggest gotcha is that MassDNS is explicitly not a general-purpose DNS client. The custom implementation only handles common record types—if you need DNSSEC validation, CAA records, or other specialized DNS features, you’ll hit a wall. The README candidly states this limitation: “MassDNS’s custom, malloc-free DNS implementation currently only supports the most common records.”
The included resolvers.txt file is acknowledged as “currently outdated with a large share of resolvers being dysfunctional.” You’ll need to curate your own resolver list, testing and filtering for reliability. This maintenance burden is real—public resolvers change, get rate-limited, or start returning malicious results. The tool’s output includes resolver IPs in packet headers specifically so you can identify and filter problematic ones (“The resolver IP address is included in order to make it easier for you to filter the output in case you detect that some resolvers produce bad results”), but this detective work falls on you.
Finally, the ethical and practical implications: blasting hundreds of thousands of DNS queries through public resolvers will generate complaints. The README explicitly warns: “Please note that the usage of MassDNS may cause a significant load on the used resolvers and result in abuse complaints being sent to your ISP. Also note that the provided resolvers are not guaranteed to be trustworthy.” For legitimate large-scale work, you’ll want to run your own resolvers or use a service designed for bulk queries. MassDNS gives you the throughput, but managing the consequences of that throughput is your responsibility.
Verdict
Use MassDNS if you’re performing reconnaissance at scale—subdomain enumeration with million-entry wordlists, validating scraped domain lists, or conducting security research requiring massive DNS throughput. It’s purpose-built for scenarios where you measure domain counts in millions and need results in hours. The 350,000 queries per second capability is real, and for bulk operations, nothing else comes close at this performance level. Skip it if you need a general-purpose DNS client, comprehensive record type support, or can’t responsibly manage resolver load and potential abuse complaints. Also skip if you’re doing production application DNS resolution—this is a reconnaissance tool, not a library. For normal subdomain enumeration (thousands, not millions of queries), newer Go-based alternatives like puredns or dnsx offer better usability and built-in wildcard filtering without the resolver management headaches, even if they’re slower.