Skip to content

Getting Started ‐ Library

Phillip Stephens edited this page Jun 25, 2024 · 4 revisions

Getting Started with ZDNS - Library

Resources

If after consulting this documentation you still have questions, please feel free to open an issue on the GitHub repo so we can update this community resource!

The ZDNS library is designed to give an interface to ZDNS from another Golang program. All options available in the CLI are available in the library. This approach gives the user the flexibility to use ZDNS in their own programs, full control of the threading behavior, and the ability to customize ZDNS to their needs.

Basic Usage

Here, we'll be looking at the simple lookup example in examples/simple_lookup/simple.go

At a high-level, using the library follows the following steps:

  1. Create a ResolverConfig object
  2. Set any desired options on the ResolverConfig object
  3. Create a/multiple new Resolver object(s) with the ResolverConfig object
  4. Use the Resolver object to perform DNS lookups

The ResolverConfig holds all configuration info for a Resolver object. The Resolver object performs the actual DNS lookups.

The Resolver object can perform two types of lookups: External and Iterative.

  • External lookups utilize a recursive resolver (1.1.1.1 or 8.8.8.8, for example) to perform the lookup.
    • If you provide an empty string for the dstServer parameter, the library will use external lookups specified in the ResolverConfig. By default, these are set to the OS's default DNS resolver(s).
    • You can provide an IP:port pair to override this behavior at the function-call level to dstServer.
  • Iterative lookups perform the lookup starting from the root servers and following the DNS resolution process to the end. You do not need to provide a dstServer parameter for iterative lookups as all recursion happens internally.
    • Iterative lookups are slower than external lookups, but ZDNS does implement an LRU caching mechanism to cache the most common domain name -> IPs to speed up this process.
    • Iterative lookups are useful for when you want to see the entire resolution process, or if you want to see the entire chain of responses from the root servers to the final authoritative server.

Please see the examples/simple_lookup/simple.go for an example.

Multi-Threaded Usage

To improve performance, and a primary feature of ZDNS over other DNS tools like dig, is it's use of a cache. The cache is an LRU cache that stores the most common domain name -> IP mappings to speed up iterative lookups. This cache is intended to be shared across multiple Resolver objects to reduce overhead.

A Resolver object is not thread-safe, so if you want to perform multiple lookups concurrently, you should create a new Resolver object for each goroutine.

As the cache and the blacklist are pointers (to enable sharing of the struct across multiple resolvers, they are thread-safe), you should not change the ResolverConfig after creating a Resolver object. If you need to change the configuration post-Resolver creation, create a new ResolverConfig object with the new configuration.

A pattern we follow in the CLI is to create a worker pool of goroutines, each with their own Resolver object, and a shared Blacklist and Cache between them. An input channel is used to pass the domain names to the worker pool, and an output channel is used to pass the results back to the main goroutine.

An example of a simple multi-threaded use-case with a worker pool and shared cache can be found in examples/multi_threaded_lookup/multi_threaded.go here. For a more complex example, see the Run function in src/cli/worker_manager.go

Clone this wiki locally