diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8c41562 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +*.service linguist-language=systemd +*.slice linguist-language=systemd +*zones/*.conf linguist-language=bindzone +*keys/provider_name linguist-language=Text + +# vim: ts=8 sts=8 sw=8 noexpandtab diff --git a/.gitignore b/.gitignore index b2eedbd..b4fa870 100644 --- a/.gitignore +++ b/.gitignore @@ -1,27 +1,4 @@ - -# Created by https://www.toptal.com/developers/gitignore/api/vim -# Edit at https://www.toptal.com/developers/gitignore?templates=vim - ### Vim ### -# Swap [._]*.s[a-v][a-z] -!*.svg # comment out if you don't need vector files [._]*.sw[a-p] -[._]s[a-rt-v][a-z] -[._]ss[a-gi-z] [._]sw[a-p] - -# Session -Session.vim -Sessionx.vim - -# Temporary -.netrwhist -*~ -# Auto-generated tag files -tags -# Persistent undo -[._]*.un~ - -# End of https://www.toptal.com/developers/gitignore/api/vim - diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000..05e4822 --- /dev/null +++ b/.yamllint @@ -0,0 +1,12 @@ +--- +yaml-files: + - '*.yaml' + - '*.yml' + - '.yamllint' + +rules: + line-length: + level: warning + +# vim: ft=yaml bs=2 ts=2 +... diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2fc469c --- /dev/null +++ b/LICENSE @@ -0,0 +1,14 @@ +DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + +Version 2, December 2004 + +Copyright (C) 2022 dotya.ml authors + +Everyone is permitted to copy and distribute verbatim or modified copies of +this license document, and changing it is allowed as long as the name is changed. + +DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/README.md b/README.md index 55d0bf0..43fe4a7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,66 @@ -# dnscrypt-server +# [`dnscrypt-server`](https://git.dotya.ml/dotya.ml/dnscrypt-server) this repo holds configuration files for dotya.ml's DNSCrypt installation. + +## what exactly? +* containerised [`encrypted-dns`](https://github.com/DNSCrypt/encrypted-dns-server) +* [OpenNIC](https://www.opennic.org/) domain support + * test using the awesome [`doggo`](https://github.com/mr-karan/doggo): + ```shell + doggo --debug --json NS epic. @sdns://AQcAAAAAAAAAETE0NC45MS43MC42Mjo1NDQzIHF-JiN46cNwFXJleEVWGWgrhe2QeysUtZoo9HwzYCMzITIuZG5zY3J5cHQtY2VydC5kbnNjcnlwdC5kb3R5YS5tbA + ``` + * example response: + ```shell + DEBUG[2022-09-01T00:22:23+02:00] initiating DNSCrypt resolver + + DEBUG[2022-09-01T00:22:23+02:00] Starting doggo 🐶 + + DEBUG[2022-09-01T00:22:23+02:00] Attempting to resolve domain=epic. nameserver="144.91.70.62:5443" ndots=0 + [ + { + "answers": [ + { + "name": "epic.", + "type": "NS", + "class": "IN", + "ttl": "86400s", + "address": "ns13.opennic.glue.", + "status": "", + "rtt": "45ms", + "nameserver": "144.91.70.62:5443" + } + ], + "authorities": null, + "questions": [ + { + "name": "epic.", + "type": "NS", + "class": "IN" + } + ] + } + ] + ``` + +a short asciicast of `doggo` interacting with our server: +[![asciicast](https://asciinema.org/a/KPGuJaYiztnOmCzCSwtfExpB3.svg)](https://asciinema.org/a/KPGuJaYiztnOmCzCSwtfExpB3) + +## why though +* improved DNS security: DNSSEC-validated responses protected by [`DNSCrypt`](https://github.com/DNSCrypt/dnscrypt-protocol/blob/master/DNSCRYPT-V2-PROTOCOL.txt) +* support for [`Anonymized DNSCrypt`](https://github.com/DNSCrypt/dnscrypt-protocol/blob/master/ANONYMIZED-DNSCRYPT.txt) +* DNS neutrality: *moar DNS == moar better* +* no logging: increased privacy +* easy access to OpenNIC interwebz +* self-hosting is fun + +## observability +a dashboard ([source](https://github.com/DNSCrypt/encrypted-dns-server/issues/66#issuecomment-868753382)) +is available for conveniently presented performance insights and cache +efficiency monitoring, deployed at https://grafana.dotya.ml/d/kX2luvMnz/dnscrypt + + +## TO DO +- [ ] automated deployment (preferably using `ansible` + `drone`) + +## LICENSE +WTFPLv2, see [LICENSE](LICENSE) for details. diff --git a/docker-compose.yml b/etc/dnscrypt-server/docker-compose.yml similarity index 56% rename from docker-compose.yml rename to etc/dnscrypt-server/docker-compose.yml index bcb15f9..03c0833 100644 --- a/docker-compose.yml +++ b/etc/dnscrypt-server/docker-compose.yml @@ -1,10 +1,16 @@ +--- version: "3" services: dnscrypt: - image: zquestz/dnscrypt-server:latest + # https://github.com/dnscrypt/dnscrypt-server-docker + # TODO: since only :latest is provided, pin using image's sha256? + image: docker.io/jedisct1/dnscrypt-server:latest container_name: dnscrypt restart: always + mem_limit: 64m + labels: + - traefik.enable=false command: "start -N dnscrypt.dotya.ml -E '144.91.70.62:5443,[2a02:c207:2030:396::1]:5443' -M 0.0.0.0:9101" ports: - '5443:5443/udp' @@ -12,8 +18,10 @@ services: - '9101:9101/tcp' volumes: - ./keys:/opt/encrypted-dns/etc/keys + - ./zones:/opt/unbound/etc/unbound/zones environment: - TZ='UTC' volumes: keys: +... diff --git a/etc/dnscrypt-server/encrypted-dns.toml b/etc/dnscrypt-server/encrypted-dns.toml new file mode 120000 index 0000000..ecc8976 --- /dev/null +++ b/etc/dnscrypt-server/encrypted-dns.toml @@ -0,0 +1 @@ +keys/encrypted-dns.toml \ No newline at end of file diff --git a/etc/dnscrypt-server/keys/encrypted-dns.toml b/etc/dnscrypt-server/keys/encrypted-dns.toml new file mode 100644 index 0000000..c79f04e --- /dev/null +++ b/etc/dnscrypt-server/keys/encrypted-dns.toml @@ -0,0 +1,262 @@ +#################################################### +# # +# Encrypted DNS Server configuration # +# # +#################################################### + + + +################################## +# Global settings # +################################## + + +## IP addresses and ports to listen to, as well as their external IP +## If there is no NAT involved, `local` and `external` can be the same. +## As many addresses as needed can be configured here, IPv4 and/or IPv6. +## You should at least change the `external` IP address. + +### Example with both IPv4 and IPv6 addresses: +# listen_addrs = [ +# { local = "0.0.0.0:443", external = "198.51.100.1:443" }, +# { local = "[::]:443", external = "[2001:db8::1]:443" } +# ] + +listen_addrs = [ + { local = "0.0.0.0:5443", external = "144.91.70.62:5443" }, { local = "[::]:5443", external = "[2a02:c207:2030:396::1]:5443" } +] + + +## Upstream DNS server and port + +upstream_addr = "127.0.0.1:553" + + +## File name to save the state to + +state_file = "/opt/encrypted-dns/etc/keys/state/encrypted-dns.state" + + +## UDP timeout in seconds + +# udp_timeout = 10 +udp_timeout = 7 + + +## TCP timeout in seconds + +# tcp_timeout = 10 +tcp_timeout = 7 + + +## Maximum active UDP sockets + +#udp_max_active_connections = 1000 +udp_max_active_connections = 2048 + + +## Maximum active TCP connections + +#tcp_max_active_connections = 100 +tcp_max_active_connections = 2048 + + +## Optional IP address to connect to upstream servers from. +## Leave commented/undefined to automatically select it. + +# external_addr = "0.0.0.0" + + +## Built-in DNS cache capacity + +cache_capacity = 15000 + + +## DNS cache: minimum TTL + +cache_ttl_min = 3600 + + +## DNS cache: max TTL + +cache_ttl_max = 86400 + + +## DNS cache: error TTL + +cache_ttl_error = 600 + + +## DNS cache: to avoid bursts of traffic for popular queries when an +## RRSET expires, hold a TTL received from an upstream server for +## `client_ttl_holdon` seconds before decreasing it in client responses. + +client_ttl_holdon = 60 + + +## Run as a background process + +daemonize = false + + +## Log file + +# log_file = "/tmp/encrypted-dns.log" + + +## PID file + +# pid_file = "/tmp/encrypted-dns.pid" + + +## User name to drop privileges to, when started as root. + +user = "_encrypted-dns" + + +## Group name to drop privileges to, when started as root. + +group = "_encrypted-dns" + + +## Path to chroot() to, when started as root. +## The path to the state file is relative to the chroot base. + +# chroot = "/var/empty" + + +## Queries sent to that name will return the client IP address. +## This can be very useful for debugging, or to check that relaying works. + +my_ip = "my.ip" + + +#################################### +# DNSCrypt settings # +#################################### + +[dnscrypt] + +## Provider name (with or without the `2.dnscrypt-cert.` prefix) + +provider_name = "2.dnscrypt-cert.dnscrypt.dotya.ml" + + +## Does the server support DNSSEC? + +dnssec = true + + +## Does the server always returns correct answers (no filtering, including ad blocking)? + +no_filters = true + + +## Set to `true` if the server doesn't keep any information that can be used to identify users + +no_logs = true + + +## Key cache capacity, per certificate + +key_cache_capacity = 10000 + + + +############################### +# TLS settings # +############################### + +[tls] + +## Where to proxy TLS connections to (e.g. DoH server) + +# upstream_addr = "127.0.0.1:4343" + + + + + +####################################### +# Server-side filtering # +####################################### + +[filtering] + +## List of domains to block, one per line + + + + +## List of undelegated TLDs +## This is the list of nonexistent TLDs that queries are frequently observed for, +## but will never resolve to anything. The server will immediately return a +## synthesized NXDOMAIN response instead of hitting root servers. + +undelegated_list = "/opt/encrypted-dns/etc/undelegated.txt" + + +## Ignore A and AAAA queries for unqualified host names. + +ignore_unqualified_hostnames = true + + + +######################### +# Metrics # +######################### + +[metrics] + +type = "prometheus" +listen_addr = "0.0.0.0:9101" +path = "/metrics" + + + +################################ +# Anonymized DNS # +################################ + +[anonymized_dns] + +# Enable relaying support for Anonymized DNS + +enabled = true + + +# Allowed upstream ports +# This is a list of commonly used ports for encrypted DNS services + +#allowed_ports = [ 443, 553, 853, 1443, 2053, 4343, 4434, 4443, 5353, 5443, 8443, 15353 ] +allowed_ports = [ 553, 1443, 2053, 4343, 4434, 4443, 5353, 5443, 8443, 15353 ] + + +# Allow all ports >= 1024 in addition to the list above + +allow_non_reserved_ports = false + + +# Blacklisted upstream IP addresses + +blacklisted_ips = [ ] + + + + +################################ +# Access control # +################################ + +[access_control] + +# Enable access control + +enabled = false + +# Only allow access to client queries including one of these random tokens +# Tokens can be configured in the `query_meta` section of `dnscrypt-proxy` as +# `query_meta = ["token:..."]` -- Replace ... with the token to use by the client. +# Example: `query_meta = ["token:Y2oHkDJNHz"]` + +tokens = ["Y2oHkDJNHz", "G5zY3J5cHQtY", "C5zZWN1cmUuZG5z"] diff --git a/etc/dnscrypt-server/keys/provider_name b/etc/dnscrypt-server/keys/provider_name new file mode 100644 index 0000000..2472c96 --- /dev/null +++ b/etc/dnscrypt-server/keys/provider_name @@ -0,0 +1 @@ +2.dnscrypt-cert.dnscrypt.dotya.ml diff --git a/etc/dnscrypt-server/zones/opennic-tlds.conf b/etc/dnscrypt-server/zones/opennic-tlds.conf new file mode 100644 index 0000000..0d5b71e --- /dev/null +++ b/etc/dnscrypt-server/zones/opennic-tlds.conf @@ -0,0 +1,174 @@ +# dig txt tlds.opennic.glue @161.97.219.84 +short +# "." "bbs" "chan" "cyb" "dyn" "epic" "geek" "gopher" "indy" "libre" "neo" "null" "o" "opennic.glue" "oss" "oz" "parody" "pirate" + +auth-zone: + name: "bbs." + primary: 161.97.219.84 + primary: 188.40.132.212 + primary: 94.103.153.176 + primary: 2a02:990:219:1:ba:1337:cafe:3 + primary: 2001:470:4212:10:0:100:53:10 + primary: 2a01:4f8:141:4281::999 + primary: 2a01:4f8:192:43a5::2 + +auth-zone: + name: "chan." + primary: 161.97.219.84 + primary: 188.40.132.212 + primary: 94.103.153.176 + primary: 2a02:990:219:1:ba:1337:cafe:3 + primary: 2001:470:4212:10:0:100:53:10 + primary: 2a01:4f8:141:4281::999 + primary: 2a01:4f8:192:43a5::2 + +auth-zone: + name: "cyb." + primary: 161.97.219.84 + primary: 188.40.132.212 + primary: 94.103.153.176 + primary: 2a02:990:219:1:ba:1337:cafe:3 + primary: 2001:470:4212:10:0:100:53:10 + primary: 2a01:4f8:141:4281::999 + primary: 2a01:4f8:192:43a5::2 + +auth-zone: + name: "dyn." + primary: 161.97.219.84 + primary: 188.40.132.212 + primary: 94.103.153.176 + primary: 2a02:990:219:1:ba:1337:cafe:3 + primary: 2001:470:4212:10:0:100:53:10 + primary: 2a01:4f8:141:4281::999 + primary: 2a01:4f8:192:43a5::2 + +auth-zone: + name: "epic." + primary: 161.97.219.84 + primary: 188.40.132.212 + primary: 94.103.153.176 + primary: 2a02:990:219:1:ba:1337:cafe:3 + primary: 2001:470:4212:10:0:100:53:10 + primary: 2a01:4f8:141:4281::999 + primary: 2a01:4f8:192:43a5::2 + +auth-zone: + name: "geek." + primary: 161.97.219.84 + primary: 188.40.132.212 + primary: 94.103.153.176 + primary: 2a02:990:219:1:ba:1337:cafe:3 + primary: 2001:470:4212:10:0:100:53:10 + primary: 2a01:4f8:141:4281::999 + primary: 2a01:4f8:192:43a5::2 + +auth-zone: + name: "gopher." + primary: 161.97.219.84 + primary: 188.40.132.212 + primary: 94.103.153.176 + primary: 2a02:990:219:1:ba:1337:cafe:3 + primary: 2001:470:4212:10:0:100:53:10 + primary: 2a01:4f8:141:4281::999 + primary: 2a01:4f8:192:43a5::2 + +auth-zone: + name: "indy." + primary: 161.97.219.84 + primary: 188.40.132.212 + primary: 94.103.153.176 + primary: 2a02:990:219:1:ba:1337:cafe:3 + primary: 2001:470:4212:10:0:100:53:10 + primary: 2a01:4f8:141:4281::999 + primary: 2a01:4f8:192:43a5::2 + +auth-zone: + name: "libre." + primary: 161.97.219.84 + primary: 188.40.132.212 + primary: 94.103.153.176 + primary: 2a02:990:219:1:ba:1337:cafe:3 + primary: 2001:470:4212:10:0:100:53:10 + primary: 2a01:4f8:141:4281::999 + primary: 2a01:4f8:192:43a5::2 + +auth-zone: + name: "neo." + primary: 161.97.219.84 + primary: 188.40.132.212 + primary: 94.103.153.176 + primary: 2a02:990:219:1:ba:1337:cafe:3 + primary: 2001:470:4212:10:0:100:53:10 + primary: 2a01:4f8:141:4281::999 + primary: 2a01:4f8:192:43a5::2 + +auth-zone: + name: "null." + primary: 161.97.219.84 + primary: 188.40.132.212 + primary: 94.103.153.176 + primary: 2a02:990:219:1:ba:1337:cafe:3 + primary: 2001:470:4212:10:0:100:53:10 + primary: 2a01:4f8:141:4281::999 + primary: 2a01:4f8:192:43a5::2 + +auth-zone: + name: "o." + primary: 161.97.219.84 + primary: 188.40.132.212 + primary: 94.103.153.176 + primary: 2a02:990:219:1:ba:1337:cafe:3 + primary: 2001:470:4212:10:0:100:53:10 + primary: 2a01:4f8:141:4281::999 + primary: 2a01:4f8:192:43a5::2 + +auth-zone: + name: "opennic.glue." + primary: 161.97.219.84 + primary: 188.40.132.212 + primary: 94.103.153.176 + primary: 2a02:990:219:1:ba:1337:cafe:3 + primary: 2001:470:4212:10:0:100:53:10 + primary: 2a01:4f8:141:4281::999 + primary: 2a01:4f8:192:43a5::2 + +auth-zone: + name: "oss." + primary: 161.97.219.84 + primary: 188.40.132.212 + primary: 94.103.153.176 + primary: 2a02:990:219:1:ba:1337:cafe:3 + primary: 2001:470:4212:10:0:100:53:10 + primary: 2a01:4f8:141:4281::999 + primary: 2a01:4f8:192:43a5::2 + +auth-zone: + name: "oz." + primary: 161.97.219.84 + primary: 188.40.132.212 + primary: 94.103.153.176 + primary: 2a02:990:219:1:ba:1337:cafe:3 + primary: 2001:470:4212:10:0:100:53:10 + primary: 2a01:4f8:141:4281::999 + primary: 2a01:4f8:192:43a5::2 + +auth-zone: + name: "parody." + primary: 161.97.219.84 + primary: 188.40.132.212 + primary: 94.103.153.176 + primary: 2a02:990:219:1:ba:1337:cafe:3 + primary: 2001:470:4212:10:0:100:53:10 + primary: 2a01:4f8:141:4281::999 + primary: 2a01:4f8:192:43a5::2 + +auth-zone: + name: "pirate." + primary: 161.97.219.84 + primary: 188.40.132.212 + primary: 94.103.153.176 + primary: 2a02:990:219:1:ba:1337:cafe:3 + primary: 2001:470:4212:10:0:100:53:10 + primary: 2a01:4f8:141:4281::999 + primary: 2a01:4f8:192:43a5::2 + +# vim: ft:bindzone ff=unix fenc=utf8 diff --git a/systemd/dnscrypt-server.service b/etc/systemd/system/dnscrypt-server.service similarity index 83% rename from systemd/dnscrypt-server.service rename to etc/systemd/system/dnscrypt-server.service index 402a385..dd79c08 100644 --- a/systemd/dnscrypt-server.service +++ b/etc/systemd/system/dnscrypt-server.service @@ -4,6 +4,7 @@ Description=A Docker image for a non-censoring, non-logging, DNSSEC-capable, DNS [Service] Restart=always +ExecStartPre=/usr/bin/docker-compose -p dnscrypt-server -f /etc/dnscrypt/docker-compose.yml down ExecStart=/usr/bin/docker-compose -p dnscrypt-server -f /etc/dnscrypt/docker-compose.yml up --remove-orphans ExecStop=/usr/bin/docker-compose -p dnscrypt-server -f /etc/dnscrypt/docker-compose.yml stop StartLimitBurst=5 diff --git a/systemd/dnscrypt-server.slice b/etc/systemd/system/dnscrypt-server.slice similarity index 88% rename from systemd/dnscrypt-server.slice rename to etc/systemd/system/dnscrypt-server.slice index 843aa8e..a298aad 100644 --- a/systemd/dnscrypt-server.slice +++ b/etc/systemd/system/dnscrypt-server.slice @@ -7,5 +7,5 @@ CPUAccounting=true # 100% is an equivalent of full utilization on a single core CPUQuota=60% MemoryAccounting=true -MemoryHigh=900M -MemoryMax=1.5G +MemoryHigh=90M +MemoryMax=100M