diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix
index cdc3a352590..b0bc1c83d6b 100644
--- a/nixos/modules/services/networking/networkmanager.nix
+++ b/nixos/modules/services/networking/networkmanager.nix
@@ -6,6 +6,9 @@ with lib;
let
cfg = config.networking.networkmanager;
+ dynamicHostsEnabled =
+ cfg.dynamicHosts.enable && cfg.dynamicHosts.hostsDirs != {};
+
# /var/lib/misc is for dnsmasq.leases.
stateDirs = "/var/lib/NetworkManager /var/lib/dhclient /var/lib/misc";
@@ -317,6 +320,52 @@ in {
so you don't need to to that yourself.
'';
};
+
+ dynamicHosts = {
+ enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Enabling this option requires the
+ option to be
+ set to dnsmasq. If enabled, the directories
+ defined by the
+
+ option will be set up when the service starts. The dnsmasq instance
+ managed by NetworkManager will then watch those directories for
+ hosts files (see the --hostsdir option of
+ dnsmasq). This way a non-privileged user can add or override DNS
+ entries on the local system (depending on what hosts directories
+ that are configured)..
+ '';
+ };
+ hostsDirs = mkOption {
+ type = with types; attrsOf (submodule {
+ options = {
+ user = mkOption {
+ type = types.str;
+ default = "root";
+ description = ''
+ The user that will own the hosts directory.
+ '';
+ };
+ group = mkOption {
+ type = types.str;
+ default = "root";
+ description = ''
+ The group that will own the hosts directory.
+ '';
+ };
+ };
+ });
+ default = {};
+ description = ''
+ Defines a set of directories (relative to
+ /run/NetworkManager/hostdirs) that dnsmasq will
+ watch for hosts files.
+ '';
+ };
+ };
};
};
@@ -325,10 +374,17 @@ in {
config = mkIf cfg.enable {
- assertions = [{
- assertion = config.networking.wireless.enable == false;
- message = "You can not use networking.networkmanager with networking.wireless";
- }];
+ assertions = [
+ { assertion = config.networking.wireless.enable == false;
+ message = "You can not use networking.networkmanager with networking.wireless";
+ }
+ { assertion = !dynamicHostsEnabled || (dynamicHostsEnabled && cfg.dns == "dnsmasq");
+ message = ''
+ To use networking.networkmanager.dynamicHosts you also need to set
+ networking.networkmanager.dns = "dnsmasq"
+ '';
+ }
+ ];
environment.etc = with cfg.basePackages; [
{ source = configFile;
@@ -362,7 +418,13 @@ in {
++ lib.imap1 (i: s: {
inherit (s) source;
target = "NetworkManager/dispatcher.d/${dispatcherTypesSubdirMap.${s.type}}03userscript${lib.fixedWidthNumber 4 i}";
- }) cfg.dispatcherScripts;
+ }) cfg.dispatcherScripts
+ ++ optional (dynamicHostsEnabled)
+ { target = "NetworkManager/dnsmasq.d/dyndns.conf";
+ text = concatMapStrings (n: ''
+ hostsdir=/run/NetworkManager/hostsdirs/${n}
+ '') (attrNames cfg.dynamicHosts.hostsDirs);
+ };
environment.systemPackages = cfg.packages;
@@ -398,6 +460,21 @@ in {
'';
};
+ systemd.services.nm-setup-hostsdirs = mkIf dynamicHostsEnabled {
+ wantedBy = [ "network-manager.service" ];
+ before = [ "network-manager.service" ];
+ partOf = [ "network-manager.service" ];
+ script = concatStrings (mapAttrsToList (n: d: ''
+ mkdir -p "/run/NetworkManager/hostsdirs/${n}"
+ chown "${d.user}:${d.group}" "/run/NetworkManager/hostsdirs/${n}"
+ chmod 0775 "/run/NetworkManager/hostsdirs/${n}"
+ '') cfg.dynamicHosts.hostsDirs);
+ serviceConfig = {
+ Type = "oneshot";
+ RemainAfterExist = true;
+ };
+ };
+
# Turn off NixOS' network management
networking = {
useDHCP = false;