From 749f4be1ef9b115c97fa717cc6068ab342c7650c Mon Sep 17 00:00:00 2001
From: Alan Pearce
Date: Tue, 12 Nov 2019 19:30:35 +0100
Subject: Configure nextdns usage via module
---
system/modules/darwin/kresd.nix | 45 ++++++
system/modules/darwin/stubby.nix | 218 +++++++++++++++++++++++++++
system/modules/nextdns.nix | 92 +++++++++++
system/settings/base.nix | 12 +-
system/settings/hardware/network-manager.nix | 8 -
system/settings/services/kresd.nix | 22 ---
system/trillian.nix | 13 +-
7 files changed, 375 insertions(+), 35 deletions(-)
create mode 100644 system/modules/darwin/kresd.nix
create mode 100644 system/modules/darwin/stubby.nix
create mode 100644 system/modules/nextdns.nix
delete mode 100644 system/settings/services/kresd.nix
diff --git a/system/modules/darwin/kresd.nix b/system/modules/darwin/kresd.nix
new file mode 100644
index 00000000..6bce8af1
--- /dev/null
+++ b/system/modules/darwin/kresd.nix
@@ -0,0 +1,45 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.kresd;
+ package = pkgs.knot-resolver;
+
+ configFile = pkgs.writeText "kresd.conf" cfg.extraConfig;
+in
+{
+ options = {
+ services.kresd.enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = "Whether to enable knot-resolver daemon.";
+ };
+
+ services.kresd.extraConfig = mkOption {
+ type = types.lines;
+ default = "";
+ description = ''
+ Extra configuration to be added to the generated configuration file.
+ '';
+ };
+ };
+
+ config = mkIf cfg.enable {
+ launchd.daemons.kresd = {
+ command = "${package}/bin/kresd -c ${configFile}";
+
+ serviceConfig = {
+ ProcessType = "Interactive";
+ # Sockets = {
+ # Listeners = {
+ # SockServiceName = "dns";
+ # SockFamily = "IPv4";
+ # };
+ # };
+ };
+ };
+
+ environment.systemPackages = [ package ];
+ };
+}
diff --git a/system/modules/darwin/stubby.nix b/system/modules/darwin/stubby.nix
new file mode 100644
index 00000000..b3b67755
--- /dev/null
+++ b/system/modules/darwin/stubby.nix
@@ -0,0 +1,218 @@
+{ config, lib, pkgs, ...}:
+
+with lib;
+
+let
+ cfg = config.services.stubby;
+ package = pkgs.stubby;
+
+ fallbacks = concatMapStringsSep "\n " (x: "- ${x}") cfg.fallbackProtocols;
+ listeners = concatMapStringsSep "\n " (x: "- ${x}") cfg.listenAddresses;
+
+ # By default, the recursive resolvers maintained by the getdns
+ # project itself are enabled. More information about both getdns's servers,
+ # as well as third party options for upstream resolvers, can be found here:
+ # https://dnsprivacy.org/wiki/display/DP/DNS+Privacy+Test+Servers
+ #
+ # You can override these values by supplying a yaml-formatted array of your
+ # preferred upstream resolvers in the following format:
+ #
+ # 106 # - address_data: IPv4 or IPv6 address of the upstream
+ # port: Port for UDP/TCP (default is 53)
+ # tls_auth_name: Authentication domain name checked against the server
+ # certificate
+ # tls_pubkey_pinset: An SPKI pinset verified against the keys in the server
+ # certificate
+ # - digest: Only "sha256" is currently supported
+ # value: Base64 encoded value of the sha256 fingerprint of the public
+ # key
+ # tls_port: Port for TLS (default is 853)
+
+ defaultUpstream = ''
+ - address_data: 145.100.185.15
+ tls_auth_name: "dnsovertls.sinodun.com"
+ tls_pubkey_pinset:
+ - digest: "sha256"
+ value: 62lKu9HsDVbyiPenApnc4sfmSYTHOVfFgL3pyB+cBL4=
+ - address_data: 145.100.185.16
+ tls_auth_name: "dnsovertls1.sinodun.com"
+ tls_pubkey_pinset:
+ - digest: "sha256"
+ value: cE2ecALeE5B+urJhDrJlVFmf38cJLAvqekONvjvpqUA=
+ - address_data: 185.49.141.37
+ tls_auth_name: "getdnsapi.net"
+ tls_pubkey_pinset:
+ - digest: "sha256"
+ value: foxZRnIh9gZpWnl+zEiKa0EJ2rdCGroMWm02gaxSc9Q=
+ - address_data: 2001:610:1:40ba:145:100:185:15
+ tls_auth_name: "dnsovertls.sinodun.com"
+ tls_pubkey_pinset:
+ - digest: "sha256"
+ value: 62lKu9HsDVbyiPenApnc4sfmSYTHOVfFgL3pyB+cBL4=
+ - address_data: 2001:610:1:40ba:145:100:185:16
+ tls_auth_name: "dnsovertls1.sinodun.com"
+ tls_pubkey_pinset:
+ - digest: "sha256"
+ value: cE2ecALeE5B+urJhDrJlVFmf38cJLAvqekONvjvpqUA=
+ - address_data: 2a04:b900:0:100::38
+ tls_auth_name: "getdnsapi.net"
+ tls_pubkey_pinset:
+ - digest: "sha256"
+ value: foxZRnIh9gZpWnl+zEiKa0EJ2rdCGroMWm02gaxSc9Q=
+ '';
+
+ # Resolution type is not changeable here because it is required per the
+ # stubby documentation:
+ #
+ # "resolution_type: Work in stub mode only (not recursive mode) - required for Stubby
+ # operation."
+ #
+ # https://dnsprivacy.org/wiki/display/DP/Configuring+Stubby
+
+ confFile = pkgs.writeText "stubby.yml" ''
+ resolution_type: GETDNS_RESOLUTION_STUB
+ dns_transport_list:
+ ${fallbacks}
+ tls_authentication: ${cfg.authenticationMode}
+ tls_query_padding_blocksize: ${toString cfg.queryPaddingBlocksize}
+ edns_client_subnet_private: ${if cfg.subnetPrivate then "1" else "0"}
+ idle_timeout: ${toString cfg.idleTimeout}
+ listen_addresses:
+ ${listeners}
+ round_robin_upstreams: ${if cfg.roundRobinUpstreams then "1" else "0"}
+ ${cfg.extraConfig}
+ upstream_recursive_servers:
+ ${cfg.upstreamServers}
+ '';
+in
+
+{
+ options = {
+ services.stubby = {
+
+ enable = mkEnableOption "Stubby DNS resolver";
+
+ fallbackProtocols = mkOption {
+ default = [ "GETDNS_TRANSPORT_TLS" ];
+ type = with types; listOf (enum [
+ "GETDNS_TRANSPORT_TLS"
+ "GETDNS_TRANSPORT_TCP"
+ "GETDNS_TRANSPORT_UDP"
+ ]);
+ description = ''
+ Ordered list composed of one or more transport protocols.
+ Strict mode should only use GETDNS_TRANSPORT_TLS.
+ Other options are GETDNS_TRANSPORT_UDP and
+ GETDNS_TRANSPORT_TCP.
+ '';
+ };
+
+ authenticationMode = mkOption {
+ default = "GETDNS_AUTHENTICATION_REQUIRED";
+ type = types.enum [
+ "GETDNS_AUTHENTICATION_REQUIRED"
+ "GETDNS_AUTHENTICATION_NONE"
+ ];
+ description = ''
+ Selects the Strict or Opportunistic usage profile.
+ For strict, set to GETDNS_AUTHENTICATION_REQUIRED.
+ for opportunistic, use GETDNS_AUTHENTICATION_NONE.
+ '';
+ };
+
+ queryPaddingBlocksize = mkOption {
+ default = 128;
+ type = types.int;
+ description = ''
+ EDNS0 option to pad the size of the DNS query to the given blocksize.
+ '';
+ };
+
+ subnetPrivate = mkOption {
+ default = true;
+ type = types.bool;
+ description = ''
+ EDNS0 option for ECS client privacy. Default is
+ true. If set, this option prevents the client
+ subnet from being sent to authoritative nameservers.
+ '';
+ };
+
+ idleTimeout = mkOption {
+ default = 10000;
+ type = types.int;
+ description = "EDNS0 option for keepalive idle timeout expressed in
+ milliseconds.";
+ };
+
+ listenAddresses = mkOption {
+ default = [ "127.0.0.1" "0::1" ];
+ type = with types; listOf str;
+ description = ''
+ Sets the listen address for the stubby daemon.
+ Uses port 53 by default.
+ Ise IP@port to specify a different port.
+ '';
+ };
+
+ roundRobinUpstreams = mkOption {
+ default = true;
+ type = types.bool;
+ description = ''
+ Instructs stubby to distribute queries across all available name
+ servers. Default is true. Set to
+ false in order to use the first available.
+ '';
+ };
+
+ upstreamServers = mkOption {
+ default = defaultUpstream;
+ type = types.lines;
+ description = ''
+ Replace default upstreams. See stubby
+ 1 for an
+ example of the entry formatting. In Strict mode, at least one of the
+ following settings must be supplied for each nameserver:
+ tls_auth_name or
+ tls_pubkey_pinset.
+ '';
+ };
+
+ debugLogging = mkOption {
+ default = false;
+ type = types.bool;
+ description = "Enable or disable debug level logging.";
+ };
+
+ extraConfig = mkOption {
+ default = "";
+ type = types.lines;
+ description = ''
+ Add additional configuration options. see
+ stubby1
+ for more options.
+ '';
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ launchd.daemons.stubby = {
+ command = "${package}/bin/stubby -C ${confFile} ${optionalString cfg.debugLogging "-l"}";
+
+ serviceConfig = {
+ ProcessType = "Interactive";
+ RunAtLoad = true;
+ KeepAlive = true;
+ # Sockets = {
+ # Listeners = {
+ # SockServiceName = "dns";
+ # SockFamily = "IPv4";
+ # };
+ # };
+ };
+ };
+
+ environment.systemPackages = [ package ];
+ };
+}
diff --git a/system/modules/nextdns.nix b/system/modules/nextdns.nix
new file mode 100644
index 00000000..6de4acdb
--- /dev/null
+++ b/system/modules/nextdns.nix
@@ -0,0 +1,92 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ inherit (pkgs) stdenv;
+
+ cfg = config.networking.nextdns;
+
+ identifyingPrefix = if cfg.identifyDevice then "${config.networking.hostName}-" else "";
+in
+{
+ options = {
+ networking.nextdns.enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = "Whether to enable DNS resolution via NextDNS";
+ };
+
+ networking.nextdns.configID = mkOption {
+ type = types.str;
+ default = "";
+ example = literalExample "abcdef";
+ description = "NextDNS configuration ID";
+ };
+
+ networking.nextdns.identifyDevice = mkOption {
+ type = types.bool;
+ default = false;
+ description = "Whether to send hostname for identifying in your logs";
+ };
+
+ networking.nextdns.resolver = mkOption {
+ type = types.enum [ "kresd" "stubby" ];
+ default = if stdenv.isDarwin then "stubby" else "kresd";
+ description = "Resolver to use";
+ };
+ };
+
+ config = mkIf cfg.enable {
+
+ assertions = [
+ {
+ assertion = !(stdenv.isDarwin && cfg.resolver == "kresd");
+ message = "kresd is not supported on Darwin";
+ }
+ ];
+ networking = if stdenv.isDarwin then
+ {
+ dns = [
+ "::1"
+ "127.0.0.1"
+ "2a07:a8c0::ab:d6e5"
+ "2a07:a8c1::ab:d6e5"
+ "45.90.28.25"
+ "45.90.30.25"
+ ];
+ } else {
+ networking.networkmanager.dns = "none";
+ resolvconf.useLocalResolver = true;
+ };
+ services = if cfg.resolver == "kresd" then {
+ kresd = {
+ enable = true;
+ extraConfig = ''
+ policy.add(policy.all(policy.TLS_FORWARD({
+ {'45.90.28.0', hostname='${identifyingPrefix}${cfg.configID}.dns1.nextdns.io'},
+ {'2a07:a8c0::', hostname='${identifyingPrefix}${cfg.configID}.dns1.nextdns.io'},
+ {'45.90.30.0', hostname='${identifyingPrefix}${cfg.configID}.dns2.nextdns.io'},
+ {'2a07:a8c1::', hostname='${identifyingPrefix}${cfg.configID}.dns2.nextdns.io'}
+ })))
+ '';
+ };
+ } else if cfg.resolver == "stubby" then {
+ stubby = {
+ enable = cfg.resolver == "stubby";
+ fallbackProtocols = lib.mkDefault [ "GETDNS_TRANSPORT_TLS" ];
+ roundRobinUpstreams = lib.mkDefault false;
+ upstreamServers = ''
+ - address_data: 45.90.28.0
+ tls_auth_name: "${identifyingPrefix}${cfg.configID}.dns1.nextdns.io"
+ - address_data: 2a07:a8c0::0
+ tls_auth_name: "${identifyingPrefix}${cfg.configID}.dns1.nextdns.io"
+ - address_data: 45.90.30.0
+ tls_auth_name: "${identifyingPrefix}${cfg.configID}.dns2.nextdns.io"
+ - address_data: 2a07:a8c1::0
+ tls_auth_name: "${identifyingPrefix}${cfg.configID}.dns2.nextdns.io"
+ '';
+ };
+ } else abort "Cannot configure resolver ${cfg.resolver}";
+ };
+}
diff --git a/system/settings/base.nix b/system/settings/base.nix
index 9e94a5a2..8f0c32b2 100644
--- a/system/settings/base.nix
+++ b/system/settings/base.nix
@@ -1,11 +1,21 @@
{ config, pkgs, ... }:
-{ boot.loader.timeout = 1;
+{
+ imports = [
+ ../modules/nextdns.nix
+ ];
+ boot.loader.timeout = 1;
environment.systemPackages = with pkgs; [
nix-index
];
+ networking.nextdns = {
+ enable = true;
+ configID = "abd6e5";
+ identifyDevice = true;
+ };
+
networking.extraHosts = ''
127.0.0.1 ${config.networking.hostName}
::1 ${config.networking.hostName}
diff --git a/system/settings/hardware/network-manager.nix b/system/settings/hardware/network-manager.nix
index 4daea7be..6ab0c818 100644
--- a/system/settings/hardware/network-manager.nix
+++ b/system/settings/hardware/network-manager.nix
@@ -1,17 +1,9 @@
{ config, lib, pkgs, ... }:
{
- imports = [
- ../services/kresd.nix
- ];
-
networking = {
networkmanager = {
enable = true;
- dns = lib.mkForce "none";
- };
- resolvconf = {
- useLocalResolver = true;
};
};
diff --git a/system/settings/services/kresd.nix b/system/settings/services/kresd.nix
deleted file mode 100644
index 335d96cc..00000000
--- a/system/settings/services/kresd.nix
+++ /dev/null
@@ -1,22 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-let
- nextdnsConfig = "abd6e5";
- hostname = config.networking.hostName;
-in
-{
- services.kresd = {
- enable = true;
- extraConfig = ''
- cache.size = 100*MB
- cache.min_ttl(3 * 3600)
-
- policy.add(policy.all(policy.TLS_FORWARD({
- {'45.90.28.0', hostname='${hostname}-${nextdnsConfig}.dns1.nextdns.io'},
- {'2a07:a8c0::', hostname='${hostname}-${nextdnsConfig}.dns1.nextdns.io'},
- {'45.90.30.0', hostname='${hostname}-${nextdnsConfig}.dns2.nextdns.io'},
- {'2a07:a8c1::', hostname='${hostname}-${nextdnsConfig}.dns2.nextdns.io'}
- })))
- '';
- };
-}
diff --git a/system/trillian.nix b/system/trillian.nix
index 21245fe8..276a2559 100644
--- a/system/trillian.nix
+++ b/system/trillian.nix
@@ -4,6 +4,9 @@
imports = [
./private/default.nix
+ ./modules/darwin/stubby.nix
+ ./modules/nextdns.nix
+
./settings/programs/accounting.nix
./settings/programs/shell.nix
];
@@ -15,10 +18,12 @@
networking = {
hostName = "trillian";
knownNetworkServices = [ "Wi-Fi" "USB 10/100/1000 LAN" ];
- dns = [
- "::1"
- "127.0.0.1"
- ];
+ nextdns = {
+ enable = true;
+ resolver = "stubby";
+ configID = "abd6e5";
+ identifyDevice = true;
+ };
};
# Use a custom configuration.nix location.
--
cgit 1.4.1