Skip to content
Phillip Stephens edited this page Jan 7, 2025 · 10 revisions

Getting Started

Introduction

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 overhead.
  • Efficient Multi-threading + Parallelism - ZDNS is designed to be multi-threaded by default leveraging light-weight goroutines.

Installing

Prerequisites

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

Clone ZDNS

git clone https://github.com/zmap/zdns.git
cd zdns

Build

make install

Confirm Installation

zdns --version

Quick Start

Starting off, you can use ZDNS similar to dig.

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

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"
    }
  }
}
Clone this wiki locally