1 { config, lib, pkgs, ... }:
3 cfg = config.services.dnsmasq;
5 stateDir = "/var/lib/dnsmasq";
7 # True values are just put as `name` instead of `name=true`, and false values
8 # are turned to comments (false values are expected to be overrides e.g.
14 else if value == false
15 then "# setting `${name}` explicitly set to false"
16 else lib.generators.mkKeyValueDefault { } "=" name value;
18 settingsFormat = pkgs.formats.keyValue {
19 mkKeyValue = formatKeyValue;
20 listsAsDuplicateKeys = true;
23 dnsmasqConf = settingsFormat.generate "dnsmasq.conf" cfg.settings;
30 (lib.mkRenamedOptionModule [ "services" "dnsmasq" "servers" ] [ "services" "dnsmasq" "settings" "server" ])
31 (lib.mkRemovedOptionModule [ "services" "dnsmasq" "extraConfig" ] "This option has been replaced by `services.dnsmasq.settings`")
40 enable = lib.mkOption {
41 type = lib.types.bool;
44 Whether to run dnsmasq.
48 package = lib.mkPackageOption pkgs "dnsmasq" {};
50 resolveLocalQueries = lib.mkOption {
51 type = lib.types.bool;
54 Whether dnsmasq should resolve local queries (i.e. add 127.0.0.1 to
59 alwaysKeepRunning = lib.mkOption {
60 type = lib.types.bool;
63 If enabled, systemd will always respawn dnsmasq even if shut down manually. The default, disabled, will only restart it on error.
67 settings = lib.mkOption {
68 type = lib.types.submodule {
70 freeformType = settingsFormat.type;
72 options.server = lib.mkOption {
73 type = lib.types.listOf lib.types.str;
75 example = [ "8.8.8.8" "8.8.4.4" ];
77 The DNS servers which dnsmasq should query.
84 Configuration of dnsmasq. Lists get added one value per line (empty
85 lists and false values don't get added, though false values get
86 turned to comments). Gets merged with
89 dhcp-leasefile = "${stateDir}/dnsmasq.leases";
90 conf-file = optional cfg.resolveLocalQueries "/etc/dnsmasq-conf.conf";
91 resolv-file = optional cfg.resolveLocalQueries "/etc/dnsmasq-resolv.conf";
94 example = lib.literalExpression ''
97 dhcp-range = [ "192.168.0.2,192.168.0.254" ];
107 ###### implementation
109 config = lib.mkIf cfg.enable {
111 services.dnsmasq.settings = {
112 dhcp-leasefile = lib.mkDefault "${stateDir}/dnsmasq.leases";
113 conf-file = lib.mkDefault (lib.optional cfg.resolveLocalQueries "/etc/dnsmasq-conf.conf");
114 resolv-file = lib.mkDefault (lib.optional cfg.resolveLocalQueries "/etc/dnsmasq-resolv.conf");
117 networking.nameservers =
118 lib.optional cfg.resolveLocalQueries "127.0.0.1";
120 services.dbus.packages = [ dnsmasq ];
122 users.users.dnsmasq = {
125 description = "Dnsmasq daemon user";
127 users.groups.dnsmasq = {};
129 networking.resolvconf = lib.mkIf cfg.resolveLocalQueries {
130 useLocalResolver = lib.mkDefault true;
133 dnsmasq_conf=/etc/dnsmasq-conf.conf
134 dnsmasq_resolv=/etc/dnsmasq-resolv.conf
138 systemd.services.dnsmasq = {
139 description = "Dnsmasq Daemon";
140 after = [ "network.target" "systemd-resolved.service" ];
141 wantedBy = [ "multi-user.target" ];
144 mkdir -m 755 -p ${stateDir}
145 touch ${stateDir}/dnsmasq.leases
146 chown -R dnsmasq ${stateDir}
147 touch /etc/dnsmasq-{conf,resolv}.conf
152 BusName = "uk.org.thekelleys.dnsmasq";
153 ExecStart = "${dnsmasq}/bin/dnsmasq -k --enable-dbus --user=dnsmasq -C ${dnsmasqConf}";
154 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
156 ProtectSystem = true;
158 Restart = if cfg.alwaysKeepRunning then "always" else "on-failure";
160 restartTriggers = [ config.environment.etc.hosts.source ];
164 meta.doc = ./dnsmasq.md;