{"id":15655245,"url":"https://github.com/mpolden/zdns","last_synced_at":"2025-05-05T03:43:16.819Z","repository":{"id":57541375,"uuid":"230619550","full_name":"mpolden/zdns","owner":"mpolden","description":"A privacy-focused DNS resolver and DNS sinkhole","archived":false,"fork":false,"pushed_at":"2025-04-17T08:45:37.000Z","size":394,"stargazers_count":28,"open_issues_count":2,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-05T03:43:03.438Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mpolden.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-12-28T14:18:25.000Z","updated_at":"2025-04-17T08:45:35.000Z","dependencies_parsed_at":"2022-09-26T18:30:47.442Z","dependency_job_id":"7a74940a-c888-48da-9af3-a42049f972a2","html_url":"https://github.com/mpolden/zdns","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpolden%2Fzdns","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpolden%2Fzdns/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpolden%2Fzdns/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpolden%2Fzdns/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mpolden","download_url":"https://codeload.github.com/mpolden/zdns/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252436240,"owners_count":21747467,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-03T12:57:21.224Z","updated_at":"2025-05-05T03:43:16.801Z","avatar_url":"https://github.com/mpolden.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# zdns\n\n![Build Status](https://github.com/mpolden/zdns/workflows/ci/badge.svg)\n\n`zdns` is a privacy-focused [DNS\nresolver](https://en.wikipedia.org/wiki/Domain_Name_System#DNS_resolvers) and\n[DNS sinkhole](https://en.wikipedia.org/wiki/DNS_sinkhole).\n\nIts primary focus is to allow easy filtering of unwanted content at the\nDNS-level, transport upstream requests securely, be portable and easy to\nconfigure.\n\n## Contents\n\n* [Features](#features)\n* [Usage](#usage)\n  * [Installation](#installation)\n  * [Configuration](#configuration)\n  * [Logging](#logging)\n  * [Port redirection](#port-redirection)\n* [REST API](#rest-api)\n* [Why not Pi-hole?](#why-not-pi-hole)\n\n## Features\n\n* **Control**: Filter unwanted content at the DNS-level. Similar to\n  [Pi-hole](https://github.com/pi-hole/pi-hole).\n* **Fast**: Parallel resolving over multiple resolvers, efficient filtering and\n  caching of DNS requests. With pre-fetching enabled, cached requests will never\n  block waiting for the upstream resolver. Asynchronous persistent caching is\n  also supported.\n* **Reliable**: Built with Go and [miekg/dns](https://github.com/miekg/dns) - a\n  mature DNS library.\n* **Secure**: Protect your DNS requests from snooping and tampering using [DNS\n  over TLS](https://en.wikipedia.org/wiki/DNS_over_TLS) or [DNS over\n  HTTPS](https://en.wikipedia.org/wiki/DNS_over_HTTPS) for upstream resolvers.\n* **Self-contained**: Zero run-time dependencies makes `zdns` easy to deploy and\n  maintain.\n* **Observable**: `zdns` features DNS logging and metrics which makes it easy to\n  observe what's going on your network.\n* **Portable**: Run it on your VPS, container, laptop, Raspberry Pi or home\n  router. Runs on all platforms supported by Go.\n\n## Usage\n\n### Installation\n\n`zdns` is a standard Go package. Install with:\n\n``` shell\n$ go install github.com/mpolden/zdns/...@latest\n```\n\n### Configuration\n\n`zdns` uses the [TOML](https://github.com/toml-lang/toml) configuration format\nand expects to find its configuration file in `~/.zdnsrc` by default.\n\nSee [zdnsrc](zdnsrc) for an example configuration file.\n[zdns.service](zdns.service) contains an example systemd service file.\n\nAn optional command line option, `-f`, allows specifying a custom configuration\nfile path.\n\n### Logging\n\n`zdns` supports logging of DNS requests. Logs are written to a SQLite database.\n\nLogs can be inspected through the built-in REST API or by querying the SQLite\ndatabase directly. See `zdnsrc` for more details.\n\n### Port redirection\n\nMost operating systems expect to find their DNS resolver on UDP port 53.\nHowever, as this is a well-known port, any program listening on this port must\nhave special privileges.\n\nTo work around this problem we can configure the firewall to redirect\nconnections to port 53 to a non-reserved port.\n\nThe following examples assumes that `zdns` is running on port 53000. See\n`zdnsrc` for port configuration.\n\n#### Linux (iptables)\n\n``` shell\n# External requests\n$ iptables -t nat -A PREROUTING -d -p udp -m udp --dport 53 -j REDIRECT --to-ports 53000\n\n# Local requests\n$ iptables -A OUTPUT -d 127.0.0.1 -p udp -m udp --dport 53 -j REDIRECT --to-ports 53000\n```\n\n#### macOS (pf)\n\n1. Edit `/etc/pf.conf`\n2. Add `rdr pass inet proto udp from any to 127.0.0.1 port domain -\u003e 127.0.0.1 port 53000` below the last `rdr-anchor` line.\n3. Enable PF and load rules: `pfctl -ef /etc/pf.conf`\n\n## REST API\n\nA basic REST API provides access to request log and cache entries. The API is\nserved by the built-in web server, which can be enabled in `zdnsrc`.\n\n### Examples\n\nRead the log:\n```shell\n$ curl -s 'http://127.0.0.1:8053/log/v1/?n=1' | jq .\n[\n  {\n    \"time\": \"2019-12-27T10:43:23Z\",\n    \"remote_addr\": \"127.0.0.1\",\n    \"hijacked\": false,\n    \"type\": \"AAAA\",\n    \"question\": \"discovery.syncthing.net.\",\n    \"answers\": [\n      \"2400:6180:100:d0::741:a001\",\n      \"2a03:b0c0:0:1010::bb:4001\"\n    ]\n  }\n]\n```\n\nRead the cache:\n```shell\n$ curl -s 'http://127.0.0.1:8053/cache/v1/?n=1' | jq .\n[\n  {\n    \"time\": \"2019-12-27T10:46:11Z\",\n    \"ttl\": 18,\n    \"type\": \"A\",\n    \"question\": \"gateway.fe.apple-dns.net.\",\n    \"answers\": [\n      \"17.248.150.110\",\n      \"17.248.150.113\",\n      \"17.248.150.10\",\n      \"17.248.150.40\",\n      \"17.248.150.42\",\n      \"17.248.150.51\",\n      \"17.248.150.79\",\n      \"17.248.150.108\"\n    ],\n    \"rcode\": \"NOERROR\"\n  }\n]\n```\n\nClear the cache:\n```shell\n$ curl -s -XDELETE 'http://127.0.0.1:8053/cache/v1/' | jq .\n{\n  \"message\": \"Cleared cache.\"\n}\n```\n\nMetrics:\n\n``` shell\n$ curl 'http://127.0.0.1:8053/metric/v1/?resolution=1m' | jq .\n{\n  \"summary\": {\n    \"log\": {\n      \"since\": \"2020-01-05T00:58:49Z\",\n      \"total\": 3816,\n      \"hijacked\": 874,\n      \"pending_tasks\": 0\n    },\n    \"cache\": {\n      \"size\": 845,\n      \"capacity\": 4096,\n      \"pending_tasks\": 0,\n      \"backend\": {\n        \"pending_tasks\": 0\n      }\n    }\n  },\n  \"requests\": [\n    {\n      \"time\": \"2020-01-05T00:58:49Z\",\n      \"count\": 1\n    }\n  ]\n}\n```\n\nNote that `log_mode = \"hijacked\"` or `log_mode = \"all\"` is required to make\nmetrics available. Choosing `hijacked` will only produce metrics for hijacked\nrequests.\n\nThe query parameter `resolution` controls the resolution of the data points in\n`requests`. It accepts the same values as\n[time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) and defaults to\n`1m`.\n\n## Why not Pi-hole?\n\n_This is my personal opinion and not a objective assessment of Pi-hole._\n\n* Pi-hole has lots of dependencies and a large feature scope.\n\n* Buggy installation script. In my personal experience, the 4.3 installation\n  script failed silently in both Debian stretch and buster LXC containers.\n\n* Installation method pipes `curl` to `bash`. Not properly packaged for any\n  distributions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpolden%2Fzdns","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmpolden%2Fzdns","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpolden%2Fzdns/lists"}