i've seen enough, that there's a path toward getting nixos proper to sandbox this in a way i'm happy with -- in time
231 lines
9.4 KiB
Nix
231 lines
9.4 KiB
Nix
# Network Manager:
|
|
# i manage this myself because the nixos service is not flexible enough.
|
|
# - it unconditionally puts modemmanager onto the system path, preventing me from patching modemmanager's service file (without an overlay).
|
|
#
|
|
# XXX: it's normal to see error messages on an ethernet-only host, even when using nixos' official networkmanager service:
|
|
# - `Couldn't initialize supplicant interface: Failed to D-Bus activate wpa_supplicant service`
|
|
{ config, lib, pkgs, ... }:
|
|
let
|
|
cfg = config.sane.programs.networkmanager;
|
|
networkmanager = pkgs.networkmanager.overrideAttrs (upstream: {
|
|
src = pkgs.fetchFromGitea {
|
|
domain = "git.uninsane.org";
|
|
owner = "colin";
|
|
repo = "NetworkManager";
|
|
rev = "dev-sane-1.46.0";
|
|
hash = "sha256-S5ZiOfCpwtVVVO+DP6OPodJqzSc/LW4waI42DRkT+RA=";
|
|
};
|
|
# patches = [];
|
|
});
|
|
networkmanager-split = pkgs.networkmanager-split.override { inherit networkmanager; };
|
|
in
|
|
{
|
|
config = lib.mkMerge [
|
|
{
|
|
sane.programs.networkmanager = {
|
|
packageUnwrapped = networkmanager-split.daemon.overrideAttrs (upstream: {
|
|
# postPatch = (upstream.postPatch or "") + ''
|
|
# substituteInPlace src/{core/org.freedesktop.NetworkManager,nm-dispatcher/nm-dispatcher}.conf --replace-fail \
|
|
# 'user="root"' 'user="networkmanager"'
|
|
# '';
|
|
postInstall = (upstream.postInstall or "") + ''
|
|
# allow the bus to owned by either root or networkmanager users
|
|
# use the group here, that way ordinary users can be elevated to control networkmanager
|
|
# (via e.g. `nmcli`)
|
|
for f in org.freedesktop.NetworkManager.conf nm-dispatcher.conf ; do
|
|
substitute $out/share/dbus-1/system.d/$f \
|
|
$out/share/dbus-1/system.d/networkmanager-$f \
|
|
--replace-fail 'user="root"' 'group="networkmanager"'
|
|
done
|
|
|
|
# remove unused services to prevent any unexpected interactions
|
|
rm $out/etc/systemd/system/{nm-cloud-setup.service,nm-cloud-setup.timer,nm-priv-helper.service}
|
|
'';
|
|
});
|
|
|
|
suggestedPrograms = [ "nmcli" "wpa_supplicant" ];
|
|
enableFor.system = lib.mkIf (builtins.any (en: en) (builtins.attrValues cfg.enableFor.user)) true;
|
|
|
|
# this contains both the NetworkManager service and the NetworkManager-dispatcher service
|
|
# the latter of which calls a lot of user code.
|
|
# as a result, this needs all the perms which my hook in modules/services/trust-dns/trust-dns-nmhook needs.
|
|
sandbox.method = "landlock";
|
|
sandbox.capabilities = [
|
|
# "dac_override"
|
|
"net_admin"
|
|
"net_raw"
|
|
"net_bind_service" #< TODO: is this needed? why? (DNS?)
|
|
# "sys_module"
|
|
"audit_write" #< allow writing to the audit log
|
|
# "kill"
|
|
];
|
|
sandbox.extraPaths = [
|
|
"/proc/net"
|
|
"/proc/sys/net"
|
|
"/run/NetworkManager"
|
|
"/run/systemd" # for trust-dns-nmhook
|
|
"/run/udev"
|
|
# "/run/wg-home.priv"
|
|
"/sys/class" #< TODO: specify this more precisely
|
|
"/sys/devices"
|
|
"/var/lib/NetworkManager"
|
|
"/var/lib/trust-dns" #< for trust-dns-nmhook
|
|
];
|
|
|
|
sandbox.whitelistDbus = [ "system" ];
|
|
};
|
|
}
|
|
|
|
(lib.mkIf cfg.enabled {
|
|
# add to systemd.packages so we get the service file it ships, then override what we need to customize (taken from nixpkgs)
|
|
# systemd.packages = [ cfg.package ];
|
|
networking.networkmanager.enable = true;
|
|
networking.networkmanager.enableDefaultPlugins = false;
|
|
networking.networkmanager.package = cfg.package;
|
|
systemd.services.NetworkManager = {
|
|
# wantedBy = [ "network.target" ];
|
|
aliases = [ "dbus-org.freedesktop.NetworkManager.service" ];
|
|
|
|
path = [ "/run/current-system/sw" ]; #< so it can find `sanebox`
|
|
serviceConfig.RuntimeDirectory = "NetworkManager"; #< tells systemd to create /run/NetworkManager
|
|
# serviceConfig.StateDirectory = "NetworkManager"; #< tells systemd to create /var/lib/NetworkManager
|
|
serviceConfig.User = "networkmanager";
|
|
serviceConfig.Group = "networkmanager";
|
|
serviceConfig.AmbientCapabilities = [
|
|
# "CAP_DAC_OVERRIDE"
|
|
"CAP_NET_ADMIN"
|
|
"CAP_NET_RAW"
|
|
"CAP_NET_BIND_SERVICE" #< this *does* seem to be necessary, though i don't understand why. DHCP?
|
|
# "CAP_SYS_MODULE"
|
|
"CAP_AUDIT_WRITE" #< allow writing to the audit log
|
|
# "CAP_KILL"
|
|
];
|
|
};
|
|
|
|
systemd.services.NetworkManager-wait-online = {
|
|
path = [ "/run/current-system/sw" ]; #< so `nm-online` can find `sanebox`
|
|
# wantedBy = [ "network-online.target" ];
|
|
serviceConfig.User = "networkmanager";
|
|
serviceConfig.Group = "networkmanager";
|
|
};
|
|
|
|
systemd.services.NetworkManager-dispatcher = {
|
|
# wantedBy = [ "NetworkManager.service" ];
|
|
after = [ "trust-dns-localhost.service" ]; #< so that /var/lib/trust-dns will exist
|
|
path = [ "/run/current-system/sw" ]; #< so it can find `sanebox`
|
|
# to debug, add NM_DISPATCHER_DEBUG_LOG=1
|
|
serviceConfig.ExecStart = [
|
|
"" # first blank line is to clear the upstream `ExecStart` field.
|
|
"${cfg.package}/libexec/nm-dispatcher --persist" # --persist is needed for it to actually run as a daemon
|
|
];
|
|
serviceConfig.Restart = "always";
|
|
serviceConfig.RestartSec = "1s";
|
|
serviceConfig.User = "networkmanager";
|
|
serviceConfig.Group = "networkmanager";
|
|
};
|
|
|
|
networking.networkmanager.settings = {
|
|
# wifi.backend = "wpa_supplicant";
|
|
# wifi.scan-rand-mac-address = true;
|
|
|
|
# logging.audit = false;
|
|
logging.level = "INFO";
|
|
|
|
# main.dhcp = "internal";
|
|
main.dns = if config.services.resolved.enable then
|
|
"systemd-resolved"
|
|
else if config.sane.services.trust-dns.enable && config.sane.services.trust-dns.asSystemResolver then
|
|
"none"
|
|
else
|
|
"internal"
|
|
;
|
|
main.systemd-resolved = false;
|
|
};
|
|
|
|
environment.etc = {
|
|
"NetworkManager/system-connections".source = "/var/lib/NetworkManager/system-connections";
|
|
# "NetworkManager/NetworkManager.conf".text = ''
|
|
# [device]
|
|
# # wifi.backend: wpa_supplicant or iwd
|
|
# wifi.backend=wpa_supplicant
|
|
# wifi.scan-rand-mac-address=true
|
|
|
|
# [logging]
|
|
# audit=false
|
|
# # level: TRACE, DEBUG, INFO, WARN, ERR, OFF
|
|
# level=INFO
|
|
# # domain=...
|
|
|
|
# [main]
|
|
# # dhcp:
|
|
# # - `internal` (default)
|
|
# # - `dhclient` (requires dhclient to be installed)
|
|
# # - `dhcpcd` (requires dhcpcd to be installed)
|
|
# dhcp=internal
|
|
# # dns:
|
|
# # - `default`: update /etc/resolv.conf with nameservers provided by the active connection
|
|
# # - `none`: NM won't update /etc/resolv.conf
|
|
# # - `systemd-resolved`: push DNS config to systemd-resolved
|
|
# # - `dnsmasq`: run a local caching nameserver
|
|
# dns=${if config.services.resolved.enable then
|
|
# "systemd-resolved"
|
|
# else if config.sane.services.trust-dns.enable && config.sane.services.trust-dns.asSystemResolver then
|
|
# "none"
|
|
# else
|
|
# "internal"
|
|
# }
|
|
# plugins=keyfile
|
|
# # rc-manager: how NM should write to /etc/resolv.conf
|
|
# # - regardless of this setting, NM will write /var/lib/NetworkManager/resolv.conf
|
|
# rc-manager=unmanaged
|
|
# # systemd-resolved: send DNS config to systemd-resolved?
|
|
# # this setting has no effect if dns="systemd-resolved"; it's supplementary, not absolute.
|
|
# systemd-resolved=false
|
|
# # debug=... (see also: NM_DEBUG env var)
|
|
# '';
|
|
};
|
|
|
|
# hardware.wirelessRegulatoryDatabase = true;
|
|
# networking.useDHCP = false;
|
|
# services.udev.packages = [ cfg.package ];
|
|
# security.polkit.enable = lib.mkDefault true;
|
|
|
|
# security.polkit.extraConfig = lib.concatStringsSep "\n" [
|
|
# # allow networkmanager unbounded control over modemmanager.
|
|
# # i believe this was sourced from the default nixpkgs config.
|
|
# ''
|
|
# polkit.addRule(function(action, subject) {
|
|
# if (subject.isInGroup("networkmanager")
|
|
# && (
|
|
# action.id.indexOf("org.freedesktop.NetworkManager.") == 0
|
|
# || action.id.indexOf("org.freedesktop.ModemManager") == 0
|
|
# )
|
|
# ) {
|
|
# return polkit.Result.YES;
|
|
# }
|
|
# });
|
|
# ''
|
|
|
|
# allow networkmanager to control systemd-resolved,
|
|
# which it needs to do to apply new DNS settings when using systemd-resolved.
|
|
security.polkit.extraConfig = ''
|
|
polkit.addRule(function(action, subject) {
|
|
if (subject.isInGroup("networkmanager") && action.id.indexOf("org.freedesktop.resolve1.") == 0) {
|
|
return polkit.Result.YES;
|
|
}
|
|
});
|
|
'';
|
|
|
|
# users.groups.networkmanager.gid = config.ids.gids.networkmanager;
|
|
users.users.networkmanager = {
|
|
isSystemUser = true;
|
|
group = "networkmanager";
|
|
extraGroups = [ "trust-dns" ];
|
|
};
|
|
|
|
# boot.kernelModules = [ "ctr" ]; #< TODO: needed (what even is this)?
|
|
# TODO: NetworkManager-ensure-profiles?
|
|
})
|
|
];
|
|
}
|