nixos/networkmanager: split modemmanager into a separate module (#316824)

This commit is contained in:
misuzu 2024-12-20 13:06:35 +02:00 committed by GitHub
commit a01b0bf2fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 322 additions and 189 deletions

View file

@ -30,6 +30,8 @@
- [MaryTTS](https://github.com/marytts/marytts), an open-source, multilingual text-to-speech synthesis system written in pure Java. Available as [services.marytts](options.html#opt-services.marytts). - [MaryTTS](https://github.com/marytts/marytts), an open-source, multilingual text-to-speech synthesis system written in pure Java. Available as [services.marytts](options.html#opt-services.marytts).
- [networking.modemmanager](options.html#opt-networking.modemmanager) has been split out of [networking.networkmanager](options.html#opt-networking.networkmanager). NetworkManager still enables ModemManager by default, but options exist now to run NetworkManager without ModemManager.
- [Conduwuit](https://conduwuit.puppyirl.gay/), a federated chat server implementing the Matrix protocol, forked from Conduit. Available as [services.conduwuit](#opt-services.conduwuit.enable). - [Conduwuit](https://conduwuit.puppyirl.gay/), a federated chat server implementing the Matrix protocol, forked from Conduit. Available as [services.conduwuit](#opt-services.conduwuit.enable).
- [Traccar](https://www.traccar.org/), a modern GPS Tracking Platform. Available as [services.traccar](#opt-services.traccar.enable). - [Traccar](https://www.traccar.org/), a modern GPS Tracking Platform. Available as [services.traccar](#opt-services.traccar.enable).

View file

@ -1137,6 +1137,7 @@
./services/networking/miredo.nix ./services/networking/miredo.nix
./services/networking/mjpg-streamer.nix ./services/networking/mjpg-streamer.nix
./services/networking/mmsd.nix ./services/networking/mmsd.nix
./services/networking/modemmanager.nix
./services/networking/monero.nix ./services/networking/monero.nix
./services/networking/morty.nix ./services/networking/morty.nix
./services/networking/mosquitto.nix ./services/networking/mosquitto.nix

View file

@ -0,0 +1,97 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.networking.modemmanager;
in
{
meta = {
maintainers = lib.teams.freedesktop.members;
};
options = with lib; {
networking.modemmanager = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether to use ModemManager to manage modem devices.
This is usually used by some higher layer manager such as NetworkManager
but can be used standalone especially if using a modem for non-IP
connectivity (e.g. GPS).
'';
};
package = mkPackageOption pkgs "modemmanager" { };
fccUnlockScripts = mkOption {
type = types.listOf (
types.submodule {
options = {
id = mkOption {
type = types.str;
description = "vid:pid of either the PCI or USB vendor and product ID";
};
path = mkOption {
type = types.path;
description = "Path to the unlock script";
};
};
}
);
default = [ ];
example = literalExpression ''[{ id = "03f0:4e1d"; path = "''${pkgs.modemmanager}/share/ModemManager/fcc-unlock.available.d/03f0:4e1d"; }]'';
description = ''
List of FCC unlock scripts to enable on the system, behaving as described in
https://modemmanager.org/docs/modemmanager/fcc-unlock/#integration-with-third-party-fcc-unlock-tools.
'';
};
};
};
config = lib.mkIf cfg.enable {
environment.etc = builtins.listToAttrs (
map (
e:
lib.nameValuePair "ModemManager/fcc-unlock.d/${e.id}" {
source = e.path;
}
) cfg.fccUnlockScripts
);
systemd.services.ModemManager = {
aliases = [ "dbus-org.freedesktop.ModemManager1.service" ];
path = lib.optionals (cfg.fccUnlockScripts != [ ]) [
pkgs.libqmi
pkgs.libmbim
];
};
/*
[modem-manager]
Identity=unix-group:networkmanager
Action=org.freedesktop.ModemManager*
ResultAny=yes
ResultInactive=no
ResultActive=yes
*/
security.polkit.enable = true;
security.polkit.extraConfig = ''
polkit.addRule(function(action, subject) {
if (
subject.isInGroup("networkmanager")
&& action.id.indexOf("org.freedesktop.ModemManager") == 0
)
{ return polkit.Result.YES; }
});
'';
environment.systemPackages = [ cfg.package ];
systemd.packages = [ cfg.package ];
services.dbus.packages = [ cfg.package ];
services.udev.packages = [ cfg.package ];
};
}

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
with lib; with lib;
@ -15,14 +20,10 @@ let
plugins = "keyfile"; plugins = "keyfile";
inherit (cfg) dhcp dns; inherit (cfg) dhcp dns;
# If resolvconf is disabled that means that resolv.conf is managed by some other module. # If resolvconf is disabled that means that resolv.conf is managed by some other module.
rc-manager = rc-manager = if config.networking.resolvconf.enable then "resolvconf" else "unmanaged";
if config.networking.resolvconf.enable then "resolvconf"
else "unmanaged";
}; };
keyfile = { keyfile = {
unmanaged-devices = unmanaged-devices = if cfg.unmanaged == [ ] then null else lib.concatStringsSep ";" cfg.unmanaged;
if cfg.unmanaged == [ ] then null
else lib.concatStringsSep ";" cfg.unmanaged;
}; };
logging = { logging = {
audit = config.security.audit.enable; audit = config.security.audit.enable;
@ -43,32 +44,29 @@ let
ResultAny=yes ResultAny=yes
ResultInactive=no ResultInactive=no
ResultActive=yes ResultActive=yes
[modem-manager]
Identity=unix-group:networkmanager
Action=org.freedesktop.ModemManager*
ResultAny=yes
ResultInactive=no
ResultActive=yes
*/ */
polkitConf = '' polkitConf = ''
polkit.addRule(function(action, subject) { polkit.addRule(function(action, subject) {
if ( if (
subject.isInGroup("networkmanager") subject.isInGroup("networkmanager")
&& (action.id.indexOf("org.freedesktop.NetworkManager.") == 0 && action.id.indexOf("org.freedesktop.NetworkManager.") == 0
|| action.id.indexOf("org.freedesktop.ModemManager") == 0 )
))
{ return polkit.Result.YES; } { return polkit.Result.YES; }
}); });
''; '';
ns = xs: pkgs.writeText "nameservers" ( ns = xs: pkgs.writeText "nameservers" (concatStrings (map (s: "nameserver ${s}\n") xs));
concatStrings (map (s: "nameserver ${s}\n") xs)
);
overrideNameserversScript = pkgs.writeScript "02overridedns" '' overrideNameserversScript = pkgs.writeScript "02overridedns" ''
#!/bin/sh #!/bin/sh
PATH=${with pkgs; makeBinPath [ gnused gnugrep coreutils ]} PATH=${
with pkgs;
makeBinPath [
gnused
gnugrep
coreutils
]
}
tmp=$(mktemp) tmp=$(mktemp)
sed '/nameserver /d' /etc/resolv.conf > $tmp sed '/nameserver /d' /etc/resolv.conf > $tmp
grep 'nameserver ' /etc/resolv.conf | \ grep 'nameserver ' /etc/resolv.conf | \
@ -84,7 +82,15 @@ let
}; };
macAddressOptWifi = mkOption { macAddressOptWifi = mkOption {
type = types.either types.str (types.enum [ "permanent" "preserve" "random" "stable" "stable-ssid" ]); type = types.either types.str (
types.enum [
"permanent"
"preserve"
"random"
"stable"
"stable-ssid"
]
);
default = "preserve"; default = "preserve";
example = "00:11:22:33:44:55"; example = "00:11:22:33:44:55";
description = '' description = ''
@ -100,7 +106,14 @@ let
}; };
macAddressOptEth = mkOption { macAddressOptEth = mkOption {
type = types.either types.str (types.enum [ "permanent" "preserve" "random" "stable" ]); type = types.either types.str (
types.enum [
"permanent"
"preserve"
"random"
"stable"
]
);
default = "preserve"; default = "preserve";
example = "00:11:22:33:44:55"; example = "00:11:22:33:44:55";
description = '' description = ''
@ -114,9 +127,9 @@ let
''; '';
}; };
packages = [ packages =
pkgs.modemmanager [
pkgs.networkmanager cfg.package
] ]
++ cfg.plugins ++ cfg.plugins
++ lib.optionals (!delegateWireless && !enableIwd) [ ++ lib.optionals (!delegateWireless && !enableIwd) [
@ -148,12 +161,18 @@ in
''; '';
}; };
package = mkPackageOption pkgs "networkmanager" { };
connectionConfig = mkOption { connectionConfig = mkOption {
type = with types; attrsOf (nullOr (oneOf [ type =
with types;
attrsOf (
nullOr (oneOf [
bool bool
int int
str str
])); ])
);
default = { }; default = { };
description = '' description = ''
Configuration for the [connection] section of NetworkManager.conf. Configuration for the [connection] section of NetworkManager.conf.
@ -169,7 +188,7 @@ in
settings = mkOption { settings = mkOption {
type = ini.type; type = ini.type;
default = {}; default = { };
description = '' description = ''
Configuration added to the generated NetworkManager.conf, note that you can overwrite settings with this. Configuration added to the generated NetworkManager.conf, note that you can overwrite settings with this.
Refer to Refer to
@ -205,9 +224,7 @@ in
check = check =
p: p:
lib.assertMsg lib.assertMsg
(types.package.check p (types.package.check p && p ? networkManagerPlugin && lib.isString p.networkManagerPlugin)
&& p ? networkManagerPlugin
&& lib.isString p.networkManagerPlugin)
'' ''
Package ${p.name}, is not a NetworkManager plug-in. Package ${p.name}, is not a NetworkManager plug-in.
Those need to have a networkManagerPlugin attribute. Those need to have a networkManagerPlugin attribute.
@ -223,7 +240,10 @@ in
}; };
dhcp = mkOption { dhcp = mkOption {
type = types.enum [ "dhcpcd" "internal" ]; type = types.enum [
"dhcpcd"
"internal"
];
default = "internal"; default = "internal";
description = '' description = ''
Which program (or internal library) should be used for DHCP. Which program (or internal library) should be used for DHCP.
@ -231,7 +251,14 @@ in
}; };
logLevel = mkOption { logLevel = mkOption {
type = types.enum [ "OFF" "ERR" "WARN" "INFO" "DEBUG" "TRACE" ]; type = types.enum [
"OFF"
"ERR"
"WARN"
"INFO"
"DEBUG"
"TRACE"
];
default = "WARN"; default = "WARN";
description = '' description = ''
Set the default logging verbosity level. Set the default logging verbosity level.
@ -262,7 +289,10 @@ in
macAddress = macAddressOptWifi; macAddress = macAddressOptWifi;
backend = mkOption { backend = mkOption {
type = types.enum [ "wpa_supplicant" "iwd" ]; type = types.enum [
"wpa_supplicant"
"iwd"
];
default = "wpa_supplicant"; default = "wpa_supplicant";
description = '' description = ''
Specify the Wi-Fi backend used for the device. Specify the Wi-Fi backend used for the device.
@ -289,7 +319,12 @@ in
}; };
dns = mkOption { dns = mkOption {
type = types.enum [ "default" "dnsmasq" "systemd-resolved" "none" ]; type = types.enum [
"default"
"dnsmasq"
"systemd-resolved"
"none"
];
default = "default"; default = "default";
description = '' description = ''
Set the DNS (`resolv.conf`) processing mode. Set the DNS (`resolv.conf`) processing mode.
@ -304,7 +339,8 @@ in
}; };
dispatcherScripts = mkOption { dispatcherScripts = mkOption {
type = types.listOf (types.submodule { type = types.listOf (
types.submodule {
options = { options = {
source = mkOption { source = mkOption {
type = types.path; type = types.path;
@ -324,7 +360,8 @@ in
''; '';
}; };
}; };
}); }
);
default = [ ]; default = [ ];
example = literalExpression '' example = literalExpression ''
[ { [ {
@ -358,28 +395,10 @@ in
''; '';
}; };
fccUnlockScripts = mkOption {
type = types.listOf (types.submodule {
options = {
id = mkOption {
type = types.str;
description = "vid:pid of either the PCI or USB vendor and product ID";
};
path = mkOption {
type = types.path;
description = "Path to the unlock script";
};
};
});
default = [ ];
example = literalExpression ''[{ id = "03f0:4e1d"; path = "''${pkgs.modemmanager}/share/ModemManager/fcc-unlock.available.d/03f0:4e1d"; }]'';
description = ''
List of FCC unlock scripts to enable on the system, behaving as described in
https://modemmanager.org/docs/modemmanager/fcc-unlock/#integration-with-third-party-fcc-unlock-tools.
'';
};
ensureProfiles = { ensureProfiles = {
profiles = with lib.types; mkOption { profiles =
with lib.types;
mkOption {
type = attrsOf (submodule { type = attrsOf (submodule {
freeformType = ini.type; freeformType = ini.type;
@ -438,7 +457,7 @@ in
''; '';
}; };
environmentFiles = mkOption { environmentFiles = mkOption {
default = []; default = [ ];
type = types.listOf types.path; type = types.listOf types.path;
example = [ "/run/secrets/network-manager.env" ]; example = [ "/run/secrets/network-manager.env" ];
description = '' description = ''
@ -473,14 +492,13 @@ in
+ settings.main.no-auto-default = "*"; + settings.main.no-auto-default = "*";
}; };
``` ```
'' '')
)
(mkRemovedOptionModule [ "networking" "networkmanager" "enableFccUnlock" ] '' (mkRemovedOptionModule [ "networking" "networkmanager" "enableFccUnlock" ] ''
This option was removed, because using bundled FCC unlock scripts is risky, This option was removed, because using bundled FCC unlock scripts is risky,
might conflict with vendor-provided unlock scripts, and should might conflict with vendor-provided unlock scripts, and should
be a conscious decision on a per-device basis. be a conscious decision on a per-device basis.
Instead it's recommended to use the Instead it's recommended to use the
`networking.networkmanager.fccUnlockScripts` option. `networking.modemmanager.fccUnlockScripts` option.
'') '')
(mkRemovedOptionModule [ "networking" "networkmanager" "dynamicHosts" ] '' (mkRemovedOptionModule [ "networking" "networkmanager" "dynamicHosts" ] ''
This option was removed because allowing (multiple) regular users to This option was removed because allowing (multiple) regular users to
@ -493,9 +511,12 @@ in
(mkRemovedOptionModule [ "networking" "networkmanager" "firewallBackend" ] '' (mkRemovedOptionModule [ "networking" "networkmanager" "firewallBackend" ] ''
This option was removed as NixOS is now using iptables-nftables-compat even when using iptables, therefore Networkmanager now uses the nftables backend unconditionally. This option was removed as NixOS is now using iptables-nftables-compat even when using iptables, therefore Networkmanager now uses the nftables backend unconditionally.
'') '')
(mkRenamedOptionModule
[ "networking" "networkmanager" "fccUnlockScripts" ]
[ "networking" "modemmanager" "fccUnlockScripts" ]
)
]; ];
###### implementation ###### implementation
config = mkIf cfg.enable { config = mkIf cfg.enable {
@ -512,7 +533,8 @@ in
hardware.wirelessRegulatoryDatabase = true; hardware.wirelessRegulatoryDatabase = true;
environment.etc = { environment.etc =
{
"NetworkManager/NetworkManager.conf".source = configFile; "NetworkManager/NetworkManager.conf".source = configFile;
# The networkmanager-l2tp plugin expects /etc/ipsec.secrets to include /etc/ipsec.d/ipsec.nm-l2tp.secrets; # The networkmanager-l2tp plugin expects /etc/ipsec.secrets to include /etc/ipsec.d/ipsec.nm-l2tp.secrets;
@ -521,27 +543,28 @@ in
include ipsec.d/ipsec.nm-l2tp.secrets include ipsec.d/ipsec.nm-l2tp.secrets
''; '';
} }
// builtins.listToAttrs (map // builtins.listToAttrs (
(pkg: nameValuePair "NetworkManager/${pkg.networkManagerPlugin}" { map (
pkg:
nameValuePair "NetworkManager/${pkg.networkManagerPlugin}" {
source = "${pkg}/lib/NetworkManager/${pkg.networkManagerPlugin}"; source = "${pkg}/lib/NetworkManager/${pkg.networkManagerPlugin}";
}) }
cfg.plugins) ) cfg.plugins
// builtins.listToAttrs (map )
(e: nameValuePair "ModemManager/fcc-unlock.d/${e.id}" { // optionalAttrs (cfg.appendNameservers != [ ] || cfg.insertNameservers != [ ]) {
source = e.path;
})
cfg.fccUnlockScripts)
// optionalAttrs (cfg.appendNameservers != [ ] || cfg.insertNameservers != [ ])
{
"NetworkManager/dispatcher.d/02overridedns".source = overrideNameserversScript; "NetworkManager/dispatcher.d/02overridedns".source = overrideNameserversScript;
} }
// listToAttrs (lib.imap1 // listToAttrs (
(i: s: lib.imap1 (i: s: {
{ name = "NetworkManager/dispatcher.d/${
name = "NetworkManager/dispatcher.d/${dispatcherTypesSubdirMap.${s.type}}03userscript${lib.fixedWidthNumber 4 i}"; dispatcherTypesSubdirMap.${s.type}
value = { mode = "0544"; inherit (s) source; }; }03userscript${lib.fixedWidthNumber 4 i}";
}) value = {
cfg.dispatcherScripts); mode = "0544";
inherit (s) source;
};
}) cfg.dispatcherScripts
);
environment.systemPackages = packages; environment.systemPackages = packages;
@ -590,17 +613,19 @@ in
wantedBy = [ "network-online.target" ]; wantedBy = [ "network-online.target" ];
}; };
systemd.services.ModemManager = {
aliases = [ "dbus-org.freedesktop.ModemManager1.service" ];
path = lib.optionals (cfg.fccUnlockScripts != []) [ pkgs.libqmi pkgs.libmbim ];
};
systemd.services.NetworkManager-dispatcher = { systemd.services.NetworkManager-dispatcher = {
wantedBy = [ "network.target" ]; wantedBy = [ "network.target" ];
restartTriggers = [ configFile overrideNameserversScript ]; restartTriggers = [
configFile
overrideNameserversScript
];
# useful binaries for user-specified hooks # useful binaries for user-specified hooks
path = [ pkgs.iproute2 pkgs.util-linux pkgs.coreutils ]; path = [
pkgs.iproute2
pkgs.util-linux
pkgs.coreutils
];
aliases = [ "dbus-org.freedesktop.nm-dispatcher.service" ]; aliases = [ "dbus-org.freedesktop.nm-dispatcher.service" ];
}; };
@ -609,16 +634,18 @@ in
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
before = [ "network-online.target" ]; before = [ "network-online.target" ];
after = [ "NetworkManager.service" ]; after = [ "NetworkManager.service" ];
script = let script =
let
path = id: "/run/NetworkManager/system-connections/${id}.nmconnection"; path = id: "/run/NetworkManager/system-connections/${id}.nmconnection";
in '' in
''
mkdir -p /run/NetworkManager/system-connections mkdir -p /run/NetworkManager/system-connections
'' + lib.concatMapStringsSep "\n" ''
(profile: '' + lib.concatMapStringsSep "\n" (profile: ''
${pkgs.envsubst}/bin/envsubst -i ${ini.generate (lib.escapeShellArg profile.n) profile.v} > ${path (lib.escapeShellArg profile.n)} ${pkgs.envsubst}/bin/envsubst -i ${ini.generate (lib.escapeShellArg profile.n) profile.v} > ${path (lib.escapeShellArg profile.n)}
'') (lib.mapAttrsToList (n: v: { inherit n v; }) cfg.ensureProfiles.profiles) '') (lib.mapAttrsToList (n: v: { inherit n v; }) cfg.ensureProfiles.profiles)
+ '' + ''
${pkgs.networkmanager}/bin/nmcli connection reload ${cfg.package}/bin/nmcli connection reload
''; '';
serviceConfig = { serviceConfig = {
EnvironmentFile = cfg.ensureProfiles.environmentFiles; EnvironmentFile = cfg.ensureProfiles.environmentFiles;
@ -654,13 +681,18 @@ in
}) })
{ {
modemmanager.enable = lib.mkDefault true;
networkmanager.connectionConfig = { networkmanager.connectionConfig = {
"ethernet.cloned-mac-address" = cfg.ethernet.macAddress; "ethernet.cloned-mac-address" = cfg.ethernet.macAddress;
"wifi.cloned-mac-address" = cfg.wifi.macAddress; "wifi.cloned-mac-address" = cfg.wifi.macAddress;
"wifi.powersave" = "wifi.powersave" =
if cfg.wifi.powersave == null then null if cfg.wifi.powersave == null then
else if cfg.wifi.powersave then 3 null
else 2; else if cfg.wifi.powersave then
3
else
2;
}; };
} }
]; ];
@ -670,7 +702,8 @@ in
security.polkit.enable = true; security.polkit.enable = true;
security.polkit.extraConfig = polkitConf; security.polkit.extraConfig = polkitConf;
services.dbus.packages = packages services.dbus.packages =
packages
++ optional cfg.enableStrongSwan pkgs.strongswanNM ++ optional cfg.enableStrongSwan pkgs.strongswanNM
++ optional (cfg.dns == "dnsmasq") pkgs.dnsmasq; ++ optional (cfg.dns == "dnsmasq") pkgs.dnsmasq;