dnscrypt-wrapper: remove package and NixOS modules

This commit is contained in:
rnhmjoj 2024-09-14 15:36:12 +02:00
parent 2e1c8b3883
commit 016f6f9f58
No known key found for this signature in database
GPG key ID: BFBAF4C975F76450
11 changed files with 10 additions and 461 deletions

View file

@ -356,6 +356,9 @@
- `zx` was updated to v8, which introduces several breaking changes. - `zx` was updated to v8, which introduces several breaking changes.
See the [v8 changelog](https://github.com/google/zx/releases/tag/8.0.0) for more information. See the [v8 changelog](https://github.com/google/zx/releases/tag/8.0.0) for more information.
- The `dnscrypt-wrapper` module was removed since the project has been effectively unmaintained since 2018; moreover the NixOS module had to rely on an abandoned version of dnscrypt-proxy v1 for the rotation of keys.
To wrap a resolver with DNSCrypt you can instead use `dnsdist`. See options `services.dnsdist.dnscrypt.*`
- The `portunus` package and service do not support weak password hashes anymore. - The `portunus` package and service do not support weak password hashes anymore.
If you installed Portunus on NixOS 23.11 or earlier, upgrade to NixOS 24.05 first to get support for strong password hashing. If you installed Portunus on NixOS 23.11 or earlier, upgrade to NixOS 24.05 first to get support for strong password hashing.
Then, follow the instructions on the [upstream release notes](https://github.com/majewsky/portunus/releases/tag/v2.0.0) to upgrade all existing user accounts to strong password hashes. Then, follow the instructions on the [upstream release notes](https://github.com/majewsky/portunus/releases/tag/v2.0.0) to upgrade all existing user accounts to strong password hashes.

View file

@ -1014,7 +1014,6 @@
./services/networking/dhcpcd.nix ./services/networking/dhcpcd.nix
./services/networking/dnscache.nix ./services/networking/dnscache.nix
./services/networking/dnscrypt-proxy2.nix ./services/networking/dnscrypt-proxy2.nix
./services/networking/dnscrypt-wrapper.nix
./services/networking/dnsdist.nix ./services/networking/dnsdist.nix
./services/networking/dnsmasq.nix ./services/networking/dnsmasq.nix
./services/networking/dnsproxy.nix ./services/networking/dnsproxy.nix

View file

@ -61,6 +61,12 @@ in
(mkRemovedOptionModule [ "services" "couchpotato" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "couchpotato" ] "The corresponding package was removed from nixpkgs.")
(mkRemovedOptionModule [ "services" "dd-agent" ] "dd-agent was removed from nixpkgs in favor of the newer datadog-agent.") (mkRemovedOptionModule [ "services" "dd-agent" ] "dd-agent was removed from nixpkgs in favor of the newer datadog-agent.")
(mkRemovedOptionModule [ "services" "dnscrypt-proxy" ] "Use services.dnscrypt-proxy2 instead") (mkRemovedOptionModule [ "services" "dnscrypt-proxy" ] "Use services.dnscrypt-proxy2 instead")
(mkRemovedOptionModule [ "services" "dnscrypt-wrapper" ] ''
The dnscrypt-wrapper module was removed since the project has been effectively unmaintained since 2018;
moreover the NixOS module had to rely on an abandoned version of dnscrypt-proxy v1 for the rotation of keys.
To wrap a resolver with DNSCrypt you can instead use dnsdist. See options `services.dnsdist.dnscrypt.*`
'')
(mkRemovedOptionModule [ "services" "exhibitor" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "exhibitor" ] "The corresponding package was removed from nixpkgs.")
(mkRemovedOptionModule [ "services" "firefox" "syncserver" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "firefox" "syncserver" ] "The corresponding package was removed from nixpkgs.")
(mkRemovedOptionModule [ "services" "flashpolicyd" ] "The flashpolicyd module has been removed. Adobe Flash Player is deprecated.") (mkRemovedOptionModule [ "services" "flashpolicyd" ] "The flashpolicyd module has been removed. Adobe Flash Player is deprecated.")

View file

@ -1,273 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.dnscrypt-wrapper;
dataDir = "/var/lib/dnscrypt-wrapper";
mkPath = path: default:
if path != null
then toString path
else default;
publicKey = mkPath cfg.providerKey.public "${dataDir}/public.key";
secretKey = mkPath cfg.providerKey.secret "${dataDir}/secret.key";
daemonArgs = with cfg; [
"--listen-address=${address}:${toString port}"
"--resolver-address=${upstream.address}:${toString upstream.port}"
"--provider-name=${providerName}"
"--provider-publickey-file=${publicKey}"
"--provider-secretkey-file=${secretKey}"
"--provider-cert-file=${providerName}.crt"
"--crypt-secretkey-file=${providerName}.key"
];
genKeys = ''
# generates time-limited keypairs
keyGen() {
dnscrypt-wrapper --gen-crypt-keypair \
--crypt-secretkey-file=${cfg.providerName}.key
dnscrypt-wrapper --gen-cert-file \
--crypt-secretkey-file=${cfg.providerName}.key \
--provider-cert-file=${cfg.providerName}.crt \
--provider-publickey-file=${publicKey} \
--provider-secretkey-file=${secretKey} \
--cert-file-expire-days=${toString cfg.keys.expiration}
}
cd ${dataDir}
# generate provider keypair (first run only)
${lib.optionalString (cfg.providerKey.public == null || cfg.providerKey.secret == null) ''
if [ ! -f ${publicKey} ] || [ ! -f ${secretKey} ]; then
dnscrypt-wrapper --gen-provider-keypair
fi
''}
# generate new keys for rotation
if [ ! -f ${cfg.providerName}.key ] || [ ! -f ${cfg.providerName}.crt ]; then
keyGen
fi
'';
rotateKeys = ''
# check if keys are not expired
keyValid() {
fingerprint=$(dnscrypt-wrapper \
--show-provider-publickey \
--provider-publickey-file=${publicKey} \
| awk '{print $(NF)}')
dnscrypt-proxy --test=${toString (cfg.keys.checkInterval + 1)} \
--resolver-address=127.0.0.1:${toString cfg.port} \
--provider-name=${cfg.providerName} \
--provider-key=$fingerprint
}
cd ${dataDir}
# archive old keys and restart the service
if ! keyValid; then
echo "certificate soon to become invalid; backing up old cert"
mkdir -p oldkeys
mv -v "${cfg.providerName}.key" "oldkeys/${cfg.providerName}-$(date +%F-%T).key"
mv -v "${cfg.providerName}.crt" "oldkeys/${cfg.providerName}-$(date +%F-%T).crt"
kill "$(pidof -s dnscrypt-wrapper)"
fi
'';
# This is the fork of the original dnscrypt-proxy maintained by Dyne.org.
# dnscrypt-proxy2 doesn't provide the `--test` feature that is needed to
# correctly implement key rotation of dnscrypt-wrapper ephemeral keys.
dnscrypt-proxy1 = pkgs.callPackage
({ stdenv, fetchFromGitHub, autoreconfHook
, pkg-config, libsodium, ldns, openssl, systemd }:
stdenv.mkDerivation rec {
pname = "dnscrypt-proxy";
version = "2019-08-20";
src = fetchFromGitHub {
owner = "dyne";
repo = "dnscrypt-proxy";
rev = "07ac3825b5069adc28e2547c16b1d983a8ed8d80";
sha256 = "0c4mq741q4rpmdn09agwmxap32kf0vgfz7pkhcdc5h54chc3g3xy";
};
configureFlags = lib.optional stdenv.isLinux "--with-systemd";
nativeBuildInputs = [ autoreconfHook pkg-config ];
# <ldns/ldns.h> depends on <openssl/ssl.h>
buildInputs = [ libsodium openssl.dev ldns ] ++ lib.optional stdenv.isLinux systemd;
postInstall = ''
# Previous versions required libtool files to load plugins; they are
# now strictly optional.
rm $out/lib/dnscrypt-proxy/*.la
'';
meta = {
description = "A tool for securing communications between a client and a DNS resolver";
homepage = "https://github.com/dyne/dnscrypt-proxy";
license = lib.licenses.isc;
maintainers = with lib.maintainers; [ rnhmjoj ];
platforms = lib.platforms.linux;
};
}) { };
in {
###### interface
options.services.dnscrypt-wrapper = {
enable = lib.mkEnableOption "DNSCrypt wrapper";
address = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1";
description = ''
The DNSCrypt wrapper will bind to this IP address.
'';
};
port = lib.mkOption {
type = lib.types.port;
default = 5353;
description = ''
The DNSCrypt wrapper will listen for DNS queries on this port.
'';
};
providerName = lib.mkOption {
type = lib.types.str;
default = "2.dnscrypt-cert.${config.networking.hostName}";
defaultText = lib.literalExpression ''"2.dnscrypt-cert.''${config.networking.hostName}"'';
example = "2.dnscrypt-cert.myresolver";
description = ''
The name that will be given to this DNSCrypt resolver.
Note: the resolver name must start with `2.dnscrypt-cert.`.
'';
};
providerKey.public = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
example = "/etc/secrets/public.key";
description = ''
The filepath to the provider public key. If not given a new
provider key pair will be generated on the first run.
'';
};
providerKey.secret = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
example = "/etc/secrets/secret.key";
description = ''
The filepath to the provider secret key. If not given a new
provider key pair will be generated on the first run.
'';
};
upstream.address = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1";
description = ''
The IP address of the upstream DNS server DNSCrypt will "wrap".
'';
};
upstream.port = lib.mkOption {
type = lib.types.port;
default = 53;
description = ''
The port of the upstream DNS server DNSCrypt will "wrap".
'';
};
keys.expiration = lib.mkOption {
type = lib.types.int;
default = 30;
description = ''
The duration (in days) of the time-limited secret key.
This will be automatically rotated before expiration.
'';
};
keys.checkInterval = lib.mkOption {
type = lib.types.int;
default = 1440;
description = ''
The time interval (in minutes) between key expiration checks.
'';
};
};
###### implementation
config = lib.mkIf cfg.enable {
users.users.dnscrypt-wrapper = {
description = "dnscrypt-wrapper daemon user";
home = "${dataDir}";
createHome = true;
isSystemUser = true;
group = "dnscrypt-wrapper";
};
users.groups.dnscrypt-wrapper = { };
systemd.services.dnscrypt-wrapper = {
description = "dnscrypt-wrapper daemon";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
path = [ pkgs.dnscrypt-wrapper ];
serviceConfig = {
User = "dnscrypt-wrapper";
WorkingDirectory = dataDir;
Restart = "always";
ExecStart = "${pkgs.dnscrypt-wrapper}/bin/dnscrypt-wrapper ${toString daemonArgs}";
};
preStart = genKeys;
};
systemd.services.dnscrypt-wrapper-rotate = {
after = [ "network.target" ];
requires = [ "dnscrypt-wrapper.service" ];
description = "Rotates DNSCrypt wrapper keys if soon to expire";
path = with pkgs; [ dnscrypt-wrapper dnscrypt-proxy1 gawk procps ];
script = rotateKeys;
serviceConfig.User = "dnscrypt-wrapper";
};
systemd.timers.dnscrypt-wrapper-rotate = {
description = "Periodically check DNSCrypt wrapper keys for expiration";
wantedBy = [ "multi-user.target" ];
timerConfig = {
Unit = "dnscrypt-wrapper-rotate.service";
OnBootSec = "1min";
OnUnitActiveSec = cfg.keys.checkInterval * 60;
};
};
assertions = with cfg; [
{ assertion = (providerKey.public == null && providerKey.secret == null) ||
(providerKey.secret != null && providerKey.public != null);
message = "The secret and public provider key must be set together.";
}
];
};
meta.maintainers = with lib.maintainers; [ rnhmjoj ];
}

View file

@ -260,7 +260,6 @@ in {
disable-installer-tools = handleTest ./disable-installer-tools.nix {}; disable-installer-tools = handleTest ./disable-installer-tools.nix {};
discourse = handleTest ./discourse.nix {}; discourse = handleTest ./discourse.nix {};
dnscrypt-proxy2 = handleTestOn ["x86_64-linux"] ./dnscrypt-proxy2.nix {}; dnscrypt-proxy2 = handleTestOn ["x86_64-linux"] ./dnscrypt-proxy2.nix {};
dnscrypt-wrapper = runTestOn ["x86_64-linux"] ./dnscrypt-wrapper;
dnsdist = import ./dnsdist.nix { inherit pkgs runTest; }; dnsdist = import ./dnsdist.nix { inherit pkgs runTest; };
doas = handleTest ./doas.nix {}; doas = handleTest ./doas.nix {};
docker = handleTestOn ["aarch64-linux" "x86_64-linux"] ./docker.nix {}; docker = handleTestOn ["aarch64-linux" "x86_64-linux"] ./docker.nix {};

View file

@ -1,148 +0,0 @@
{ lib, pkgs, ... }:
let
snakeoil = import ../common/acme/server/snakeoil-certs.nix;
hosts = lib.mkForce
{ "fd::a" = [ "server" snakeoil.domain ];
"fd::b" = [ "client" ];
};
in
{
name = "dnscrypt-wrapper";
meta = with pkgs.lib.maintainers; {
maintainers = [ rnhmjoj ];
};
nodes = {
server = {
networking.hosts = hosts;
networking.interfaces.eth1.ipv6.addresses = lib.singleton
{ address = "fd::a"; prefixLength = 64; };
services.dnscrypt-wrapper =
{ enable = true;
address = "[::]";
port = 5353;
keys.expiration = 5; # days
keys.checkInterval = 2; # min
# The keypair was generated by the command:
# dnscrypt-wrapper --gen-provider-keypair \
# --provider-name=2.dnscrypt-cert.server \
providerKey.public = "${./public.key}";
providerKey.secret = "${./secret.key}";
};
# nameserver
services.bind.enable = true;
services.bind.zones = lib.singleton
{ name = ".";
master = true;
file = pkgs.writeText "root.zone" ''
$TTL 3600
. IN SOA example.org. admin.example.org. ( 1 3h 1h 1w 1d )
. IN NS example.org.
example.org. IN AAAA 2001:db8::1
'';
};
# webserver
services.nginx.enable = true;
services.nginx.virtualHosts.${snakeoil.domain} =
{ onlySSL = true;
listenAddresses = [ "localhost" ];
sslCertificate = snakeoil.${snakeoil.domain}.cert;
sslCertificateKey = snakeoil.${snakeoil.domain}.key;
locations."/ip".extraConfig = ''
default_type text/plain;
return 200 "Ciao $remote_addr!\n";
'';
};
# demultiplex HTTP and DNS from port 443
services.sslh =
{ enable = true;
method = "ev";
settings.transparent = true;
settings.listen = lib.mkForce
[ { host = "server"; port = "443"; is_udp = false; }
{ host = "server"; port = "443"; is_udp = true; }
];
settings.protocols =
[ # Send TLS to webserver (TCP)
{ name = "tls"; host= "localhost"; port= "443"; }
# Send DNSCrypt to dnscrypt-wrapper (TCP or UDP)
{ name = "anyprot"; host = "localhost"; port = "5353"; }
{ name = "anyprot"; host = "localhost"; port = "5353"; is_udp = true;}
];
};
networking.firewall.allowedTCPPorts = [ 443 ];
networking.firewall.allowedUDPPorts = [ 443 ];
};
client = {
networking.hosts = hosts;
networking.interfaces.eth1.ipv6.addresses = lib.singleton
{ address = "fd::b"; prefixLength = 64; };
services.dnscrypt-proxy2.enable = true;
services.dnscrypt-proxy2.upstreamDefaults = false;
services.dnscrypt-proxy2.settings =
{ server_names = [ "server" ];
listen_addresses = [ "[::1]:53" ];
cache = false;
# Computed using https://dnscrypt.info/stamps/
static.server.stamp =
"sdns://AQAAAAAAAAAADzE5Mi4xNjguMS4yOjQ0MyAUQdg6"
+"_RIIpK6pHkINhrv7nxwIG5c7b_m5NJVT3A1AXRYyLmRuc2NyeXB0LWNlcnQuc2VydmVy";
};
networking.nameservers = [ "::1" ];
security.pki.certificateFiles = [ snakeoil.ca.cert ];
};
};
testScript = ''
with subtest("The server can generate the ephemeral keypair"):
server.wait_for_unit("dnscrypt-wrapper")
server.wait_for_file("/var/lib/dnscrypt-wrapper/2.dnscrypt-cert.server.key")
server.wait_for_file("/var/lib/dnscrypt-wrapper/2.dnscrypt-cert.server.crt")
almost_expiration = server.succeed("date --date '4days 23 hours 56min'").strip()
with subtest("The DNSCrypt client can connect to the server"):
server.wait_for_unit("sslh")
client.wait_until_succeeds("journalctl -u dnscrypt-proxy2 --grep '\[server\] OK'")
with subtest("HTTP client can connect to the server"):
server.wait_for_unit("nginx")
client.succeed("curl -s --fail https://${snakeoil.domain}/ip | grep -q fd::b")
with subtest("DNS queries over UDP are working"):
server.wait_for_unit("bind")
client.wait_for_open_port(53)
assert "2001:db8::1" in client.wait_until_succeeds(
"host -U example.org"
), "The IP address of 'example.org' does not match 2001:db8::1"
with subtest("DNS queries over TCP are working"):
server.wait_for_unit("bind")
client.wait_for_open_port(53)
assert "2001:db8::1" in client.wait_until_succeeds(
"host -T example.org"
), "The IP address of 'example.org' does not match 2001:db8::1"
with subtest("The server rotates the ephemeral keys"):
# advance time by a little less than 5 days
server.succeed(f"date -s '{almost_expiration}'")
client.succeed(f"date -s '{almost_expiration}'")
server.wait_for_file("/var/lib/dnscrypt-wrapper/oldkeys")
with subtest("The client can still connect to the server"):
client.systemctl("restart dnscrypt-proxy2")
client.wait_until_succeeds("host -T example.org")
client.wait_until_succeeds("host -U example.org")
'';
}

View file

@ -1 +0,0 @@
A<>:<3A><08><><EFBFBD>B <0A><><EFBFBD><EFBFBD><1B>;o<><6F>4<EFBFBD>S<EFBFBD> @]

View file

@ -1 +0,0 @@
G½>ֶ©» ל>׀א¥(ׂ²‡¼J•«÷=<3D><EFBFBD>ֱ<EFBFBD>A״:₪®©B †»<E280A0><C2BB>—;oש¹4•S<E280A2> @]

View file

@ -1,34 +0,0 @@
{ lib, stdenv, fetchFromGitHub, autoreconfHook, pkg-config, libsodium, libevent, nixosTests }:
stdenv.mkDerivation rec {
pname = "dnscrypt-wrapper";
version = "0.4.2";
src = fetchFromGitHub {
owner = "Cofyc";
repo = "dnscrypt-wrapper";
rev = "v${version}";
sha256 = "055vxpcfg80b1456p6p0p236pwykknph9x3c9psg8ya3i8qqywkl";
};
enableParallelBuilding = true;
# causes `dnscrypt-wrapper --gen-provider-keypair` to crash
hardeningDisable = [ "fortify3" ];
nativeBuildInputs = [ pkg-config autoreconfHook ];
buildInputs = [ libsodium libevent ];
passthru.tests = {
inherit (nixosTests) dnscrypt-wrapper;
};
meta = with lib; {
description = "Tool for adding dnscrypt support to any name resolver";
homepage = "https://dnscrypt.info/";
license = licenses.isc;
maintainers = with maintainers; [ joachifm ];
platforms = platforms.linux;
mainProgram = "dnscrypt-wrapper";
};
}

View file

@ -335,6 +335,7 @@ mapAliases ({
dhcp = throw "dhcp (ISC DHCP) has been removed from nixpkgs, because it reached its end of life"; # Added 2023-04-04 dhcp = throw "dhcp (ISC DHCP) has been removed from nixpkgs, because it reached its end of life"; # Added 2023-04-04
dibbler = throw "dibbler was removed because it is not maintained anymore"; # Added 2024-05-14 dibbler = throw "dibbler was removed because it is not maintained anymore"; # Added 2024-05-14
dnnl = oneDNN; # Added 2020-04-22 dnnl = oneDNN; # Added 2020-04-22
dnscrypt-wrapper = throw "dnscrypt-wrapper was removed because it has been effectively unmaintained since 2018. Use DNSCcrypt support in dnsdist instead"; # Added 2024-09-14
docker-compose_1 = throw "'docker-compose_1' has been removed because it has been unmaintained since May 2021. Use docker-compose instead."; # Added 2024-07-29 docker-compose_1 = throw "'docker-compose_1' has been removed because it has been unmaintained since May 2021. Use docker-compose instead."; # Added 2024-07-29
docker-distribution = distribution; # Added 2023-12-26 docker-distribution = distribution; # Added 2023-12-26
docker-machine = throw "'docker-machine' has been removed, because the upstream project was archived"; # Added 2023-12-27 docker-machine = throw "'docker-machine' has been removed, because the upstream project was archived"; # Added 2023-12-27

View file

@ -7032,8 +7032,6 @@ with pkgs;
dnscrypt-proxy = callPackage ../tools/networking/dnscrypt-proxy { }; dnscrypt-proxy = callPackage ../tools/networking/dnscrypt-proxy { };
dnscrypt-wrapper = callPackage ../tools/networking/dnscrypt-wrapper { };
dnscontrol = callPackage ../applications/networking/dnscontrol { }; dnscontrol = callPackage ../applications/networking/dnscontrol { };
dnsenum = callPackage ../tools/security/dnsenum { }; dnsenum = callPackage ../tools/security/dnsenum { };