nixos/tests/dnscrypt-wrapper: test TCP and run on port 443
- Test both TCP and UDP queries (tinydns → bind) - Test IPv6 by default - Run DNSCrypt on port 443 along with HTTPS
This commit is contained in:
parent
61202fc867
commit
7f71262745
1 changed files with 109 additions and 35 deletions
|
@ -1,5 +1,15 @@
|
||||||
|
|
||||||
{ lib, pkgs, ... }:
|
{ 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";
|
name = "dnscrypt-wrapper";
|
||||||
meta = with pkgs.lib.maintainers; {
|
meta = with pkgs.lib.maintainers; {
|
||||||
|
@ -7,59 +17,122 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
nodes = {
|
nodes = {
|
||||||
server = { lib, ... }:
|
server = {
|
||||||
{ services.dnscrypt-wrapper = with builtins;
|
networking.hosts = hosts;
|
||||||
|
networking.interfaces.eth1.ipv6.addresses = lib.singleton
|
||||||
|
{ address = "fd::a"; prefixLength = 64; };
|
||||||
|
|
||||||
|
services.dnscrypt-wrapper =
|
||||||
{ enable = true;
|
{ enable = true;
|
||||||
address = "192.168.1.1";
|
address = "[::]";
|
||||||
|
port = 5353;
|
||||||
keys.expiration = 5; # days
|
keys.expiration = 5; # days
|
||||||
keys.checkInterval = 2; # min
|
keys.checkInterval = 2; # min
|
||||||
# The keypair was generated by the command:
|
# The keypair was generated by the command:
|
||||||
# dnscrypt-wrapper --gen-provider-keypair \
|
# dnscrypt-wrapper --gen-provider-keypair \
|
||||||
# --provider-name=2.dnscrypt-cert.server \
|
# --provider-name=2.dnscrypt-cert.server \
|
||||||
# --ext-address=192.168.1.1:5353
|
providerKey.public = "${./public.key}";
|
||||||
providerKey.public = toFile "public.key" (readFile ./public.key);
|
providerKey.secret = "${./secret.key}";
|
||||||
providerKey.secret = toFile "secret.key" (readFile ./secret.key);
|
|
||||||
};
|
|
||||||
services.tinydns.enable = true;
|
|
||||||
services.tinydns.data = ''
|
|
||||||
..:192.168.1.1:a
|
|
||||||
+it.works:1.2.3.4
|
|
||||||
'';
|
|
||||||
networking.firewall.allowedUDPPorts = [ 5353 ];
|
|
||||||
networking.firewall.allowedTCPPorts = [ 5353 ];
|
|
||||||
networking.interfaces.eth1.ipv4.addresses = lib.mkForce
|
|
||||||
[ { address = "192.168.1.1"; prefixLength = 24; } ];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
client = { lib, ... }:
|
# nameserver
|
||||||
{ services.dnscrypt-proxy2.enable = true;
|
services.bind.enable = true;
|
||||||
services.dnscrypt-proxy2.upstreamDefaults = false;
|
services.bind.zones = lib.singleton
|
||||||
services.dnscrypt-proxy2.settings = {
|
{ name = ".";
|
||||||
server_names = [ "server" ];
|
master = true;
|
||||||
static.server.stamp = "sdns://AQAAAAAAAAAAEDE5Mi4xNjguMS4xOjUzNTMgFEHYOv0SCKSuqR5CDYa7-58cCBuXO2_5uTSVU9wNQF0WMi5kbnNjcnlwdC1jZXJ0LnNlcnZlcg";
|
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
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
networking.nameservers = [ "127.0.0.1" ];
|
|
||||||
networking.interfaces.eth1.ipv4.addresses = lib.mkForce
|
# webserver
|
||||||
[ { address = "192.168.1.2"; prefixLength = 24; } ];
|
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 = ''
|
testScript = ''
|
||||||
start_all()
|
|
||||||
|
|
||||||
with subtest("The server can generate the ephemeral keypair"):
|
with subtest("The server can generate the ephemeral keypair"):
|
||||||
server.wait_for_unit("dnscrypt-wrapper")
|
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.key")
|
||||||
server.wait_for_file("/var/lib/dnscrypt-wrapper/2.dnscrypt-cert.server.crt")
|
server.wait_for_file("/var/lib/dnscrypt-wrapper/2.dnscrypt-cert.server.crt")
|
||||||
almost_expiration = server.succeed("date --date '4days 23 hours 56min'").strip()
|
almost_expiration = server.succeed("date --date '4days 23 hours 56min'").strip()
|
||||||
|
|
||||||
with subtest("The client can connect to the server"):
|
with subtest("The DNSCrypt client can connect to the server"):
|
||||||
server.wait_for_unit("tinydns")
|
server.wait_for_unit("sslh")
|
||||||
client.wait_for_unit("dnscrypt-proxy2")
|
client.wait_until_succeeds("journalctl -u dnscrypt-proxy2 --grep '\[server\] OK'")
|
||||||
assert "1.2.3.4" in client.wait_until_succeeds(
|
|
||||||
"host it.works"
|
with subtest("HTTP client can connect to the server"):
|
||||||
), "The IP address of 'it.works' does not match 1.2.3.4"
|
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"):
|
with subtest("The server rotates the ephemeral keys"):
|
||||||
# advance time by a little less than 5 days
|
# advance time by a little less than 5 days
|
||||||
|
@ -68,7 +141,8 @@
|
||||||
server.wait_for_file("/var/lib/dnscrypt-wrapper/oldkeys")
|
server.wait_for_file("/var/lib/dnscrypt-wrapper/oldkeys")
|
||||||
|
|
||||||
with subtest("The client can still connect to the server"):
|
with subtest("The client can still connect to the server"):
|
||||||
server.wait_for_unit("dnscrypt-wrapper")
|
client.systemctl("restart dnscrypt-proxy2")
|
||||||
client.succeed("host it.works")
|
client.wait_until_succeeds("host -T example.org")
|
||||||
|
client.wait_until_succeeds("host -U example.org")
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue