at 24.11-pre 6.4 kB view raw
1{ config, lib, pkgs, ... }: 2let 3 cfg = config.services.trust-dns; 4 toml = pkgs.formats.toml { }; 5 6 configFile = toml.generate "trust-dns.toml" ( 7 lib.filterAttrsRecursive (_: v: v != null) cfg.settings 8 ); 9 10 zoneType = lib.types.submodule ({ config, ... }: { 11 options = with lib; { 12 zone = mkOption { 13 type = types.str; 14 description = '' 15 Zone name, like "example.com", "localhost", or "0.0.127.in-addr.arpa". 16 ''; 17 }; 18 zone_type = mkOption { 19 type = types.enum [ "Primary" "Secondary" "Hint" "Forward" ]; 20 default = "Primary"; 21 description = '' 22 One of: 23 - "Primary" (the master, authority for the zone). 24 - "Secondary" (the slave, replicated from the primary). 25 - "Hint" (a cached zone with recursive resolver abilities). 26 - "Forward" (a cached zone where all requests are forwarded to another resolver). 27 28 For more details about these zone types, consult the documentation for BIND, 29 though note that trust-dns supports only a subset of BIND's zone types: 30 <https://bind9.readthedocs.io/en/v9_18_4/reference.html#type> 31 ''; 32 }; 33 file = mkOption { 34 type = types.either types.path types.str; 35 default = "${config.zone}.zone"; 36 defaultText = literalExpression ''"''${config.zone}.zone"''; 37 description = '' 38 Path to the .zone file. 39 If not fully-qualified, this path will be interpreted relative to the `directory` option. 40 If omitted, defaults to the value of the `zone` option suffixed with ".zone". 41 ''; 42 }; 43 }; 44 }); 45in 46{ 47 meta.maintainers = with lib.maintainers; [ colinsane ]; 48 options = { 49 services.trust-dns = with lib; { 50 enable = mkEnableOption "trust-dns"; 51 package = mkPackageOption pkgs "trust-dns" { 52 extraDescription = '' 53 ::: {.note} 54 The package must provide `meta.mainProgram` which names the server binary; any other utilities (client, resolver) are not needed. 55 ::: 56 ''; 57 }; 58 quiet = mkOption { 59 type = types.bool; 60 default = false; 61 description = '' 62 Log ERROR level messages only. 63 This option is mutually exclusive with the `debug` option. 64 If neither `quiet` nor `debug` are enabled, logging defaults to the INFO level. 65 ''; 66 }; 67 debug = mkOption { 68 type = types.bool; 69 default = false; 70 description = '' 71 Log DEBUG, INFO, WARN and ERROR messages. 72 This option is mutually exclusive with the `debug` option. 73 If neither `quiet` nor `debug` are enabled, logging defaults to the INFO level. 74 ''; 75 }; 76 settings = mkOption { 77 description = '' 78 Settings for trust-dns. The options enumerated here are not exhaustive. 79 Refer to upstream documentation for all available options: 80 - [Example settings](https://github.com/bluejekyll/trust-dns/blob/main/tests/test-data/test_configs/example.toml) 81 ''; 82 type = types.submodule { 83 freeformType = toml.type; 84 options = { 85 listen_addrs_ipv4 = mkOption { 86 type = types.listOf types.str; 87 default = [ "0.0.0.0" ]; 88 description = '' 89 List of ipv4 addresses on which to listen for DNS queries. 90 ''; 91 }; 92 listen_addrs_ipv6 = mkOption { 93 type = types.listOf types.str; 94 default = lib.optional config.networking.enableIPv6 "::0"; 95 defaultText = literalExpression ''lib.optional config.networking.enableIPv6 "::0"''; 96 description = '' 97 List of ipv6 addresses on which to listen for DNS queries. 98 ''; 99 }; 100 listen_port = mkOption { 101 type = types.port; 102 default = 53; 103 description = '' 104 Port to listen on (applies to all listen addresses). 105 ''; 106 }; 107 directory = mkOption { 108 type = types.str; 109 default = "/var/lib/trust-dns"; 110 description = '' 111 The directory in which trust-dns should look for .zone files, 112 whenever zones aren't specified by absolute path. 113 ''; 114 }; 115 zones = mkOption { 116 description = "List of zones to serve."; 117 default = []; 118 type = types.listOf (types.coercedTo types.str (zone: { inherit zone; }) zoneType); 119 }; 120 }; 121 }; 122 }; 123 }; 124 }; 125 126 config = lib.mkIf cfg.enable { 127 systemd.services.trust-dns = { 128 description = "trust-dns Domain Name Server"; 129 unitConfig.Documentation = "https://trust-dns.org/"; 130 serviceConfig = { 131 ExecStart = 132 let 133 flags = (lib.optional cfg.debug "--debug") ++ (lib.optional cfg.quiet "--quiet"); 134 flagsStr = builtins.concatStringsSep " " flags; 135 in '' 136 ${cfg.package}/bin/${cfg.package.meta.mainProgram} --config ${configFile} ${flagsStr} 137 ''; 138 Type = "simple"; 139 Restart = "on-failure"; 140 RestartSec = "10s"; 141 DynamicUser = true; 142 143 StateDirectory = "trust-dns"; 144 ReadWritePaths = [ cfg.settings.directory ]; 145 146 AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; 147 CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; 148 LockPersonality = true; 149 MemoryDenyWriteExecute = true; 150 NoNewPrivileges = true; 151 PrivateDevices = true; 152 PrivateMounts = true; 153 PrivateTmp = true; 154 ProtectClock = true; 155 ProtectControlGroups = true; 156 ProtectHome = true; 157 ProtectHostname = true; 158 ProtectKernelLogs = true; 159 ProtectKernelModules = true; 160 ProtectKernelTunables = true; 161 ProtectProc = "invisible"; 162 ProtectSystem = "full"; 163 RemoveIPC = true; 164 RestrictAddressFamilies = [ "AF_INET AF_INET6" ]; 165 RestrictNamespaces = true; 166 RestrictSUIDSGID = true; 167 SystemCallArchitectures = "native"; 168 SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ]; 169 }; 170 after = [ "network.target" ]; 171 wantedBy = [ "multi-user.target" ]; 172 }; 173 }; 174}