-
Notifications
You must be signed in to change notification settings - Fork 126
Home
A common question is "Why usezdns
over dig
or nslookup
?" For one-off queries, these tools or the DNS lookup functionality in your language of choice are more than sufficient.
However, zdns
is designed to efficiently handle large numbers of DNS queries in parallel as well as support more complex DNS queries like --all-nameservers
that aren't supported with dig
.
Several features to improve the performance of large volumes of DNS queries are:
- Shared Cache - each thread shares an LRU cache to store the most common domain name -> IP mappings. This greatly speeds up iterative lookups.
- UDP socket re-use -
dig
and friends will open new socket for each query. ZDNS re-uses the same socket for multiple queries, reducing networking overhead. - Efficient Multi-threading + Parallelism - ZDNS is designed to be multi-threaded by default leveraging light-weight goroutines.
You'll need to have the following installed in order to install ZDNS
Both of these should return the version if they're properly installed
git --version
go version
git clone https://github.com/zmap/zdns.git
cd zdns
make install
zdns --version
You can use ZDNS similar to dig
.
For example, if you want to query the A
record for google.com
from Cloudflare's recursive resolver, 1.1.1.1
.
zdns A google.com --name-servers=1.1.1.1
$ zdns A google.com --name-servers=1.1.1.1
{"name":"google.com","results":{"A":{"data":{"additionals":[{"flags":"","type":"EDNS0","udpsize":1232,"version":0}],"answers":[{"answer":"142.250.189.174","class":"IN","name":"google.com","ttl":173,"type":"A"}],"protocol":"udp","resolver":"1.1.1.1:53"},"duration":0.003042781,"status":"NOERROR","timestamp":"2024-12-26T17:06:31Z"}}}
00h:00m:00s; Scan Complete; 1 names scanned; 293.19 names/sec; 100.0% success rate; NOERROR: 1
When you specify --name-servers=1.1.1.1
, these nameservers will be used for all lookups made with that invocation of zdns
. If multiple are provided, a random one will be chosen for each name lookup.
Without specifying --name-servers
, ZDNS will read /etc/resolv.conf
to get your OS's default external resolvers. You can see in the below that this host had 127.0.0.53:53
configured as the local resolver (denoted with "resolver": "127.0.0.53:53"
).
$ zdns A google.com
00h:00m:00s; Scan Complete; 1 names scanned; 746.57 names/sec; 100.0% success rate; NOERROR: 1
{"name":"google.com","results":{"A":{"data":{"additionals":[{"flags":"","type":"EDNS0","udpsize":65494,"version":0}],"answers":[{"answer":"142.250.189.206","class":"IN","name":"google.com","ttl":145,"type":"A"}],"protocol":"udp","resolver":"127.0.0.53:53"},"duration":0.001102308,"status":"NOERROR","timestamp":"2024-12-26T17:10:08Z"}}}
Output is streamed to stdout
by default, so you can pipe into jq
for prettier output. You'll notice that the per-second status updates are not processed by jq
, those and any logs are sent to stderr
by default.
$ zdns A google.com | jq
00h:00m:00s; Scan Complete; 1 names scanned; 54.55 names/sec; 100.0% success rate; NOERROR: 1
{
"name": "google.com",
"results": {
"A": {
"data": {
"additionals": [
{
"flags": "",
"type": "EDNS0",
"udpsize": 65494,
"version": 0
}
],
"answers": [
{
"answer": "142.250.189.206",
"class": "IN",
"name": "google.com",
"ttl": 300,
"type": "A"
}
],
"protocol": "udp",
"resolver": "127.0.0.53:53"
},
"duration": 0.017919065,
"status": "NOERROR",
"timestamp": "2024-12-26T17:13:26Z"
}
}
}
This section outlines how to pass in names to query and how output is handled.
You can query names in similar fashion to the dig
CLI tool by passing in names as arguments after the lookup type (in this case an A
query).
Ex:
zdns A google.com yahoo.com
For querying large sets of names, ZDNS can also read names from StdIn
. Names must be new-line delimited, one name per line.
Using echo
:
echo "google.com\nyahoo.com" | zdns A
Using cat
to read 1+ files consisting of newline-delimited names:
$ cat list1.txt
google.com
yahoo.com
$ cat list2.txt
apple.com
apnews.com
$ cat list1.txt list2.txt | zdns A
...
{"name":"apple.com","results":{"A":{"data":{"additionals":[{"flags":"","type":"EDNS0","udpsize":1232,"version":0}],"answers":[{"answer":"17.253.144.10","class":"IN","name":"apple.com","ttl":593,"type":"A"}],"protocol":"udp","resolver":"1.1.1.1:53"},"duration":0.069962125,"status":"NOERROR","timestamp":"2025-01-06T16:05:44-07:00"}}}
{"name":"google.com","results":{"A":{"data":{"additionals":[{"flags":"","type":"EDNS0","udpsize":1232,"version":0}],"answers":[{"answer":"142.250.189.238","class":"IN","name":"google.com","ttl":287,"type":"A"}],"protocol":"udp","resolver":"1.1.1.1:53"},"duration":0.071940958,"status":"NOERROR","timestamp":"2025-01-06T16:05:44-07:00"}}}
{"name":"apnews.com","results":{"A":{"data":{"additionals":[{"flags":"","type":"EDNS0","udpsize":1232,"version":0}],"answers":[{"answer":"104.16.22.8","class":"IN","name":"apnews.com","ttl":85,"type":"A"},{"answer":"104.16.23.8","class":"IN","name":"apnews.com","ttl":85,"type":"A"}],"protocol":"udp","resolver":"1.1.1.1:53"},"duration":0.07367475,"status":"NOERROR","timestamp":"2025-01-06T16:05:44-07:00"}}}
{"name":"yahoo.com","results":{"A":{"data":{"additionals":[{"flags":"","type":"EDNS0","udpsize":1232,"version":0}],"answers":[{"answer":"74.6.231.21","class":"IN","name":"yahoo.com","ttl":1730,"type":"A"},{"answer":"98.137.11.163","class":"IN","name":"yahoo.com","ttl":1730,"type":"A"},{"answer":"74.6.143.25","class":"IN","name":"yahoo.com","ttl":1730,"type":"A"},{"answer":"74.6.143.26","class":"IN","name":"yahoo.com","ttl":1730,"type":"A"},{"answer":"98.137.11.164","class":"IN","name":"yahoo.com","ttl":1730,"type":"A"},{"answer":"74.6.231.20","class":"IN","name":"yahoo.com","ttl":1730,"type":"A"}],"protocol":"udp","resolver":"1.1.1.1:53"},"duration":0.08348,"status":"NOERROR","timestamp":"2025-01-06T16:05:44-07:00"}}}
00h:00m:00s; Scan Complete; 4 names scanned; 47.37 names/sec; 100.0% success rate; NOERROR: 4
You can also specify a file of input names using CLI flags to override the default behavior of reading from stdin
.
$ cat list1.txt
google.com
yahoo.com
$ zdns A --input-file=list1.txt
...
{"name":"google.com","results":{"A":{"data":{"additionals":[{"flags":"","type":"EDNS0","udpsize":1232,"version":0}],"answers":[{"answer":"142.250.189.206","class":"IN","name":"google.com","ttl":280,"type":"A"}],"protocol":"udp","resolver":"1.1.1.1:53"},"duration":0.061279167,"status":"NOERROR","timestamp":"2025-01-06T16:11:55-07:00"}}}
{"name":"yahoo.com","results":{"A":{"data":{"additionals":[{"flags":"","type":"EDNS0","udpsize":1232,"version":0}],"answers":[{"answer":"74.6.143.26","class":"IN","name":"yahoo.com","ttl":1528,"type":"A"},{"answer":"74.6.143.25","class":"IN","name":"yahoo.com","ttl":1528,"type":"A"},{"answer":"98.137.11.163","class":"IN","name":"yahoo.com","ttl":1528,"type":"A"},{"answer":"74.6.231.20","class":"IN","name":"yahoo.com","ttl":1528,"type":"A"},{"answer":"98.137.11.164","class":"IN","name":"yahoo.com","ttl":1528,"type":"A"},{"answer":"74.6.231.21","class":"IN","name":"yahoo.com","ttl":1528,"type":"A"}],"protocol":"udp","resolver":"1.1.1.1:53"},"duration":0.063159292,"status":"NOERROR","timestamp":"2025-01-06T16:11:55-07:00"}}}
00h:00m:00s; Scan Complete; 2 names scanned; 31.29 names/sec; 100.0% success rate; NOERROR: 2
By default, zdns
outputs its results to stdout
and all logs (both event-based and the per-second status updates) to stderr
.
You can control the verbosity of event-based logs with --verbosity=N
where:
-
--verbosity=1
Fatal logs only -
--verbosity=2
Above and Error logs -
--verbosity=3
Above and Warning logs (default) -
--verbosity=4
Above and Info logs -
--verbosity=5
Above and Debug logs
Below we can see examples of all 3 types of output. An INFO
log explains that zdns
chose a local IP address to send queries from. A per-second and an end-of-scan log show progress, success rate, and DNS statuses encountered. Finally, each of the 2 input names have a respective output line showing the result of the DNS query.
$ zdns A --input-file=list1.txt --threads=1 --iterative --verbosity=4
INFO[0000] none of the default local addresses could connect to name server 198.97.190.53:53, using local address 10.216.70.2
{"name":"google.com","results":{"A":{"data":{"answers":[{"answer":"142.250.191.46","class":"IN","name":"google.com","ttl":300,"type":"A"}],"protocol":"udp","resolver":"216.239.38.10:53"},"duration":0.270621125,"status":"NOERROR","timestamp":"2025-01-06T16:23:58-07:00"}}}
{"name":"yahoo.com","results":{"A":{"data":{"answers":[{"answer":"98.137.11.163","class":"IN","name":"yahoo.com","ttl":1800,"type":"A"},{"answer":"74.6.231.20","class":"IN","name":"yahoo.com","ttl":1800,"type":"A"},{"answer":"74.6.143.26","class":"IN","name":"yahoo.com","ttl":1800,"type":"A"},{"answer":"74.6.143.25","class":"IN","name":"yahoo.com","ttl":1800,"type":"A"},{"answer":"74.6.231.21","class":"IN","name":"yahoo.com","ttl":1800,"type":"A"},{"answer":"98.137.11.164","class":"IN","name":"yahoo.com","ttl":1800,"type":"A"}],"protocol":"udp","resolver":"202.165.97.53:53"},"duration":0.226075667,"status":"NOERROR","timestamp":"2025-01-06T16:23:58-07:00"}}}
00h:00m:01s; 2 names scanned; 2.00 names/sec; 100.0% success rate; NOERROR: 2
00h:00m:01s; Scan Complete; 2 names scanned; 1.33 names/sec; 100.0% success rate; NOERROR: 2
Caution
Each of the below file output redirects will create/overwrite the file specified if it exists. Be sure to use a new filename if you don't want to overwrite anything.
--status-updates-file=
redirects the status updates to the file specified instead of the default, stderr
.
Example:
zdns A google.com --status-updates-file=status.out
--log-file=
redirects the event-based logs to the file specified instead of the default, stderr
.
Example:
zdns A google.com --log-file=log.out
--output-file=
redirects the per-name output to the file specified instead of the default, stdout
.
Example:
zdns A google.com --output-file=out
--quiet
will disable the per-second and end-of-scan status updates.
$ zdns A google.com --iterative --quiet
{"name":"google.com","results":{"A":{"data":{"answers":[{"answer":"142.250.191.46","class":"IN","name":"google.com","ttl":300,"type":"A"}],"protocol":"udp","resolver":"216.239.34.10:53"},"duration":0.425099125,"status":"NOERROR","timestamp":"2025-01-06T16:46:25-07:00"}}}