hosts: networking: switch to using nixos NetworkManager/ModemManager/etc, just patched for hardening
This commit is contained in:
parent
1b85aa0441
commit
e4bcbab224
|
@ -4,6 +4,8 @@
|
|||
imports = [
|
||||
./dns.nix
|
||||
./hostnames.nix
|
||||
./modemmanager.nix
|
||||
./networkmanager.nix
|
||||
./upnp.nix
|
||||
./vpn.nix
|
||||
];
|
||||
|
@ -57,7 +59,8 @@
|
|||
#
|
||||
# i don't use these, and notably they drag in huge dependency sets and don't cross compile well.
|
||||
# e.g. openconnect drags in webkitgtk (for SSO)!
|
||||
networking.networkmanager.plugins = lib.mkForce [];
|
||||
# networking.networkmanager.plugins = lib.mkForce [];
|
||||
networking.networkmanager.enableDefaultPlugins = false;
|
||||
|
||||
# keyfile.path = where networkmanager should look for connection credentials
|
||||
networking.networkmanager.settings.keyfile.path = "/var/lib/NetworkManager/system-connections";
|
||||
|
|
60
hosts/common/net/modemmanager.nix
Normal file
60
hosts/common/net/modemmanager.nix
Normal file
|
@ -0,0 +1,60 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
networking.modemmanager.package = pkgs.modemmanager-split.daemon.overrideAttrs (upstream: {
|
||||
# patch to allow the dbus endpoints to be owned by networkmanager user
|
||||
postInstall = (upstream.postInstall or "") + ''
|
||||
substitute $out/share/dbus-1/system.d/org.freedesktop.ModemManager1.conf \
|
||||
$out/share/dbus-1/system.d/networkmanager-org.freedesktop.ModemManager1.conf \
|
||||
--replace-fail 'user="root"' 'group="networkmanager"'
|
||||
'';
|
||||
});
|
||||
|
||||
systemd.services.ModemManager = {
|
||||
# aliases = [ "dbus-org.freedesktop.ModemManager1.service" ];
|
||||
# after = [ "polkit.service" ];
|
||||
# requires = [ "polkit.service" ];
|
||||
wantedBy = [ "network.target" ]; #< default is `multi-user.target`, somehow it doesn't auto-start with that...
|
||||
# path = [ "/run/current-system/sw" ]; #< so it can find `sanebox`
|
||||
|
||||
# serviceConfig.Type = "dbus";
|
||||
# serviceConfig.BusName = "org.freedesktop.ModemManager1";
|
||||
|
||||
# only if started with `--debug` does mmcli let us issue AT commands like
|
||||
# `mmcli --modem any --command=<AT_CMD>`
|
||||
serviceConfig.ExecStart = [
|
||||
"" # first blank line is to clear the upstream `ExecStart` field.
|
||||
"${lib.getExe' config.networking.modemmanager.package "ModemManager"} --debug"
|
||||
];
|
||||
# --debug sets DEBUG level logging: so reset
|
||||
serviceConfig.ExecStartPost = "${lib.getExe config.sane.programs.mmcli.package} --set-logging=INFO";
|
||||
|
||||
# v this is what upstream ships
|
||||
# serviceConfig.Restart = "on-abort";
|
||||
# serviceConfig.StandardError = "null";
|
||||
# serviceConfig.CapabilityBoundingSet = "CAP_SYS_ADMIN CAP_NET_ADMIN";
|
||||
# serviceConfig.ProtectSystem = true;
|
||||
# serviceConfig.ProtectHome = true;
|
||||
# serviceConfig.PrivateTmp = true;
|
||||
# serviceConfig.RestrictAddressFamilies = "AF_NETLINK AF_UNIX AF_QIPCRTR";
|
||||
# serviceConfig.NoNewPrivileges = true;
|
||||
|
||||
# TODO: sandbox more aggressively
|
||||
# - CAP_NET_ADMIN *only*?
|
||||
# it needs these paths:
|
||||
# - # "/"
|
||||
# - "/dev" #v modem-power + net are not enough
|
||||
# - # "/dev/modem-power"
|
||||
# - # "/dev/net"
|
||||
# - "/proc"
|
||||
# - # /run #v can likely be reduced more
|
||||
# - "/run/dbus"
|
||||
# - "/run/NetworkManager"
|
||||
# - "/run/resolvconf"
|
||||
# - "/run/systemd"
|
||||
# - "/run/udev"
|
||||
# - "/sys"
|
||||
};
|
||||
|
||||
# so that ModemManager can discover when the modem appears
|
||||
# services.udev.packages = lib.mkIf cfg.enabled [ cfg.package ];
|
||||
}
|
166
hosts/common/net/networkmanager.nix
Normal file
166
hosts/common/net/networkmanager.nix
Normal file
|
@ -0,0 +1,166 @@
|
|||
{ config, pkgs, ... }:
|
||||
let
|
||||
networkmanager = pkgs.networkmanager.overrideAttrs (upstream: {
|
||||
src = pkgs.fetchFromGitea {
|
||||
domain = "git.uninsane.org";
|
||||
owner = "colin";
|
||||
repo = "NetworkManager";
|
||||
# patched to fix polkit permissions (with `nmcli`) when NetworkManager runs as user networkmanager
|
||||
rev = "dev-sane-1.46.0";
|
||||
hash = "sha256-S5ZiOfCpwtVVVO+DP6OPodJqzSc/LW4waI42DRkT+RA=";
|
||||
};
|
||||
# patches = [];
|
||||
});
|
||||
# split the package into `daemon` and `nmcli` outputs, because the networkmanager *service*
|
||||
# doesn't need `nmcli`/`nmtui` tooling
|
||||
networkmanager-split = pkgs.networkmanager-split.override { inherit networkmanager; };
|
||||
in {
|
||||
networking.networkmanager.enable = true;
|
||||
networking.networkmanager.enableDefaultPlugins = false;
|
||||
networking.networkmanager.package = 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}
|
||||
'';
|
||||
});
|
||||
|
||||
# fixup the services to run as `networkmanager` and with less permissions
|
||||
systemd.services.NetworkManager = {
|
||||
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"
|
||||
];
|
||||
# TODO: it needs these directories:
|
||||
# - "/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
|
||||
# - "/run/systemd"
|
||||
};
|
||||
|
||||
systemd.services.NetworkManager-wait-online = {
|
||||
serviceConfig.User = "networkmanager";
|
||||
serviceConfig.Group = "networkmanager";
|
||||
};
|
||||
|
||||
# fix NetworkManager-dispatcher to actually run as a daemon,
|
||||
# and sandbox it a bit
|
||||
systemd.services.NetworkManager-dispatcher = {
|
||||
after = [ "trust-dns-localhost.service" ]; #< so that /var/lib/trust-dns will exist
|
||||
# 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";
|
||||
# TODO: it needs access only to the above mentioned directories
|
||||
};
|
||||
|
||||
# harden wpa_supplicant (used by NetworkManager)
|
||||
systemd.services.wpa_supplicant = {
|
||||
serviceConfig.User = "networkmanager";
|
||||
serviceConfig.Group = "networkmanager";
|
||||
serviceConfig.AmbientCapabilities = [
|
||||
"CAP_NET_ADMIN"
|
||||
"CAP_NET_RAW"
|
||||
];
|
||||
# TODO: it needs only these paths:
|
||||
# - "/dev/net"
|
||||
# - "/dev/rfkill"
|
||||
# - "/proc/sys/net"
|
||||
# - "/sys/class/net"
|
||||
# - "/sys/devices"
|
||||
# - "/run/systemd"
|
||||
};
|
||||
|
||||
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";
|
||||
|
||||
# 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.users.networkmanager = {
|
||||
isSystemUser = true;
|
||||
group = "networkmanager";
|
||||
extraGroups = [ "trust-dns" ];
|
||||
};
|
||||
|
||||
# there is, unfortunately, no proper interface by which to plumb wpa_supplicant into the NixOS service, except by overlay.
|
||||
nixpkgs.overlays = [(self: super: {
|
||||
wpa_supplicant = super.wpa_supplicant.overrideAttrs (upstream: {
|
||||
# postPatch = (upstream.postPatch or "") + ''
|
||||
# substituteInPlace wpa_supplicant/dbus/dbus-wpa_supplicant.conf --replace-fail \
|
||||
# 'user="root"' 'user="networkmanager"'
|
||||
# '';
|
||||
postInstall = (upstream.postInstall or "") + ''
|
||||
substitute $out/share/dbus-1/system.d/dbus-wpa_supplicant.conf \
|
||||
$out/share/dbus-1/system.d/networkmanager-wpa_supplicant.conf \
|
||||
--replace-fail 'user="root"' 'group="networkmanager"'
|
||||
'';
|
||||
|
||||
postFixup = (upstream.postFixup or "") + ''
|
||||
# nixpkgs wpa_supplicant generates a dbus file which has a path like
|
||||
# /nix/store/abc-wpa_supplicant/nix/store/abc-wpa_supplicant/sbin/...
|
||||
# upstreaming status: <https://github.com/NixOS/nixpkgs/pull/315346>
|
||||
substituteInPlace $out/share/dbus-1/system-services/* --replace-fail \
|
||||
"$out$out" "$out"
|
||||
|
||||
# remove unused services to avoid unexpected interactions
|
||||
rm $out/etc/systemd/system/{wpa_supplicant-nl80211@,wpa_supplicant-wired@,wpa_supplicant@}.service
|
||||
'';
|
||||
});
|
||||
})];
|
||||
}
|
|
@ -71,12 +71,14 @@ in
|
|||
"man-pages"
|
||||
"man-pages-posix"
|
||||
# "miniupnpc"
|
||||
"mmcli"
|
||||
"nano"
|
||||
# "ncdu" # ncurses disk usage. doesn't cross compile (zig)
|
||||
"neovim"
|
||||
"netcat"
|
||||
"nethogs"
|
||||
"nmap"
|
||||
"nmcli"
|
||||
"nvme-cli" # nvme
|
||||
# "openssl"
|
||||
"parted"
|
||||
|
|
|
@ -81,13 +81,11 @@
|
|||
./mepo.nix
|
||||
./mimeo
|
||||
./mmcli.nix
|
||||
./modemmanager.nix
|
||||
./mopidy.nix
|
||||
./mpv
|
||||
./msmtp.nix
|
||||
./nautilus.nix
|
||||
./neovim.nix
|
||||
./networkmanager.nix
|
||||
./newsflash.nix
|
||||
./nheko.nix
|
||||
./nicotine-plus.nix
|
||||
|
@ -144,7 +142,6 @@
|
|||
./wine.nix
|
||||
./wireplumber.nix
|
||||
./wireshark.nix
|
||||
./wpa_supplicant.nix
|
||||
./wvkbd.nix
|
||||
./xarchiver.nix
|
||||
./xdg-desktop-portal.nix
|
||||
|
|
|
@ -4,7 +4,7 @@ let
|
|||
in
|
||||
{
|
||||
sane.programs.eg25-control = {
|
||||
suggestedPrograms = [ "modemmanager" ];
|
||||
suggestedPrograms = [ "mmcli" ];
|
||||
|
||||
services.eg25-control-powered = {
|
||||
description = "eg25-control-powered: power to the Qualcomm eg25 modem used by PinePhone";
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.modemmanager;
|
||||
in
|
||||
{
|
||||
sane.programs.modemmanager = {
|
||||
packageUnwrapped = pkgs.modemmanager-split.daemon.overrideAttrs (upstream: {
|
||||
postInstall = (upstream.postInstall or "") + ''
|
||||
substitute $out/share/dbus-1/system.d/org.freedesktop.ModemManager1.conf \
|
||||
$out/share/dbus-1/system.d/networkmanager-org.freedesktop.ModemManager1.conf \
|
||||
--replace-fail 'user="root"' 'group="networkmanager"'
|
||||
'';
|
||||
|
||||
meta = upstream.meta // {
|
||||
mainProgram = "ModemManager";
|
||||
};
|
||||
});
|
||||
# mmcli needs /run/current-system/sw/share/dbus-1 files to function
|
||||
enableFor.system = lib.mkIf (builtins.any (en: en) (builtins.attrValues cfg.enableFor.user)) true;
|
||||
|
||||
suggestedPrograms = [ "mmcli" ];
|
||||
|
||||
# bwrap sandboxing works, but requires the real user to be root.
|
||||
# landlock sandboxing works, and allows the real user to be someone else (like `networkmanager`).
|
||||
# non-root is very important, because of how many things in e.g. /dev are r/w based on uid=0.
|
||||
# TODO: have the services run as `networkmanager` user
|
||||
sandbox.method = "bwrap";
|
||||
# sandbox.method = "landlock";
|
||||
sandbox.wrapperType = "inplace"; #< .pc files, GIR files with absolute paths,
|
||||
sandbox.net = "all"; #< needed for modem bringup
|
||||
# sandbox.isolatePids = false;
|
||||
sandbox.capabilities = [
|
||||
"net_admin"
|
||||
"net_raw"
|
||||
];
|
||||
sandbox.extraPaths = lib.warn "TODO: modemmanager: sandbox more aggressively" [
|
||||
# "/"
|
||||
"/dev" #v modem-power + net are not enough
|
||||
# "/dev/modem-power"
|
||||
# "/dev/net"
|
||||
"/proc"
|
||||
# /run #v can likely be reduced more
|
||||
"/run/dbus"
|
||||
"/run/NetworkManager"
|
||||
"/run/resolvconf"
|
||||
"/run/systemd"
|
||||
"/run/udev"
|
||||
"/sys"
|
||||
# "/var"
|
||||
];
|
||||
};
|
||||
|
||||
networking.modemmanager = {
|
||||
enable = cfg.enabled;
|
||||
package = cfg.package;
|
||||
};
|
||||
|
||||
systemd.services.ModemManager = lib.mkIf cfg.enabled {
|
||||
# aliases = [ "dbus-org.freedesktop.ModemManager1.service" ];
|
||||
# after = [ "polkit.service" ];
|
||||
# requires = [ "polkit.service" ];
|
||||
# wantedBy = [ "network.target" ];
|
||||
path = [ "/run/current-system/sw" ]; #< so it can find `sanebox`
|
||||
|
||||
# serviceConfig.Type = "dbus";
|
||||
# serviceConfig.BusName = "org.freedesktop.ModemManager1";
|
||||
|
||||
# only if started with `--debug` does mmcli let us issue AT commands like
|
||||
# `mmcli --modem any --command=<AT_CMD>`
|
||||
serviceConfig.ExecStart = [
|
||||
"" # first blank line is to clear the upstream `ExecStart` field.
|
||||
"${lib.getExe cfg.package} --debug"
|
||||
];
|
||||
# --debug sets DEBUG level logging: so reset
|
||||
serviceConfig.ExecStartPost = "${lib.getExe config.sane.programs.mmcli.package} --set-logging=INFO";
|
||||
|
||||
# v this is what upstream ships
|
||||
# serviceConfig.Restart = "on-abort";
|
||||
# serviceConfig.StandardError = "null";
|
||||
# serviceConfig.CapabilityBoundingSet = "CAP_SYS_ADMIN CAP_NET_ADMIN";
|
||||
# serviceConfig.ProtectSystem = true;
|
||||
# serviceConfig.ProtectHome = true;
|
||||
# serviceConfig.PrivateTmp = true;
|
||||
# serviceConfig.RestrictAddressFamilies = "AF_NETLINK AF_UNIX AF_QIPCRTR";
|
||||
# serviceConfig.NoNewPrivileges = true;
|
||||
};
|
||||
|
||||
# so that ModemManager can discover when the modem appears
|
||||
# services.udev.packages = lib.mkIf cfg.enabled [ cfg.package ];
|
||||
}
|
|
@ -1,230 +0,0 @@
|
|||
# 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?
|
||||
})
|
||||
];
|
||||
}
|
|
@ -140,7 +140,6 @@ in
|
|||
"fontconfig"
|
||||
# "gnome.gnome-bluetooth" # XXX(2023/05/14): broken
|
||||
# "gnome.gnome-control-center" # XXX(2023/06/28): depends on webkitgtk4_1
|
||||
"networkmanager"
|
||||
"pipewire"
|
||||
"playerctl" # for waybar & particularly to have playerctld running
|
||||
"rofi" # menu/launcher
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.wpa_supplicant;
|
||||
in
|
||||
{
|
||||
config = lib.mkMerge [
|
||||
{
|
||||
sane.programs.wpa_supplicant = {
|
||||
packageUnwrapped = pkgs.wpa_supplicant.overrideAttrs (upstream: {
|
||||
# postPatch = (upstream.postPatch or "") + ''
|
||||
# substituteInPlace wpa_supplicant/dbus/dbus-wpa_supplicant.conf --replace-fail \
|
||||
# 'user="root"' 'user="networkmanager"'
|
||||
# '';
|
||||
postInstall = (upstream.postInstall or "") + ''
|
||||
substitute $out/share/dbus-1/system.d/dbus-wpa_supplicant.conf \
|
||||
$out/share/dbus-1/system.d/networkmanager-wpa_supplicant.conf \
|
||||
--replace-fail 'user="root"' 'group="networkmanager"'
|
||||
'';
|
||||
|
||||
postFixup = (upstream.postFixup or "") + ''
|
||||
# nixpkgs wpa_supplicant generates a dbus file which has a path like
|
||||
# /nix/store/abc-wpa_supplicant/nix/store/abc-wpa_supplicant/sbin/...
|
||||
# upstreaming status: <https://github.com/NixOS/nixpkgs/pull/315346>
|
||||
substituteInPlace $out/share/dbus-1/system-services/* --replace-fail \
|
||||
"$out$out" "$out"
|
||||
|
||||
# remove unused services to avoid unexpected interactions
|
||||
rm $out/etc/systemd/system/{wpa_supplicant-nl80211@,wpa_supplicant-wired@,wpa_supplicant@}.service
|
||||
'';
|
||||
});
|
||||
# bwrap sandboxing works, but requires the real user to be root.
|
||||
# landlock sandboxing works, and allows the real user to be someone else (like `networkmanager`).
|
||||
# non-root is very important, because of how many things in e.g. /dev are r/w based on uid=0.
|
||||
# sandbox.method = "bwrap";
|
||||
sandbox.method = "landlock";
|
||||
sandbox.capabilities = [
|
||||
# see also: <https://github.com/NixOS/nixpkgs/pull/305722>
|
||||
"net_admin" "net_raw"
|
||||
];
|
||||
# sandbox.extraConfig = [ "--sanebox-keep-namespace" "all" ];
|
||||
sandbox.net = "all";
|
||||
sandbox.extraPaths = [
|
||||
"/dev/net"
|
||||
"/dev/rfkill"
|
||||
"/proc/sys/net"
|
||||
"/sys/class/net"
|
||||
"/sys/devices"
|
||||
];
|
||||
sandbox.whitelistDbus = [ "system" ];
|
||||
};
|
||||
}
|
||||
(lib.mkIf cfg.enabled {
|
||||
#v TODO: networkmanager module enforces that it install this for us...
|
||||
# if i relly want to avoid that, maybe i implement some `apply` override for `environment.systemPackages`, & others
|
||||
# or switch to the `iwd` backend, which is more patchable.
|
||||
# services.udev.packages = [ cfg.package ];
|
||||
# systemd.packages = [ cfg.package ]; #< needs to be on systemd.packages so we get its service file
|
||||
systemd.services.wpa_supplicant = {
|
||||
path = [ "/run/current-system/sw" ]; #< so it can find `sanebox`
|
||||
serviceConfig.User = "networkmanager";
|
||||
serviceConfig.Group = "networkmanager";
|
||||
serviceConfig.AmbientCapabilities = [
|
||||
"CAP_NET_ADMIN"
|
||||
"CAP_NET_RAW"
|
||||
];
|
||||
};
|
||||
# systemd.services.wpa_supplicant = {
|
||||
# aliases = [ "dbus-fi.w1.wpa_supplicant1.service" ];
|
||||
# before = [ "network.target" ];
|
||||
# wantedBy = [ "network.target" ];
|
||||
# serviceConfig = {
|
||||
# Type = "dbus";
|
||||
# BusName = "fi.w1.wpa_supplicant1";
|
||||
# ExecStart = "${cfg.package}/bin/wpa_supplicant -u";
|
||||
# Restart = "always";
|
||||
# };
|
||||
# };
|
||||
})
|
||||
];
|
||||
}
|
Loading…
Reference in New Issue
Block a user