DNSvizor
Privacy-enhanced, secure and robust DNS resolver and DHCP server with a small resource footprint as a MirageOS unikernel
Declared in: projects/DNSvizor/default.nix
Try the service in a VM
-
Install Nix
- Bash
-
$ apt install --yes curl git jq nix
- Bash
-
$ apt install --yes curl git jq nix
- Bash
-
$ pacman --sync --refresh --noconfirm curl git jq nix
-
Download a configuration file
# default.nix { ngipkgs ? import (fetchTarball "https://github.com/ngi-nix/ngipkgs/tarball/main") { }, }: ngipkgs.demo-vm ( { ... }: { services.dnsvizor = { enable = true; memory = 128; mainInterface = "enp1s0"; settings = { hostname = "dnsvizor.mydomain.example"; ipv4 = "10.0.0.2/24"; ipv4-gateway = "10.0.0.1"; ipv6 = "fdc9:281f:4d7:9ee9::2/64"; ipv6-gateway = "fdc9:281f:4d7:9ee9::1"; ca-seed = "Te9ffyY3Clcaz/4P7eFLyZQfLWIz/fSSK4NDb8THMDc="; password = "password"; dns-block = [ "block1.cli.example.com" "block2.cli.example.com" ]; dns-blocklist-url = [ "http://10.0.0.1/block-list-4" "http://[fdc9:281f:4d7:9ee9::1]:80/block-list-6" "https://example.com/non-existent-block-list" ]; qname-minimisation = true; opportunistic-tls-authoritative = true; }; openFirewall = true; }; } )
-
Enable binary substituters
- Bash
-
$ export NIX_CONFIG='substituters = https://cache.nixos.org/ https://ngi.cachix.org/ trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= ngi.cachix.org-1:n+CAL72ROC3qQuLxIHpV+Tw5t42WhXmMhprAGkRSrOw='
-
Build and run a virtual machine
- Bash
-
$ nix-build ./default.nix && ./result
- Bash
-
$ nix-build ./default.nix && ./result
- Bash
-
$ rev=$(nix-instantiate --eval --attr sources.nixpkgs.rev https://github.com/ngi-nix/ngipkgs/archive/master.tar.gz | jq --raw-output)$ nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/$rev.tar.gz --packages nix --run "nix-build ./default.nix && ./result"
- Bash
-
$ nix-build ./default.nix && ./result
-
Usage Instructions
-
Visit https://127.0.0.1:4443 in your browser. This is a web interface of DNSvizor.
You'll see a warning of potential security risk. Rest assured. This is because DNSvizor uses a self-signed certification.
Accept the risk and continue.
-
In the demo VM terminal, run this to send DNS queries to DNSvizor (
10.0.0.2):$ q --verbose www.example.com A @10.0.0.2If the query timeouts, re-run the command to query again.
-
You can also use an IPv6 address for DNSvizor (
fdc9:281f:4d7:9ee9::2):$ q --verbose www.example.com A @fdc9:281f:4d7:9ee9::2 -
You can also use a domain name for DNSvizor (
dnsvizor.mydomain.example):$ q --verbose www.example.com A @dnsvizor.mydomain.example -
Send encrypted DNS queries using
DNS-over-TLS:$ q --verbose www.example.com A @tls://dnsvizor.mydomain.exampleYou'll see an error telling you that certification verification failed. This is because DNSvizor uses a self-signed certification, which is not trusted by default. You can ignore that error by adding
--tls-insecure-skip-verify:$ q --verbose --tls-insecure-skip-verify www.example.com A @tls://dnsvizor.mydomain.example -
Let's show you how to trust that self-signed certification of DNSvizor.
First, we extract that certification using
curl.$ curl --write-out %{certs} https://dnsvizor.mydomain.example > /tmp/self-signed-cert.pemThen we setting environment variable
SSL_CERT_FILEbefore runningq.$ SSL_CERT_FILE=/tmp/self-signed-cert.pem q --verbose www.example.com A @tls://dnsvizor.mydomain.example -
Send encrypted DNS queries using
DNS-over-HTTPS:$ SSL_CERT_FILE=/tmp/self-signed-cert.pem q --verbose www.example.com A @https://dnsvizor.mydomain.example -
Go back to the Dashboard page, you should see those numbers, such as
Total queries, have changed. -
Go to the Query log page, you should see domains you just queried.
-
DNSvizor supports blocking DNS resolution for some domains. You can specify them as boot parameters.
Go to the Blocklist page. Enter the password
password. User can be anything you like. You can see some blocked domains we already specified.Query one of them:
$ q --verbose --format raw block1.cli.example.com A @dnsvizor.mydomain.exampleYou should see
status: NXDOMAINandANSWER: 0in the output. This means there is no answer to your DNS query. You should also seeappears in blocklist boot-parameterin the output. -
Blocked domains can also be specified using URLs. DNSvizor will fetch them using those URLs.
Go to the Blocklist page, you can see some blocked domain lists we already specified.
Query one of them:
$ q --verbose --format raw block1.url.example.com A @dnsvizor.mydomain.exampleYou should see
status: NXDOMAINandANSWER: 0in the output. You should also seeappears in blocklist http://10.0.0.1/block-list-4in the output. -
In the Blocklist page, you can also add or delete blocked domains.
Add one, query it and check the result.
You should see a similar output as before. But this time, it shows
appears in blocklist web-ui.Delete the domain you just added, query it and check the result.
You should see the normal result again.
-
Now go back to the Dashboard page, you should see the number of "Queries blocked" has changed.
-
Options
services.dnsvizor
-
Whether to enable dnsvizor.
- Type:
boolean- Default:
false- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
The main network interface of the host.
- Type:
string- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
Memory limit of the unikernel in MB.
- Type:
positive integer, meaning >0- Default:
512- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
Whether to enable opening ports in the firewall for dnsvizor.
- Type:
boolean- Default:
false- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
The dnsvizor (hvt target) package to use. We assume dnsvizor.hvt exists at the root dir of the package.
- Type:
package- Default:
pkgs.dnsvizor.hvt- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
Whether efforts have been taken to make sure packet forwarding is secure.
- Type:
boolean- Default:
config.networking.firewall.enable && config.networking.firewall.filterForward- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
Configuration for the unikernel. See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.- Type:
open submodule of attribute set of (null or boolean or string or list of string)- Default:
{ }- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
The seed (base64 encoded) used to generate the private key for the certificate. See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.::: {.warning} This secret will be copied into the nix store in clear text. :::
- Type:
null or string- Default:
null- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
Domains to block. See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.- Type:
list of string- Default:
[ ]- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
Web addresses to fetch DNS block lists from. See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.- Type:
list of string- Default:
[ ]- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
Upstream DNS resolver. By default, it runs as a recursive DNS resolver. If this is specified, it runs as a stub DNS resolver instead. See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.- Type:
null or string- Default:
null- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
Show help instead of running the unikernel. See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.- Type:
boolean- Default:
false- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
The hostname (SNI for the certificate, entry in DNS) of the unikernel. See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.- Type:
null or string- Default:
null- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
The HTTPS port. See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.- Type:
16 bit unsigned integer; between 0 and 65535 (both inclusive)- Default:
443- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
IPv4 network address and prefix length for the unikernel. See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.- Type:
string- Default:
"10.0.0.2/24"- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
IPv4 gateway of the unikernel. See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.- Type:
string- Default:
"10.0.0.1"- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
Only use IPv4 for the unikernel. See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.- Type:
null or one of "true", "false"- Default:
null- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
IPv6 network address and prefix length for the unikernel. See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.- Type:
null or string- Default:
null- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
IPv6 gateway of the unikernel. See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.- Type:
null or string- Default:
null- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
Only use IPv6 for the unikernel. See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.- Type:
null or one of "true", "false"- Default:
null- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
Don't read the synthesized /etc/hosts which contains only {option}
services.dnsvizor.hostname. See upstream online documentation for more information. Setting {option}services.dnsvizor.settings.helpshows the help message locally at runtime.- Type:
boolean- Default:
false- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
Disable TLS: web interface and DNS-over-TLS/DNS-over-HTTPS. See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.- Type:
boolean- Default:
config.services.dnsvizor.settings.ca-seed == null- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
Use opportunistic TLS from recursive resolver to authoriative (RFC 9539). See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.- Type:
boolean- Default:
false- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
Password used for authentication. See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.::: {.tip} The space character needs to be escaped with
\\. :::::: {.warning} This secret will be copied into the nix store in clear text. :::
- Type:
null or string- Default:
null- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
-
Use qname minimisation (RFC 9156). See upstream online documentation for more information. Setting {option}
services.dnsvizor.settings.helpshows the help message locally at runtime.- Type:
boolean- Default:
false- Declared in:
- projects/DNSvizor/services/dnsvizor/module.nix
services.dnsvizor.enable
services.dnsvizor.mainInterface
services.dnsvizor.memory
services.dnsvizor.openFirewall
services.dnsvizor.package
services.dnsvizor.packetForwardingIsSecure
services.dnsvizor.settings
services.dnsvizor.settings.ca-seed
services.dnsvizor.settings.dns-block
services.dnsvizor.settings.dns-blocklist-url
services.dnsvizor.settings.dns-upstream
services.dnsvizor.settings.help
services.dnsvizor.settings.hostname
services.dnsvizor.settings.https-port
services.dnsvizor.settings.ipv4
services.dnsvizor.settings.ipv4-gateway
services.dnsvizor.settings.ipv4-only
services.dnsvizor.settings.ipv6
services.dnsvizor.settings.ipv6-gateway
services.dnsvizor.settings.ipv6-only
services.dnsvizor.settings.no-hosts
services.dnsvizor.settings.no-tls
services.dnsvizor.settings.opportunistic-tls-authoritative
services.dnsvizor.settings.password
services.dnsvizor.settings.qname-minimisation
Examples
Enable DNSvizor as a IPv4-only stub DNS resolver
{ ... }: { services.dnsvizor = { enable = true; memory = 128; mainInterface = "enp1s0"; settings = { ipv4 = "10.0.0.2/24"; ipv4-gateway = "10.0.0.1"; ipv4-only = "true"; ca-seed = "Te9ffyY3Clcaz/4P7eFLyZQfLWIz/fSSK4NDb8THMDc="; password = "password"; dns-block = [ "block1.cli.example.com" "block2.cli.example.com" ]; dns-blocklist-url = [ "http://10.0.0.1/block-list" "https://example.com/non-existent-block-list" ]; dns-upstream = "tls:1.1.1.1"; }; }; }
Declared in: projects/DNSvizor/services/dnsvizor/examples/stub-dns-resolver.nix
Enable DNSvizor as a dual-stack recursive DNS resolver
{ ... }: { services.dnsvizor = { enable = true; memory = 128; mainInterface = "enp1s0"; settings = { hostname = "dnsvizor.mydomain.example"; ipv4 = "10.0.0.2/24"; ipv4-gateway = "10.0.0.1"; ipv6 = "fdc9:281f:4d7:9ee9::2/64"; ipv6-gateway = "fdc9:281f:4d7:9ee9::1"; ca-seed = "Te9ffyY3Clcaz/4P7eFLyZQfLWIz/fSSK4NDb8THMDc="; password = "password"; dns-block = [ "block1.cli.example.com" "block2.cli.example.com" ]; dns-blocklist-url = [ "http://10.0.0.1/block-list-4" "http://[fdc9:281f:4d7:9ee9::1]:80/block-list-6" "https://example.com/non-existent-block-list" ]; qname-minimisation = true; opportunistic-tls-authoritative = true; }; openFirewall = true; }; }
Declared in: projects/DNSvizor/services/dnsvizor/examples/recursive-dns-resolver.nix
Metadata
This project is funded by NLnet through these subgrants:
- Entrust
- DNSvizor
Related links: