Hysen Labs
Open-source project
hezhijie0327/ZJDNS avatar
hezhijie0327

ZJDNS

High performance recursive DNS server with DNS hijack protection, TLS/QUIC/HTTPS/HTTP3/DTLS, (PQ)DNSCrypt, TLCP/DTLCP support

46 stars14 forksGoNOASSERTION
DEEP OPEN-SOURCE ANALYSIS

ZJDNS is a recursive DNS server with encrypted transport and DNSSEC

A Go DNS resolver parses queries through IANA roots, supports DoT, DoQ, DoH, and DNSCrypt, and ships with a config generator.

What ZJDNS provides

ZJDNS is a high performance recursive DNS server written in Go. The README describes it as a recursive resolver with DNS hijack protection, an in memory cache, and DNSSEC support. It ships encryption across many transports: TLS, QUIC, HTTPS, HTTP3, DTLS, and DNSCrypt, including a post quantum variant. It also mentions TLCP and DTLCP support and KTLS kernel offload. The version shown is 4.4.1, built with Go 1.27, and the license badge reads Apache 2.0 with the Commons Clause. The README's Chinese description repeats these points and adds that the resolver walks from IANA root servers down to authoritative servers to answer queries. One listed feature is protection against DNS pollution, which in practice means it resists poisoned responses from upstream networks. That capability is also what makes the tool relevant in regions where DNS is interfered with, though the README presents it as a general resolver feature rather than a circumvention tool. The broad protocol support is the headline: a single binary can serve standard UDP and TCP plus the encrypted variants. The README lists golangci-lint as clean, which signals the code passes static checks. For a network service that handles untrusted input, that is a relevant quality marker alongside the feature list.

Building and running the server

The README's quick start shows how to build and run the server. To build, run go build with the output flag set to zjdns and the path ./cmd/zjdns. Running the binary with no arguments starts the default config, which acts as a recursive resolver listening on UDP and TCP. To use a specific file, pass --config config.json. To create a sample config, run --generate-config. To create a DNSCrypt config, run --generate-config with the --dnscrypt flag and a --provider value such as example.com. The README then shows query tests using dig and kdig against the local server on various ports: UDP and TCP on 53, DoT on 853, DoQ on 853, and DoH on 443. These commands let a user confirm each transport works after starting the server. The build step is a standard Go compile, so anyone with the Go 1.27 toolchain can produce the zjdns binary and begin serving. The --generate-config flags mean a new user does not have to write a config file by hand before trying the server. The sample config gives a working starting point that can be edited later. The information above is drawn from the project README and its repository metadata, which remain the source for the project's current behaviour. The binary is built with go build and the version shown in the README is 4.4.1 using Go 1.27. A reader who wants exact commands or file names should open the repository and read the documentation the maintainers provide.

Configuring encryption protocols

The README demonstrates verifying DNSCrypt with a dig command against port 8443, querying the TXT record at 2.dnscrypt-cert.example.com. This checks that the DNSCrypt certificate is served correctly. Beyond DNSCrypt, the quick start exercises DoT, DoQ, and DoH through kdig with the appropriate plus flags, each on its own port. The README's feature list also mentions TLS, QUIC, HTTPS, HTTP3, DTLS, and the TLCP or DTLCP variants, plus KTLS offload to the kernel. Together these cover nearly every modern encrypted DNS standard in one server. A user can enable only the transports they need by editing the generated config. The presence of both classic DNSCrypt and the post quantum (PQ) DNSCrypt option points to a design that tracks current and emerging standards. The README treats encrypted transport as a core capability rather than an add on, which matches the project's stated goal of full protocol encryption. Because each protocol listens on a distinct port in the examples, a reader can test them one at a time and map ports to transports without ambiguity. The information above is drawn from the project README and its repository metadata, which remain the source for the project's current behaviour. The binary is built with go build and the version shown in the README is 4.4.1 using Go 1.27. A reader who wants exact commands or file names should open the repository and read the documentation the maintainers provide.

How recursive resolution works

The README's core features section describes how resolution works. Recursive resolution walks from the IANA root servers down to authoritative servers, building a full DNSSEC trust chain. It uses root hints plus a latency ordered cache and a delegation cache. Upstream forwarding is supported, with primary and backup servers queried concurrently and a first wins strategy, and a pure recursive mode is available through protocol set to recursive. CNAME tracing goes up to 16 levels with loop detection. QNAME minimisation, per RFC 9156, is enabled by default. A delegation cache stores zone cut records, namely NS names and DS, in an in memory LRU with a snapshot file, so later subdomain queries skip known levels. Concurrent deduplication uses singleflight to merge repeated misses. Compact denial per RFC 9824 sets a code bit so NXNAME signals recover NXDOMAIN semantics. Fragment avoidance per RFC 9715 caps UDP responses at 1400 bytes and retries over TCP when exceeded. Multi type bundling, called MQTYPE and referenced to RFC 10, bundles record types in one query. These mechanics explain how the resolver answers a name from the root up while keeping caches warm. The information above is drawn from the project README and its repository metadata, which remain the source for the project's current behaviour. The binary is built with go build and the version shown in the README is 4.4.1 using Go 1.27. A reader who wants exact commands or file names should open the repository and read the documentation the maintainers provide.

Editorial conclusion

ZJDNS is version 4.4.1, written in Go 1.27, and is shared under the Apache 2.0 license with the Commons Clause.

DEEP OPEN-SOURCE ANALYSIS

Official sources

Community notes

Community notes