Compare commits
13 Commits
test-nm-ni
...
wip-nm-sys
Author | SHA1 | Date | |
---|---|---|---|
5ec159bbf5 | |||
f6725f60b9 | |||
2f1592376d | |||
42fed64b75 | |||
682143d47f | |||
1448cb4444 | |||
2d07ff966b | |||
83404f6769 | |||
c6bb6e2e3c | |||
9d109644b7 | |||
0050403b31 | |||
e4bcbab224 | |||
1b85aa0441 |
2
TODO.md
2
TODO.md
@@ -84,6 +84,8 @@
|
||||
|
||||
#### sudo-free world
|
||||
- `systemctl restart FOO`: needs `sudo`
|
||||
- `systemctl daemon-reload`: needs sudo
|
||||
- `watch ifconfig`: needs `SANEBOX_DISABLE=1`
|
||||
|
||||
### user experience
|
||||
- rofi: sort items case-insensitively
|
||||
|
24
flake.lock
generated
24
flake.lock
generated
@@ -167,11 +167,11 @@
|
||||
},
|
||||
"nixpkgs-next-unpatched": {
|
||||
"locked": {
|
||||
"lastModified": 1717243271,
|
||||
"narHash": "sha256-M3VxP6DtREz5Lq6MKg1gQ2EeVdIbq6AEp/N1tDSrvoc=",
|
||||
"lastModified": 1717372940,
|
||||
"narHash": "sha256-fK1PJqC8kQOy8rD7B+qmJOTx9IV8AOmFtH5Z/ip7340=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "f7de25c01e4c073c06e0525226a0c2311d530cee",
|
||||
"rev": "c987c730bbf2121264ebd68921b443db5bb28543",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -183,11 +183,11 @@
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1716655032,
|
||||
"narHash": "sha256-kQ25DAiCGigsNR/Quxm3v+JGXAEXZ8I7RAF4U94bGzE=",
|
||||
"lastModified": 1717265169,
|
||||
"narHash": "sha256-IITcGd6xpNoyq9SZBigCkv4+qMHSqot0RDPR4xsZ2CA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "59a450646ec8ee0397f5fa54a08573e8240eb91f",
|
||||
"rev": "3b1b4895b2c5f9f5544d02132896aeb9ceea77bc",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -199,11 +199,11 @@
|
||||
},
|
||||
"nixpkgs-unpatched": {
|
||||
"locked": {
|
||||
"lastModified": 1717242134,
|
||||
"narHash": "sha256-2X835ZESUaQ/KZEuG9HkoEB7h0USG5uvkSUmLzFkxAE=",
|
||||
"lastModified": 1717392304,
|
||||
"narHash": "sha256-i9Kh2ty++/xMj4GPTMI7vQrpH4jopjT4BUq2GKX1zug=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "61c1d282153dbfcb5fe413c228d172d0fe7c2a7e",
|
||||
"rev": "77a51024c0f953d503eb3ed364aa4bff378649f8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -254,11 +254,11 @@
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716692524,
|
||||
"narHash": "sha256-sALodaA7Zkp/JD6ehgwc0UCBrSBfB4cX66uFGTsqeFU=",
|
||||
"lastModified": 1717297459,
|
||||
"narHash": "sha256-cZC2f68w5UrJ1f+2NWGV9Gx0dEYmxwomWN2B0lx0QRA=",
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"rev": "962797a8d7f15ed7033031731d0bb77244839960",
|
||||
"rev": "ab2a43b0d21d1d37d4d5726a892f714eaeb4b075",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@@ -4,6 +4,8 @@
|
||||
imports = [
|
||||
./dns.nix
|
||||
./hostnames.nix
|
||||
./modemmanager.nix
|
||||
./networkmanager.nix
|
||||
./upnp.nix
|
||||
./vpn.nix
|
||||
];
|
||||
@@ -24,41 +26,4 @@
|
||||
# this is required separately by servo and by any `sane-vpn` users,
|
||||
# however Nix requires this be set centrally, in only one location (i.e. here)
|
||||
boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
|
||||
|
||||
# the default backend is "wpa_supplicant".
|
||||
# wpa_supplicant reliably picks weak APs to connect to.
|
||||
# see: <https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/474>
|
||||
# iwd is an alternative that shouldn't have this problem
|
||||
# docs:
|
||||
# - <https://nixos.wiki/wiki/Iwd>
|
||||
# - <https://iwd.wiki.kernel.org/networkmanager>
|
||||
# - `man iwd.config` for global config
|
||||
# - `man iwd.network` for per-SSID config
|
||||
# use `iwctl` to control
|
||||
# networking.networkmanager.wifi.backend = "iwd";
|
||||
# networking.wireless.iwd.enable = true;
|
||||
# networking.wireless.iwd.settings = {
|
||||
# # auto-connect to a stronger network if signal drops below this value
|
||||
# # bedroom -> bedroom connection is -35 to -40 dBm
|
||||
# # bedroom -> living room connection is -60 dBm
|
||||
# General.RoamThreshold = "-52"; # default -70
|
||||
# General.RoamThreshold5G = "-52"; # default -76
|
||||
# };
|
||||
|
||||
# plugins mostly add support for establishing different VPN connections.
|
||||
# the default plugin set includes mostly proprietary VPNs:
|
||||
# - fortisslvpn (Fortinet)
|
||||
# - iodine (DNS tunnels)
|
||||
# - l2tp
|
||||
# - openconnect (Cisco Anyconnect / Juniper / ocserv)
|
||||
# - openvpn
|
||||
# - vpnc (Cisco VPN)
|
||||
# - sstp
|
||||
#
|
||||
# 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 [];
|
||||
|
||||
# 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 ];
|
||||
}
|
213
hosts/common/net/networkmanager.nix
Normal file
213
hosts/common/net/networkmanager.nix
Normal file
@@ -0,0 +1,213 @@
|
||||
{ config, pkgs, ... }:
|
||||
let
|
||||
# networkmanager = pkgs.networkmanager;
|
||||
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.48.0";
|
||||
hash = "sha256-vGmOKtwVItxjYioZJlb1og3K6u9s4rcmDnjAPLBC3ao=";
|
||||
};
|
||||
# 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;
|
||||
# plugins mostly add support for establishing different VPN connections.
|
||||
# the default plugin set includes mostly proprietary VPNs:
|
||||
# - fortisslvpn (Fortinet)
|
||||
# - iodine (DNS tunnels)
|
||||
# - l2tp
|
||||
# - openconnect (Cisco Anyconnect / Juniper / ocserv)
|
||||
# - openvpn
|
||||
# - vpnc (Cisco VPN)
|
||||
# - sstp
|
||||
#
|
||||
# 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.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"
|
||||
];
|
||||
serviceConfig.LockPersonality = true;
|
||||
serviceConfig.PrivateDevices = true; # remount /dev with just the basics, syscall filter to block @raw-io
|
||||
serviceConfig.PrivateIPC = true;
|
||||
serviceConfig.PrivateUsers = true; # TODO: might break hooks?
|
||||
serviceConfig.ProtectClock = true; # syscall filter to prevent changing the RTC
|
||||
serviceConfig.ProtectControlGroups = true;
|
||||
serviceConfig.ProtectHome = true; # makes empty: /home, /root, /run/user
|
||||
serviceConfig.ProtectHostname = true; # probably not upstreamable: prevents changing hostname
|
||||
serviceConfig.ProtectKernelLogs = true; # disable /proc/kmsg, /dev/kmsg
|
||||
serviceConfig.ProtectKernelModules = true; # syscall filter to prevent module calls
|
||||
# ProtectKernelTunables = true; # but NM might need to write /proc/sys/net/...
|
||||
serviceConfig.ProtectSystem = "full"; # makes read-only: /boot, /etc/, /usr. TODO: "strict" would make all but /dev, /proc, /sys inaccessible.
|
||||
# serviceConfig.RestrictAddressFamilies = TODO
|
||||
serviceConfig.RestrictSUIDSGID = true;
|
||||
serviceConfig.SystemCallArchitectures = "native"; # prevents e.g. aarch64 syscalls in the event that the kernel is multi-architecture.
|
||||
# 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 = {
|
||||
# keyfile.path = where networkmanager should look for connection credentials
|
||||
keyfile.path = "/var/lib/NetworkManager/system-connections";
|
||||
|
||||
# wifi.backend = "wpa_supplicant"; #< default
|
||||
# wifi.scan-rand-mac-address = true; #< default
|
||||
|
||||
# logging.audit = false; #< default
|
||||
logging.level = "INFO";
|
||||
|
||||
# main.dhcp = "internal"; #< default
|
||||
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";
|
||||
|
||||
# the default backend is "wpa_supplicant".
|
||||
# wpa_supplicant reliably picks weak APs to connect to.
|
||||
# see: <https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/474>
|
||||
# iwd is an alternative that shouldn't have this problem
|
||||
# docs:
|
||||
# - <https://nixos.wiki/wiki/Iwd>
|
||||
# - <https://iwd.wiki.kernel.org/networkmanager>
|
||||
# - `man iwd.config` for global config
|
||||
# - `man iwd.network` for per-SSID config
|
||||
# use `iwctl` to control
|
||||
# networking.networkmanager.wifi.backend = "iwd";
|
||||
# networking.wireless.iwd.enable = true;
|
||||
# networking.wireless.iwd.settings = {
|
||||
# # auto-connect to a stronger network if signal drops below this value
|
||||
# # bedroom -> bedroom connection is -35 to -40 dBm
|
||||
# # bedroom -> living room connection is -60 dBm
|
||||
# General.RoamThreshold = "-52"; # default -70
|
||||
# General.RoamThreshold5G = "-52"; # default -76
|
||||
# };
|
||||
|
||||
# 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 "") + ''
|
||||
# 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,81 +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"
|
||||
];
|
||||
};
|
||||
|
||||
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 = "${lib.getExe cfg.package} --debug";
|
||||
# --debug sets DEBUG level logging: so reset
|
||||
serviceConfig.ExecStartPost = "${lib.getExe config.sane.programs.mmcli.package} --set-logging=INFO";
|
||||
|
||||
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,209 +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 ];
|
||||
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";
|
||||
};
|
||||
|
||||
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.
|
||||
''
|
||||
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,77 +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 {
|
||||
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";
|
||||
# };
|
||||
# };
|
||||
})
|
||||
];
|
||||
}
|
@@ -33,17 +33,23 @@ in [
|
||||
# and can be found with `nix-repl > :lf . > lastModifiedDate`
|
||||
|
||||
(fetchpatch' {
|
||||
title = "trust-dns: rebrand as hickory-dns";
|
||||
saneCommit = "a7613d50c58b5612a7b806ce1375d8bf0485ab55";
|
||||
hash = "sha256-N4DfNhCeg9etVeTPVzJ73CwiZzf43SozK8nrfXIm0uQ=";
|
||||
title = "networkmanager: 1.46.0 → 1.48.0";
|
||||
prUrl = "https://github.com/NixOS/nixpkgs/pull/316417";
|
||||
hash = "sha256-LfQyB3tzQa3UNyZl9HWCuoyBznIhinodlTL6TnPn0Uk=";
|
||||
})
|
||||
|
||||
(fetchpatch' {
|
||||
title = "libphonenumber: fix cross compilation";
|
||||
prUrl = "https://github.com/NixOS/nixpkgs/pull/316094";
|
||||
saneCommit = "151fb5ea9c43847dbd114cb80c04ce7118fef95d";
|
||||
# hash = "sha256-dvgpuldhBlSrpwkqNEtgAHqhaGsrMwoAT+Q5J27NYrQ=";
|
||||
hash = "sha256-N8ZA/93qTmrCE9eE8VPgkXD/ciTOHdD5zRz9JJLU5gA=";
|
||||
title = "nixos/networkmanager: split ModemManager bits into own module";
|
||||
prUrl = "https://github.com/NixOS/nixpkgs/pull/316824";
|
||||
hash = "sha256-u0hd2VfEcqkhs4xgv1gF6sXqnVJYVRgmSKBrmYUw29c=";
|
||||
# saneCommit = "23bfba9b76757ffc00fc2be810009dcf92e2eaf2";
|
||||
# hash = "sha256-cn6ihwO3MyzdpVoJoQNKAHyo8GuGvFP6vr//7r9pzjE=";
|
||||
})
|
||||
|
||||
(fetchpatch' {
|
||||
title = "trust-dns: rebrand as hickory-dns";
|
||||
saneCommit = "a7613d50c58b5612a7b806ce1375d8bf0485ab55";
|
||||
hash = "sha256-N4DfNhCeg9etVeTPVzJ73CwiZzf43SozK8nrfXIm0uQ=";
|
||||
})
|
||||
|
||||
(fetchpatch' {
|
||||
|
@@ -52,7 +52,6 @@ stdenv.mkDerivation {
|
||||
meta = with lib; {
|
||||
description = "The Linux-phone camera application";
|
||||
homepage = "https://gitlab.com/megapixels-org/Megapixels";
|
||||
changelog = "https://gitlab.com/megapixels-org/Megapixels/-/tags/${finalAttrs.version}";
|
||||
license = licenses.gpl3Plus;
|
||||
maintainers = with maintainers; [ colinsane ];
|
||||
platforms = platforms.linux;
|
||||
|
@@ -7,8 +7,10 @@ shift
|
||||
host="$(hostname)"
|
||||
if [ "$host" = "$target" ]
|
||||
then
|
||||
# N.B.: anything other than just `reboot` with no args requires `sudo` privilegs (to write to /run/systemd/)
|
||||
reboot "$@"
|
||||
# N.B.: anything other than just `reboot` with no args requires `sudo` privileges (to write to /run/systemd/).
|
||||
# `systemctl reboot -i` tells systemd to ignore inhibitors (i.e. other users logged in).
|
||||
reboot "$@" || \
|
||||
systemctl reboot -i "$@"
|
||||
else
|
||||
echo "WRONG MACHINE. you're on $host."
|
||||
exit 1
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p curl -p dig -p iputils -p lftp
|
||||
#!nix-shell -i bash -p curl -p dig -p iputils -p lftp -p openssh
|
||||
|
||||
echo "this script will check that uninsane.org is baseline operational"
|
||||
echo "it doesn't check all services, just the most critical ones"
|
||||
@@ -45,6 +45,10 @@ check "git.uninsane.org" git ls-remote origin --quiet
|
||||
|
||||
check "ftp://uninsane.org" lftpget ftp://uninsane.org/README.md && rm README.md
|
||||
|
||||
echo ""
|
||||
echo "systemctl --failed:"
|
||||
ssh uninsane.org systemctl -q --failed
|
||||
|
||||
echo ""
|
||||
if [ $last_error -eq 0 ]; then
|
||||
echo "SUCCESS"
|
||||
|
35
scripts/update
Executable file
35
scripts/update
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/bin/sh
|
||||
|
||||
inputs=()
|
||||
addInputs() {
|
||||
case $1 in
|
||||
(safe)
|
||||
inputs+=(uninsane-dot-org nixpkgs-unpatched nixpkgs-next-unpatched sops-nix)
|
||||
;;
|
||||
(unsafe)
|
||||
# these tend to break more frequently
|
||||
inputs+=(mobile-nixos nixpkgs-wayland)
|
||||
;;
|
||||
(*)
|
||||
echo "unknown input '$1'"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
(all|"")
|
||||
addInputs "safe"
|
||||
addInputs "unsafe"
|
||||
;;
|
||||
(*)
|
||||
addInputs "$1"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "updating:" "${inputs[@]}"
|
||||
nixFlags=()
|
||||
for i in "${inputs[@]}"; do
|
||||
nixFlags+=("--update-input" "$i")
|
||||
done
|
||||
nix flake lock "${nixFlags[@]}"
|
Reference in New Issue
Block a user