{ config, pkgs, ... }: { assertions = [{ assertion = config.networking.networkmanager.enable; message = ''This module is only tested with NetworkManager''; } { assertion = ! config.services.resolved.enable; message = ''This module is incompatible with resolved as resolved does not listen to IPv6 loopback''; } { assertion = config.networking.enableIPv6; message = ''This module assumes that IPv6 networking is available''; }]; # Encrypted, anonymized DNS queries. # # NixOS networking options: # https://nixos.wiki/wiki/Encrypted_DNS#Setting_nameservers # Exmaple dnscrypt-proxy config: # https://github.com/DNSCrypt/dnscrypt-proxy/blob/master/dnscrypt-proxy/example-dnscrypt-proxy.toml # NixOS config examples: # https://nixos.wiki/wiki/Encrypted_DNS#dnscrypt-proxy2 # https://github.com/LudovicoPiero/dotfiles/blob/338b0585d195e6644df9bf8b63fd574af7c18e26/cells/workstations/nixosProfiles/dnscrypt2/default.nix # # Check if service is running # systemctl status dnscrypt-proxy2.service # # Check if it is working # https://wiki.archlinux.org/title/Dnscrypt-proxy#Check_if_dnscrypt-proxy_is_working # # View generated config file: # cat "$(systemctl show -P FragmentPath dnscrypt-proxy2.service)" | grep 'ExecStart=' # cat ....toml # Example: Running c in a container and routhing dnscrypt-proxy queries through it # https://github.com/AtaraxiaSjel/nixos-config/blob/3510d178bafeb5d742806d25d5c6c34570c498e8/profiles/workspace/proxy.nix # TODO # create new config option # encrypted-dns # If enabled # use dnscrypt # don't use adguard and ffmuc DNS servers # Firefox use system DNS networking.nameservers = [ # IPv4 "127.0.0.1" # IPv6 "::1" ]; #networking.nameservers = [ # # https://www.kuketz-blog.de/empfehlungsecke/#dns # # unfiltered.adguard-dns.com (supports DNSSEC) # "94.140.14.140" "94.140.14.141" # # https://www.kuketz-blog.de/empfehlungsecke/#dns # # dot.ffmuc.net (supports DNSSEC) # "5.1.66.255" "185.150.99.255" #]; # If using dhcpcd. networking.dhcpcd.extraConfig = "nohook resolv.conf"; # If using NetworkManager. networking.networkmanager.dns = "none"; systemd.services.dnscrypt-proxy2.serviceConfig = { StateDirectory = "dnscrypt-proxy"; }; services.dnscrypt-proxy2 = { enable = true; settings = { #listen_addresses = ['127.0.0.1:53']; # Enable a DNS cache to reduce latency and outgoing traffic cache = true; # Dont alter the TTL of cached entries # https://github.com/DNSCrypt/dnscrypt-proxy/issues/1552#issuecomment-750021306 cache_min_ttl = 0; # DNSCrypt: Create a new, unique key for every single DNS query. # This may improve privacy but can also have a significant impact on CPU usage. # Only enable if you don't have a lot of network load. #dnscrypt_ephemeral_keys = false # The cipher suite can't be changed for TLS 1.3 connections, see # https://github.com/dnscrypt/dnscrypt-proxy/wiki/Performance#cipher-suites-doh # https://github.com/DNSCrypt/dnscrypt-proxy/issues/2359#issuecomment-1488501839 #tls_cipher_suite = ... bootstrap_resolvers = [ # # Local DNS servers # # DNS server of Fritz!Box guest WiFi "192.168.179.1:53" # # Public DNS servers # # https://www.kuketz-blog.de/empfehlungsecke/#dns # dot.ffmuc.net (supports DNSSEC) "5.1.66.255:53" "185.150.99.255:53" # https://www.kuketz-blog.de/empfehlungsecke/#dns # unfiltered.adguard-dns.com (supports DNSSEC) "94.140.14.140:853" "94.140.14.141:853" "9.9.9.11:53" # Quad9 "1.1.1.1:53" # Cloudflare "8.8.8.8:53" # Google ]; # Use servers reachable over IPv4. ipv4_servers = true; # Use servers reachable over IPv6. # Do not enable if you don't have IPv6 connectivity. ipv6_servers = true; block_ipv6 = false; # Use servers implementing the DNSCrypt protocol. dnscrypt_servers = true; # Use servers implementing the DNS-over-HTTPS protocol. doh_servers = false; # Use servers implementing the Oblivious DoH protocol odoh_servers = false; # Server must support DNS security extensions (DNSSEC). require_dnssec = true; # Server must not log user queries (declarative). require_nolog = true; # Server must not enforce its own blacklist (for parental control, ads blocking...). require_nofilter = true; # Fetch list of dnscrypt server names. # These server names are used below in the `server_names` and `via` options. sources = { public-resolvers = { urls = [ "https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md" ]; cache_file = "/var/lib/dnscrypt-proxy2/public-resolvers.md"; minisign_key = "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3"; }; relays = { urls = [ "https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/relays.md" ]; cache_file = "/var/lib/dnscrypt-proxy2/relays.md"; minisign_key = "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3"; }; }; # Names of servers to be used for DNS queries. # These are not contacted directly. # Instead, the queries are forwarded by relay servers. server_names = [ # Operated by https://cryptostorm.is/ "cs-berlin" "cs-de" "cs-dus1" "cs-dus2" "cs-dus3" "cs-dus4" # Other operators. "dns.digitale-gesellschaft.ch" "dns.digitale-gesellschaft.ch-ipv6" "dct-de" "dct-nl" "dns.digitalsize.net" "dns.digitalsize.net-ipv6" "ibksturm" # Switzerland "doh-ibksturm" # Switzerland "faelix-ch-ipv4" # Switzerland # Already used as relay server. #"dnswarden-uncensor-dc-swiss" # Switzerland # DNS servers that filter some requests. #"switch" # Filters requests #"dnsforge.de" # Filters requests #"brahma-world" # Filters requests #"brahma-world-ipv6" # Filters requests #"libredns" # No DNSSEC ]; anonymized_dns = { routes = [ { # All DNS servers given in `server_names`. server_name = "*"; # Relay servers. # These forward requests to the chosen DNS servers. via = [ "anon-digitalprivacy.diy-ipv4" # Germany, by https://digitalprivacy.diy "anon-serbica" # Netherlands, by https://litepay.ch "anon-kama" # France, by Frank Denis (@jedisct1) "anon-scaleway" # France, by Frank Denis (@jedisct1) "anon-scaleway2" # France, by Frank Denis (@jedisct1) "anon-fluffycat-fr-01" # France "anon-dnswarden-swiss" # Already used as DNS server. #"anon-cs-berlin" #"anon-cs-de" #"anon-cs-dus1" # Germany #"anon-cs-dus2" # Germany #"anon-cs-dus3" # Germany #"anon-cs-dus4" # Germany #"anon-cs-fr" #"anon-cs-dk" #"anon-cs-belgium" #"anon-cs-nl" #"anon-cs-nl2" #"anon-cs-poland" #"anon-cs-czech" #"anon-cs-austria" ]; } ]; # Skip resolvers incompatible with anonymization instead of using them directly. skip_incompatible = true; }; # As this dict is converted to JSON, we can't use `proxy = lib.mkIf (...) "socks5://127.0.0.1:9050"` inside it - it won't be evaluated. # Instead, we merge it with another dict below: } // ( # On some networks dnscrypt-proxy can't resove DNS queries. # # Example: Fritz!Box Guest WiFi # https://docs.pi-hole.net/routers/fritzbox/ # The Fritz!Box always sets its own IP as DNS server for the guest network. # # Solution: Proxy dnscrypt-proxy through Tor # - Currently, we have this enabled. # - The latency of DNS queries is higher than without Tor - at about 130ms. if config.services.tor.torsocks.enable then { # Route all TCP connections to a local Tor node. # As Tor doesn't support UDP, `force_tcp` has to be set to `true`. proxy = "socks5://127.0.0.1:9050"; # This can be useful if you need to route everything through Tor. # Otherwise, leave this to `false`. force_tcp = true; } else {} ); }; }