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