at 23.11-pre 5.3 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.dnsmasq; 7 dnsmasq = pkgs.dnsmasq; 8 stateDir = "/var/lib/dnsmasq"; 9 10 # True values are just put as `name` instead of `name=true`, and false values 11 # are turned to comments (false values are expected to be overrides e.g. 12 # mkForce) 13 formatKeyValue = 14 name: value: 15 if value == true 16 then name 17 else if value == false 18 then "# setting `${name}` explicitly set to false" 19 else generators.mkKeyValueDefault { } "=" name value; 20 21 settingsFormat = pkgs.formats.keyValue { 22 mkKeyValue = formatKeyValue; 23 listsAsDuplicateKeys = true; 24 }; 25 26 # Because formats.generate is outputting a file, we use of conf-file. Once 27 # `extraConfig` is deprecated we can just use 28 # `dnsmasqConf = format.generate "dnsmasq.conf" cfg.settings` 29 dnsmasqConf = pkgs.writeText "dnsmasq.conf" '' 30 conf-file=${settingsFormat.generate "dnsmasq.conf" cfg.settings} 31 ${cfg.extraConfig} 32 ''; 33 34in 35 36{ 37 38 imports = [ 39 (mkRenamedOptionModule [ "services" "dnsmasq" "servers" ] [ "services" "dnsmasq" "settings" "server" ]) 40 ]; 41 42 ###### interface 43 44 options = { 45 46 services.dnsmasq = { 47 48 enable = mkOption { 49 type = types.bool; 50 default = false; 51 description = lib.mdDoc '' 52 Whether to run dnsmasq. 53 ''; 54 }; 55 56 resolveLocalQueries = mkOption { 57 type = types.bool; 58 default = true; 59 description = lib.mdDoc '' 60 Whether dnsmasq should resolve local queries (i.e. add 127.0.0.1 to 61 /etc/resolv.conf). 62 ''; 63 }; 64 65 alwaysKeepRunning = mkOption { 66 type = types.bool; 67 default = false; 68 description = lib.mdDoc '' 69 If enabled, systemd will always respawn dnsmasq even if shut down manually. The default, disabled, will only restart it on error. 70 ''; 71 }; 72 73 settings = mkOption { 74 type = types.submodule { 75 76 freeformType = settingsFormat.type; 77 78 options.server = mkOption { 79 type = types.listOf types.str; 80 default = [ ]; 81 example = [ "8.8.8.8" "8.8.4.4" ]; 82 description = lib.mdDoc '' 83 The DNS servers which dnsmasq should query. 84 ''; 85 }; 86 87 }; 88 default = { }; 89 description = lib.mdDoc '' 90 Configuration of dnsmasq. Lists get added one value per line (empty 91 lists and false values don't get added, though false values get 92 turned to comments). Gets merged with 93 94 { 95 dhcp-leasefile = "${stateDir}/dnsmasq.leases"; 96 conf-file = optional cfg.resolveLocalQueries "/etc/dnsmasq-conf.conf"; 97 resolv-file = optional cfg.resolveLocalQueries "/etc/dnsmasq-resolv.conf"; 98 } 99 ''; 100 example = literalExpression '' 101 { 102 domain-needed = true; 103 dhcp-range = [ "192.168.0.2,192.168.0.254" ]; 104 } 105 ''; 106 }; 107 108 extraConfig = mkOption { 109 type = types.lines; 110 default = ""; 111 description = lib.mdDoc '' 112 Extra configuration directives that should be added to 113 `dnsmasq.conf`. 114 115 This option is deprecated, please use {option}`settings` instead. 116 ''; 117 }; 118 119 }; 120 121 }; 122 123 124 ###### implementation 125 126 config = mkIf cfg.enable { 127 128 warnings = lib.optional (cfg.extraConfig != "") "Text based config is deprecated, dnsmasq now supports `services.dnsmasq.settings` for an attribute-set based config"; 129 130 services.dnsmasq.settings = { 131 dhcp-leasefile = mkDefault "${stateDir}/dnsmasq.leases"; 132 conf-file = mkDefault (optional cfg.resolveLocalQueries "/etc/dnsmasq-conf.conf"); 133 resolv-file = mkDefault (optional cfg.resolveLocalQueries "/etc/dnsmasq-resolv.conf"); 134 }; 135 136 networking.nameservers = 137 optional cfg.resolveLocalQueries "127.0.0.1"; 138 139 services.dbus.packages = [ dnsmasq ]; 140 141 users.users.dnsmasq = { 142 isSystemUser = true; 143 group = "dnsmasq"; 144 description = "Dnsmasq daemon user"; 145 }; 146 users.groups.dnsmasq = {}; 147 148 networking.resolvconf = mkIf cfg.resolveLocalQueries { 149 useLocalResolver = mkDefault true; 150 151 extraConfig = '' 152 dnsmasq_conf=/etc/dnsmasq-conf.conf 153 dnsmasq_resolv=/etc/dnsmasq-resolv.conf 154 ''; 155 }; 156 157 systemd.services.dnsmasq = { 158 description = "Dnsmasq Daemon"; 159 after = [ "network.target" "systemd-resolved.service" ]; 160 wantedBy = [ "multi-user.target" ]; 161 path = [ dnsmasq ]; 162 preStart = '' 163 mkdir -m 755 -p ${stateDir} 164 touch ${stateDir}/dnsmasq.leases 165 chown -R dnsmasq ${stateDir} 166 touch /etc/dnsmasq-{conf,resolv}.conf 167 dnsmasq --test 168 ''; 169 serviceConfig = { 170 Type = "dbus"; 171 BusName = "uk.org.thekelleys.dnsmasq"; 172 ExecStart = "${dnsmasq}/bin/dnsmasq -k --enable-dbus --user=dnsmasq -C ${dnsmasqConf}"; 173 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; 174 PrivateTmp = true; 175 ProtectSystem = true; 176 ProtectHome = true; 177 Restart = if cfg.alwaysKeepRunning then "always" else "on-failure"; 178 }; 179 restartTriggers = [ config.environment.etc.hosts.source ]; 180 }; 181 }; 182}