Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/mpolden/zdns

A privacy-focused DNS resolver and DNS sinkhole
https://github.com/mpolden/zdns

Last synced: 15 days ago
JSON representation

A privacy-focused DNS resolver and DNS sinkhole

Awesome Lists containing this project

README

        

# zdns

![Build Status](https://github.com/mpolden/zdns/workflows/ci/badge.svg)

`zdns` is a privacy-focused [DNS
resolver](https://en.wikipedia.org/wiki/Domain_Name_System#DNS_resolvers) and
[DNS sinkhole](https://en.wikipedia.org/wiki/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](#features)
* [Usage](#usage)
* [Installation](#installation)
* [Configuration](#configuration)
* [Logging](#logging)
* [Port redirection](#port-redirection)
* [REST API](#rest-api)
* [Why not Pi-hole?](#why-not-pi-hole)

## Features

* **Control**: Filter unwanted content at the DNS-level. Similar to
[Pi-hole](https://github.com/pi-hole/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](https://github.com/miekg/dns) - a
mature DNS library.
* **Secure**: Protect your DNS requests from snooping and tampering using [DNS
over TLS](https://en.wikipedia.org/wiki/DNS_over_TLS) or [DNS over
HTTPS](https://en.wikipedia.org/wiki/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:

``` shell
$ go install github.com/mpolden/zdns/...@latest
```

### Configuration

`zdns` uses the [TOML](https://github.com/toml-lang/toml) configuration format
and expects to find its configuration file in `~/.zdnsrc` by default.

See [zdnsrc](zdnsrc) for an example configuration file.
[zdns.service](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)

``` shell
# 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:
```shell
$ 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:
```shell
$ 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:
```shell
$ curl -s -XDELETE 'http://127.0.0.1:8053/cache/v1/' | jq .
{
"message": "Cleared cache."
}
```

Metrics:

``` shell
$ 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](https://golang.org/pkg/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.