zdns

package module
v0.0.0-...-fbfc268 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 19, 2024 License: Apache-2.0 Imports: 15 Imported by: 0

README

zdns

Build Status

zdns is a privacy-focused DNS resolver and DNS sinkhole.

Its primary focus is to allow easy filtering of unwanted content at the DNS-level, transport upstream requests securely, be portable and easy to configure.

Contents

Features

  • Control: Filter unwanted content at the DNS-level. Similar to Pi-hole.
  • Fast: Parallel resolving over multiple resolvers, efficient filtering and caching of DNS requests. With pre-fetching enabled, cached requests will never block waiting for the upstream resolver. Asynchronous persistent caching is also supported.
  • Reliable: Built with Go and miekg/dns - a mature DNS library.
  • Secure: Protect your DNS requests from snooping and tampering using DNS over TLS or DNS over HTTPS for upstream resolvers.
  • Self-contained: Zero run-time dependencies makes zdns easy to deploy and maintain.
  • Observable: zdns features DNS logging and metrics which makes it easy to observe what's going on your network.
  • Portable: Run it on your VPS, container, laptop, Raspberry Pi or home router. Runs on all platforms supported by Go.

Usage

Installation

zdns is a standard Go package. Install with:

$ go install github.com/mpolden/zdns/...@latest
Configuration

zdns uses the TOML configuration format and expects to find its configuration file in ~/.zdnsrc by default.

See zdnsrc for an example configuration file. zdns.service contains an example systemd service file.

An optional command line option, -f, allows specifying a custom configuration file path.

Logging

zdns supports logging of DNS requests. Logs are written to a SQLite database.

Logs can be inspected through the built-in REST API or by querying the SQLite database directly. See zdnsrc for more details.

Port redirection

Most operating systems expect to find their DNS resolver on UDP port 53. However, as this is a well-known port, any program listening on this port must have special privileges.

To work around this problem we can configure the firewall to redirect connections to port 53 to a non-reserved port.

The following examples assumes that zdns is running on port 53000. See zdnsrc for port configuration.

Linux (iptables)
# External requests
$ iptables -t nat -A PREROUTING -d -p udp -m udp --dport 53 -j REDIRECT --to-ports 53000

# Local requests
$ iptables -A OUTPUT -d 127.0.0.1 -p udp -m udp --dport 53 -j REDIRECT --to-ports 53000
macOS (pf)
  1. Edit /etc/pf.conf
  2. Add rdr pass inet proto udp from any to 127.0.0.1 port domain -> 127.0.0.1 port 53000 below the last rdr-anchor line.
  3. Enable PF and load rules: pfctl -ef /etc/pf.conf

REST API

A basic REST API provides access to request log and cache entries. The API is served by the built-in web server, which can be enabled in zdnsrc.

Examples

Read the log:

$ curl -s 'http://127.0.0.1:8053/log/v1/?n=1' | jq .
[
  {
    "time": "2019-12-27T10:43:23Z",
    "remote_addr": "127.0.0.1",
    "hijacked": false,
    "type": "AAAA",
    "question": "discovery.syncthing.net.",
    "answers": [
      "2400:6180:100:d0::741:a001",
      "2a03:b0c0:0:1010::bb:4001"
    ]
  }
]

Read the cache:

$ curl -s 'http://127.0.0.1:8053/cache/v1/?n=1' | jq .
[
  {
    "time": "2019-12-27T10:46:11Z",
    "ttl": 18,
    "type": "A",
    "question": "gateway.fe.apple-dns.net.",
    "answers": [
      "17.248.150.110",
      "17.248.150.113",
      "17.248.150.10",
      "17.248.150.40",
      "17.248.150.42",
      "17.248.150.51",
      "17.248.150.79",
      "17.248.150.108"
    ],
    "rcode": "NOERROR"
  }
]

Clear the cache:

$ curl -s -XDELETE 'http://127.0.0.1:8053/cache/v1/' | jq .
{
  "message": "Cleared cache."
}

Metrics:

$ curl 'http://127.0.0.1:8053/metric/v1/?resolution=1m' | jq .
{
  "summary": {
    "log": {
      "since": "2020-01-05T00:58:49Z",
      "total": 3816,
      "hijacked": 874,
      "pending_tasks": 0
    },
    "cache": {
      "size": 845,
      "capacity": 4096,
      "pending_tasks": 0,
      "backend": {
        "pending_tasks": 0
      }
    }
  },
  "requests": [
    {
      "time": "2020-01-05T00:58:49Z",
      "count": 1
    }
  ]
}

Note that log_mode = "hijacked" or log_mode = "all" is required to make metrics available. Choosing hijacked will only produce metrics for hijacked requests.

The query parameter resolution controls the resolution of the data points in requests. It accepts the same values as time.ParseDuration and defaults to 1m.

Why not Pi-hole?

This is my personal opinion and not a objective assessment of Pi-hole.

  • Pi-hole has lots of dependencies and a large feature scope.

  • Buggy installation script. In my personal experience, the 4.3 installation script failed silently in both Debian stretch and buster LXC containers.

  • Installation method pipes curl to bash. Not properly packaged for any distributions.

Documentation

Index

Constants

View Source
const (
	// HijackZero returns the zero IP address to matching requests.
	HijackZero = iota
	// HijackEmpty returns an empty answer to matching requests.
	HijackEmpty
	// HijackHosts returns the value of the  hoss entry to matching request.
	HijackHosts
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	DNS      DNSOptions
	Resolver ResolverOptions
	Hosts    []Hosts
}

Config specifies is the zdns configuration parameters.

func ReadConfig

func ReadConfig(r io.Reader) (Config, error)

ReadConfig reads a zdns configuration from reader r.

type DNSOptions

type DNSOptions struct {
	Listen        string
	Protocol      string `toml:"protocol"`
	CacheSize     int    `toml:"cache_size"`
	CachePrefetch bool   `toml:"cache_prefetch"`
	CachePersist  bool   `toml:"cache_persist"`
	HijackMode    string `toml:"hijack_mode"`

	RefreshInterval string `toml:"hosts_refresh_interval"`

	Resolvers     []string
	Database      string `toml:"database"`
	LogModeString string `toml:"log_mode"`
	LogMode       int
	LogTTLString  string `toml:"log_ttl"`
	LogTTL        time.Duration
	ListenHTTP    string `toml:"listen_http"`
	// contains filtered or unexported fields
}

DNSOptions controlers the behaviour of the DNS server.

type Hosts

type Hosts struct {
	URL   string
	Hosts []string `toml:"entries"`

	Hijack  bool
	Timeout string
	// contains filtered or unexported fields
}

Hosts controls how a hosts file should be retrieved.

type ResolverOptions

type ResolverOptions struct {
	Protocol      string `toml:"protocol"`
	TimeoutString string `toml:"timeout"`
	Timeout       time.Duration
}

ResolverOptions controls the behaviour of resolvers.

type Server

type Server struct {
	Config Config
	// contains filtered or unexported fields
}

A Server defines parameters for running a DNS server.

func NewServer

func NewServer(proxy *dns.Proxy, config Config) (*Server, error)

NewServer returns a new server configured according to config.

func (*Server) Close

func (s *Server) Close() error

Close terminates all active operations and shuts down the DNS server.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe() error

ListenAndServe starts a server on configured address and protocol.

func (*Server) Reload

func (s *Server) Reload()

Reload updates hosts entries of Server s.

Directories

Path Synopsis
cmd
dns

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL