Merge pull request #78543 from Atemu/dnscrypt-proxy2-service

nixos/dnscrypt-proxy2: init
This commit is contained in:
worldofpeace 2020-02-02 23:02:06 -05:00 committed by GitHub
commit 74e4cb7ea4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 86 additions and 447 deletions

View File

@ -577,6 +577,13 @@ auth required pam_succeed_if.so uid >= 1000 quiet
as they aren't provided by upstream anymore.
</para>
</listitem>
<listitem>
<para>
The <option>services.dnscrypt-proxy</option> module has been removed
as it used the deprecated version of dnscrypt-proxy. We've added
<xref linkend="opt-services.dnscrypt-proxy2.enable"/> to use the supported version.
</para>
</listitem>
</itemizedlist>
</section>

View File

@ -591,7 +591,7 @@
./services/networking/dhcpd.nix
./services/networking/dnscache.nix
./services/networking/dnschain.nix
./services/networking/dnscrypt-proxy.nix
./services/networking/dnscrypt-proxy2.nix
./services/networking/dnscrypt-wrapper.nix
./services/networking/dnsdist.nix
./services/networking/dnsmasq.nix

View File

@ -41,6 +41,7 @@ with lib;
LightDM. Please use the services.xserver.displayManager.lightdm.autoLogin options
instead, or any other display manager in NixOS as they all support auto-login.
'')
(mkRemovedOptionModule [ "services" "dnscrypt-proxy" ] "Use services.dnscrypt-proxy2 instead")
# Do NOT add any option renames here, see top of the file
];

View File

@ -1,328 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.dnscrypt-proxy;
stateDirectory = "/var/lib/dnscrypt-proxy";
# The minisign public key used to sign the upstream resolver list.
# This is somewhat more flexible than preloading the key as an
# embedded string.
upstreamResolverListPubKey = pkgs.fetchurl {
url = https://raw.githubusercontent.com/dyne/dnscrypt-proxy/master/minisign.pub;
sha256 = "18lnp8qr6ghfc2sd46nn1rhcpr324fqlvgsp4zaigw396cd7vnnh";
};
# Internal flag indicating whether the upstream resolver list is used.
useUpstreamResolverList = cfg.customResolver == null;
# The final local address.
localAddress = "${cfg.localAddress}:${toString cfg.localPort}";
# The final resolvers list path.
resolverList = "${stateDirectory}/dnscrypt-resolvers.csv";
# Build daemon command line
resolverArgs =
if (cfg.customResolver == null)
then
[ "-L ${resolverList}"
"-R ${cfg.resolverName}"
]
else with cfg.customResolver;
[ "-N ${name}"
"-k ${key}"
"-r ${address}:${toString port}"
];
daemonArgs =
[ "-a ${localAddress}" ]
++ resolverArgs
++ cfg.extraArgs;
in
{
meta = {
maintainers = with maintainers; [ joachifm ];
doc = ./dnscrypt-proxy.xml;
};
options = {
# Before adding another option, consider whether it could
# equally well be passed via extraArgs.
services.dnscrypt-proxy = {
enable = mkOption {
default = false;
type = types.bool;
description = "Whether to enable the DNSCrypt client proxy";
};
localAddress = mkOption {
default = "127.0.0.1";
type = types.str;
description = ''
Listen for DNS queries to relay on this address. The only reason to
change this from its default value is to proxy queries on behalf
of other machines (typically on the local network).
'';
};
localPort = mkOption {
default = 53;
type = types.int;
description = ''
Listen for DNS queries to relay on this port. The default value
assumes that the DNSCrypt proxy should relay DNS queries directly.
When running as a forwarder for another DNS client, set this option
to a different value; otherwise leave the default.
'';
};
resolverName = mkOption {
default = "random";
example = "dnscrypt.eu-nl";
type = types.nullOr types.str;
description = ''
The name of the DNSCrypt resolver to use, taken from
<filename>${resolverList}</filename>. The default is to
pick a random non-logging resolver that supports DNSSEC.
'';
};
customResolver = mkOption {
default = null;
description = ''
Use an unlisted resolver (e.g., a private DNSCrypt provider). For
advanced users only. If specified, this option takes precedence.
'';
type = types.nullOr (types.submodule ({ ... }: { options = {
address = mkOption {
type = types.str;
description = "IP address";
example = "208.67.220.220";
};
port = mkOption {
type = types.int;
description = "Port";
default = 443;
};
name = mkOption {
type = types.str;
description = "Fully qualified domain name";
example = "2.dnscrypt-cert.example.com";
};
key = mkOption {
type = types.str;
description = "Public key";
example = "B735:1140:206F:225D:3E2B:D822:D7FD:691E:A1C3:3CC8:D666:8D0C:BE04:BFAB:CA43:FB79";
};
}; }));
};
extraArgs = mkOption {
default = [];
type = types.listOf types.str;
description = ''
Additional command-line arguments passed verbatim to the daemon.
See <citerefentry><refentrytitle>dnscrypt-proxy</refentrytitle>
<manvolnum>8</manvolnum></citerefentry> for details.
'';
example = [ "-X libdcplugin_example_cache.so,--min-ttl=60" ];
};
};
};
config = mkIf cfg.enable (mkMerge [{
assertions = [
{ assertion = (cfg.customResolver != null) || (cfg.resolverName != null);
message = "please configure upstream DNSCrypt resolver";
}
];
# make man 8 dnscrypt-proxy work
environment.systemPackages = [ pkgs.dnscrypt-proxy ];
users.users.dnscrypt-proxy = {
description = "dnscrypt-proxy daemon user";
isSystemUser = true;
group = "dnscrypt-proxy";
};
users.groups.dnscrypt-proxy = {};
systemd.sockets.dnscrypt-proxy = {
description = "dnscrypt-proxy listening socket";
documentation = [ "man:dnscrypt-proxy(8)" ];
wantedBy = [ "sockets.target" ];
socketConfig = {
ListenStream = localAddress;
ListenDatagram = localAddress;
};
};
systemd.services.dnscrypt-proxy = {
description = "dnscrypt-proxy daemon";
documentation = [ "man:dnscrypt-proxy(8)" ];
before = [ "nss-lookup.target" ];
after = [ "network.target" ];
requires = [ "dnscrypt-proxy.socket "];
serviceConfig = {
NonBlocking = "true";
ExecStart = "${pkgs.dnscrypt-proxy}/bin/dnscrypt-proxy ${toString daemonArgs}";
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
User = "dnscrypt-proxy";
PrivateTmp = true;
PrivateDevices = true;
ProtectHome = true;
};
};
}
(mkIf config.security.apparmor.enable {
systemd.services.dnscrypt-proxy.after = [ "apparmor.service" ];
security.apparmor.profiles = singleton (pkgs.writeText "apparmor-dnscrypt-proxy" ''
${pkgs.dnscrypt-proxy}/bin/dnscrypt-proxy {
/dev/null rw,
/dev/random r,
/dev/urandom r,
/etc/passwd r,
/etc/group r,
${config.environment.etc."nsswitch.conf".source} r,
${getLib pkgs.glibc}/lib/*.so mr,
${pkgs.tzdata}/share/zoneinfo/** r,
network inet stream,
network inet6 stream,
network inet dgram,
network inet6 dgram,
${getLib pkgs.dnscrypt-proxy}/lib/dnscrypt-proxy/libdcplugin*.so mr,
${getLib pkgs.gcc.cc}/lib/libssp.so.* mr,
${getLib pkgs.libsodium}/lib/libsodium.so.* mr,
${getLib pkgs.systemd}/lib/libsystemd.so.* mr,
${getLib pkgs.utillinuxMinimal.out}/lib/libmount.so.* mr,
${getLib pkgs.utillinuxMinimal.out}/lib/libblkid.so.* mr,
${getLib pkgs.utillinuxMinimal.out}/lib/libuuid.so.* mr,
${getLib pkgs.xz}/lib/liblzma.so.* mr,
${getLib pkgs.libgcrypt}/lib/libgcrypt.so.* mr,
${getLib pkgs.libgpgerror}/lib/libgpg-error.so.* mr,
${getLib pkgs.libcap}/lib/libcap.so.* mr,
${getLib pkgs.lz4}/lib/liblz4.so.* mr,
${getLib pkgs.attr}/lib/libattr.so.* mr, # */
${resolverList} r,
/run/systemd/notify rw,
}
'');
})
(mkIf useUpstreamResolverList {
systemd.services.init-dnscrypt-proxy-statedir = {
description = "Initialize dnscrypt-proxy state directory";
wantedBy = [ "dnscrypt-proxy.service" ];
before = [ "dnscrypt-proxy.service" ];
script = ''
mkdir -pv ${stateDirectory}
chown -c dnscrypt-proxy:dnscrypt-proxy ${stateDirectory}
cp -uv \
${pkgs.dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv \
${stateDirectory}
'';
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
};
systemd.services.update-dnscrypt-resolvers = {
description = "Update list of DNSCrypt resolvers";
requires = [ "init-dnscrypt-proxy-statedir.service" ];
after = [ "init-dnscrypt-proxy-statedir.service" ];
path = with pkgs; [ curl diffutils dnscrypt-proxy minisign ];
script = ''
cd ${stateDirectory}
domain=raw.githubusercontent.com
get="curl -fSs --resolve $domain:443:$(hostip -r 8.8.8.8 $domain | head -1)"
$get -o dnscrypt-resolvers.csv.tmp \
https://$domain/dyne/dnscrypt-proxy/master/dnscrypt-resolvers.csv
$get -o dnscrypt-resolvers.csv.minisig.tmp \
https://$domain/dyne/dnscrypt-proxy/master/dnscrypt-resolvers.csv.minisig
mv dnscrypt-resolvers.csv.minisig{.tmp,}
if ! minisign -q -V -p ${upstreamResolverListPubKey} \
-m dnscrypt-resolvers.csv.tmp -x dnscrypt-resolvers.csv.minisig ; then
echo "failed to verify resolver list!" >&2
exit 1
fi
[[ -f dnscrypt-resolvers.csv ]] && mv dnscrypt-resolvers.csv{,.old}
mv dnscrypt-resolvers.csv{.tmp,}
if cmp dnscrypt-resolvers.csv{,.old} ; then
echo "no change"
else
echo "resolver list updated"
fi
'';
serviceConfig = {
PrivateTmp = true;
PrivateDevices = true;
ProtectHome = true;
ProtectSystem = "strict";
ReadWritePaths = "${dirOf stateDirectory} ${stateDirectory}";
SystemCallFilter = "~@mount";
};
};
systemd.timers.update-dnscrypt-resolvers = {
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = "5min";
OnUnitActiveSec = "6h";
};
};
})
]);
imports = [
(mkRenamedOptionModule [ "services" "dnscrypt-proxy" "port" ] [ "services" "dnscrypt-proxy" "localPort" ])
(mkChangedOptionModule
[ "services" "dnscrypt-proxy" "tcpOnly" ]
[ "services" "dnscrypt-proxy" "extraArgs" ]
(config:
let val = getAttrFromPath [ "services" "dnscrypt-proxy" "tcpOnly" ] config; in
optional val "-T"))
(mkChangedOptionModule
[ "services" "dnscrypt-proxy" "ephemeralKeys" ]
[ "services" "dnscrypt-proxy" "extraArgs" ]
(config:
let val = getAttrFromPath [ "services" "dnscrypt-proxy" "ephemeralKeys" ] config; in
optional val "-E"))
(mkRemovedOptionModule [ "services" "dnscrypt-proxy" "resolverList" ] ''
The current resolver listing from upstream is always used
unless a custom resolver is specified.
'')
];
}

View File

@ -1,66 +0,0 @@
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="sec-dnscrypt-proxy">
<title>DNSCrypt client proxy</title>
<para>
The DNSCrypt client proxy relays DNS queries to a DNSCrypt enabled upstream
resolver. The traffic between the client and the upstream resolver is
encrypted and authenticated, mitigating the risk of MITM attacks, DNS
poisoning attacks, and third-party snooping (assuming the upstream is
trustworthy).
</para>
<sect1 xml:id="sec-dnscrypt-proxy-configuration">
<title>Basic configuration</title>
<para>
To enable the client proxy, set
<programlisting>
<xref linkend="opt-services.dnscrypt-proxy.enable"/> = true;
</programlisting>
</para>
<para>
Enabling the client proxy does not alter the system nameserver; to relay
local queries, prepend <literal>127.0.0.1</literal> to
<option>networking.nameservers</option>.
</para>
</sect1>
<sect1 xml:id="sec-dnscrypt-proxy-forwarder">
<title>As a forwarder for another DNS client</title>
<para>
To run the DNSCrypt proxy client as a forwarder for another DNS client,
change the default proxy listening port to a non-standard value and point
the other client to it:
<programlisting>
<xref linkend="opt-services.dnscrypt-proxy.localPort"/> = 43;
</programlisting>
</para>
<sect2 xml:id="sec-dnscrypt-proxy-forwarder-dsnmasq">
<title>dnsmasq</title>
<para>
<programlisting>
{
<xref linkend="opt-services.dnsmasq.enable"/> = true;
<xref linkend="opt-services.dnsmasq.servers"/> = [ "127.0.0.1#43" ];
}
</programlisting>
</para>
</sect2>
<sect2 xml:id="sec-dnscrypt-proxy-forwarder-unbound">
<title>unbound</title>
<para>
<programlisting>
{
<xref linkend="opt-services.unbound.enable"/> = true;
<xref linkend="opt-services.unbound.forwardAddresses"/> = [ "127.0.0.1@43" ];
}
</programlisting>
</para>
</sect2>
</sect1>
</chapter>

View File

@ -0,0 +1,61 @@
{ config, lib, pkgs, ... }: with lib;
let
cfg = config.services.dnscrypt-proxy2;
in
{
options.services.dnscrypt-proxy2 = {
enable = mkEnableOption "dnscrypt-proxy2";
settings = mkOption {
description = ''
Attrset that is converted and passed as TOML config file.
For available params, see: <link xlink:href="https://github.com/DNSCrypt/dnscrypt-proxy/blob/master/dnscrypt-proxy/example-dnscrypt-proxy.toml"/>
'';
example = literalExample ''
{
sources.public-resolvers = {
urls = [ "https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md" ];
cache_file = "public-resolvers.md";
minisign_key = "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3";
refresh_delay = 72;
};
}
'';
type = types.attrs;
default = {};
};
configFile = mkOption {
description = ''
Path to TOML config file. See: <link xlink:href="https://github.com/DNSCrypt/dnscrypt-proxy/blob/master/dnscrypt-proxy/example-dnscrypt-proxy.toml"/>
If this option is set, it will override any configuration done in options.services.dnscrypt-proxy2.settings.
'';
example = "/etc/dnscrypt-proxy/dnscrypt-proxy.toml";
type = types.path;
default = pkgs.runCommand "dnscrypt-proxy.toml" {
json = builtins.toJSON cfg.settings;
passAsFile = [ "json" ];
} ''
${pkgs.remarshal}/bin/json2toml < $jsonPath > $out
'';
defaultText = literalExample "TOML file generated from services.dnscrypt-proxy2.settings";
};
};
config = mkIf cfg.enable {
networking.nameservers = lib.mkDefault [ "127.0.0.1" ];
systemd.services.dnscrypt-proxy2 = {
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
DynamicUser = true;
ExecStart = "${pkgs.dnscrypt-proxy2}/bin/dnscrypt-proxy -config ${cfg.configFile}";
};
};
};
}

View File

@ -65,7 +65,7 @@ in
couchdb = handleTest ./couchdb.nix {};
deluge = handleTest ./deluge.nix {};
dhparams = handleTest ./dhparams.nix {};
dnscrypt-proxy = handleTestOn ["x86_64-linux"] ./dnscrypt-proxy.nix {};
dnscrypt-proxy2 = handleTestOn ["x86_64-linux"] ./dnscrypt-proxy2.nix {};
docker = handleTestOn ["x86_64-linux"] ./docker.nix {};
docker-containers = handleTestOn ["x86_64-linux"] ./docker-containers.nix {};
docker-edge = handleTestOn ["x86_64-linux"] ./docker-edge.nix {};

View File

@ -1,5 +1,5 @@
import ./make-test-python.nix ({ pkgs, ... }: {
name = "dnscrypt-proxy";
name = "dnscrypt-proxy2";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ joachifm ];
};
@ -13,9 +13,16 @@ import ./make-test-python.nix ({ pkgs, ... }: {
{
security.apparmor.enable = true;
services.dnscrypt-proxy.enable = true;
services.dnscrypt-proxy.localPort = localProxyPort;
services.dnscrypt-proxy.extraArgs = [ "-X libdcplugin_example.so" ];
services.dnscrypt-proxy2.enable = true;
services.dnscrypt-proxy2.settings = {
listen_addresses = [ "127.0.0.1:${toString localProxyPort}" ];
sources.public-resolvers = {
urls = [ "https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md" ];
cache_file = "public-resolvers.md";
minisign_key = "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3";
refresh_delay = 72;
};
};
services.dnsmasq.enable = true;
services.dnsmasq.servers = [ "127.0.0.1#${toString localProxyPort}" ];
@ -24,12 +31,6 @@ import ./make-test-python.nix ({ pkgs, ... }: {
testScript = ''
client.wait_for_unit("dnsmasq")
# The daemon is socket activated; sending a single ping should activate it.
client.fail("systemctl is-active dnscrypt-proxy")
client.execute(
"${pkgs.iputils}/bin/ping -c1 example.com"
)
client.wait_until_succeeds("systemctl is-active dnscrypt-proxy")
client.wait_for_unit("dnscrypt-proxy2")
'';
})

View File

@ -1,37 +0,0 @@
{ stdenv, fetchurl, pkgconfig, libsodium, ldns, openssl, systemd }:
with stdenv.lib;
stdenv.mkDerivation rec {
pname = "dnscrypt-proxy";
version = "1.9.5";
src = fetchurl {
url = "https://launchpad.net/ubuntu/+archive/primary/+files/${pname}-${version}.orig.tar.gz";
sha256 = "1dhvklr4dg2vlw108n11xbamacaryyg3dbrg629b76lp7685p7z8";
};
enableParallelBuilding = true;
configureFlags = optional stdenv.isLinux "--with-systemd";
nativeBuildInputs = [ pkgconfig ];
# <ldns/ldns.h> depends on <openssl/ssl.h>
buildInputs = [ libsodium openssl.dev ldns ] ++ 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://dnscrypt.info/;
license = licenses.isc;
maintainers = with maintainers; [ joachifm ];
# upstream claims OSX support, but Hydra fails
platforms = platforms.linux; # Maybe other non-darwin Unix
};
}

View File

@ -565,4 +565,6 @@ mapAliases ({
'';
oraclejre8psu = oraclejdk8psu;
oraclejdk8psu_distro = oraclejdk8psu;
dnscrypt-proxy = throw "dnscrypt-proxy has been removed. Please use dnscrypt-proxy2."; # added 2020-02-02
})

View File

@ -2772,9 +2772,7 @@ in
djbdns = callPackage ../tools/networking/djbdns { };
dnscrypt-proxy = callPackage ../tools/networking/dnscrypt-proxy/1.x { };
dnscrypt-proxy2 = callPackage ../tools/networking/dnscrypt-proxy/2.x { };
dnscrypt-proxy2 = callPackage ../tools/networking/dnscrypt-proxy2 { };
dnscrypt-wrapper = callPackage ../tools/networking/dnscrypt-wrapper { };