lol

nixos: Add option networking.networkmanager.dynamicHosts

This allows non-privileged users to configure local DNS
entries by editing hosts files read by NetworkManager's dnsmasq
instance.

Cherry-picked from e6c3d5a507909c4e0c0a5013040684cce89c35ce and
5a566004a2b12c3d91bf0acdb704f1b40770c28f.

+82 -5
+82 -5
nixos/modules/services/networking/networkmanager.nix
··· 6 6 let 7 7 cfg = config.networking.networkmanager; 8 8 9 + dynamicHostsEnabled = 10 + cfg.dynamicHosts.enable && cfg.dynamicHosts.hostsDirs != {}; 11 + 9 12 # /var/lib/misc is for dnsmasq.leases. 10 13 stateDirs = "/var/lib/NetworkManager /var/lib/dhclient /var/lib/misc"; 11 14 ··· 317 320 so you don't need to to that yourself. 318 321 ''; 319 322 }; 323 + 324 + dynamicHosts = { 325 + enable = mkOption { 326 + type = types.bool; 327 + default = false; 328 + description = '' 329 + Enabling this option requires the 330 + <option>networking.networkmanager.dns</option> option to be 331 + set to <literal>dnsmasq</literal>. If enabled, the directories 332 + defined by the 333 + <option>networking.networkmanager.dynamicHosts.hostsDirs</option> 334 + option will be set up when the service starts. The dnsmasq instance 335 + managed by NetworkManager will then watch those directories for 336 + hosts files (see the <literal>--hostsdir</literal> option of 337 + dnsmasq). This way a non-privileged user can add or override DNS 338 + entries on the local system (depending on what hosts directories 339 + that are configured).. 340 + ''; 341 + }; 342 + hostsDirs = mkOption { 343 + type = with types; attrsOf (submodule { 344 + options = { 345 + user = mkOption { 346 + type = types.str; 347 + default = "root"; 348 + description = '' 349 + The user that will own the hosts directory. 350 + ''; 351 + }; 352 + group = mkOption { 353 + type = types.str; 354 + default = "root"; 355 + description = '' 356 + The group that will own the hosts directory. 357 + ''; 358 + }; 359 + }; 360 + }); 361 + default = {}; 362 + description = '' 363 + Defines a set of directories (relative to 364 + <literal>/run/NetworkManager/hostdirs</literal>) that dnsmasq will 365 + watch for hosts files. 366 + ''; 367 + }; 368 + }; 320 369 }; 321 370 }; 322 371 ··· 325 374 326 375 config = mkIf cfg.enable { 327 376 328 - assertions = [{ 329 - assertion = config.networking.wireless.enable == false; 330 - message = "You can not use networking.networkmanager with networking.wireless"; 331 - }]; 377 + assertions = [ 378 + { assertion = config.networking.wireless.enable == false; 379 + message = "You can not use networking.networkmanager with networking.wireless"; 380 + } 381 + { assertion = !dynamicHostsEnabled || (dynamicHostsEnabled && cfg.dns == "dnsmasq"); 382 + message = '' 383 + To use networking.networkmanager.dynamicHosts you also need to set 384 + networking.networkmanager.dns = "dnsmasq" 385 + ''; 386 + } 387 + ]; 332 388 333 389 environment.etc = with cfg.basePackages; [ 334 390 { source = configFile; ··· 362 418 ++ lib.imap1 (i: s: { 363 419 inherit (s) source; 364 420 target = "NetworkManager/dispatcher.d/${dispatcherTypesSubdirMap.${s.type}}03userscript${lib.fixedWidthNumber 4 i}"; 365 - }) cfg.dispatcherScripts; 421 + }) cfg.dispatcherScripts 422 + ++ optional (dynamicHostsEnabled) 423 + { target = "NetworkManager/dnsmasq.d/dyndns.conf"; 424 + text = concatMapStrings (n: '' 425 + hostsdir=/run/NetworkManager/hostsdirs/${n} 426 + '') (attrNames cfg.dynamicHosts.hostsDirs); 427 + }; 366 428 367 429 environment.systemPackages = cfg.packages; 368 430 ··· 396 458 mkdir -m 700 -p /etc/ipsec.d 397 459 mkdir -m 755 -p ${stateDirs} 398 460 ''; 461 + }; 462 + 463 + systemd.services.nm-setup-hostsdirs = mkIf dynamicHostsEnabled { 464 + wantedBy = [ "network-manager.service" ]; 465 + before = [ "network-manager.service" ]; 466 + partOf = [ "network-manager.service" ]; 467 + script = concatStrings (mapAttrsToList (n: d: '' 468 + mkdir -p "/run/NetworkManager/hostsdirs/${n}" 469 + chown "${d.user}:${d.group}" "/run/NetworkManager/hostsdirs/${n}" 470 + chmod 0775 "/run/NetworkManager/hostsdirs/${n}" 471 + '') cfg.dynamicHosts.hostsDirs); 472 + serviceConfig = { 473 + Type = "oneshot"; 474 + RemainAfterExist = true; 475 + }; 399 476 }; 400 477 401 478 # Turn off NixOS' network management