-
-
Save Ma27/fc3e2bfcdd0aba7e65552a97189d7715 to your computer and use it in GitHub Desktop.
IWD Declarative Networks with NixOS (Patch)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/0001-Prohibit-modification-of-SSIDs-that-were-added-by-Ni.patch b/0001-Prohibit-modification-of-SSIDs-that-were-added-by-Ni.patch | |
new file mode 100644 | |
index 00000000000..51321106ed6 | |
--- /dev/null | |
+++ b/0001-Prohibit-modification-of-SSIDs-that-were-added-by-Ni.patch | |
@@ -0,0 +1,82 @@ | |
+From b480ee3586625d01da9faf464fb110e861e521fd Mon Sep 17 00:00:00 2001 | |
+From: Maximilian Bosch <maximilian@mbosch.me> | |
+Date: Fri, 2 Oct 2020 23:51:37 +0200 | |
+Subject: [PATCH] Prohibit modification of SSIDs that were added by NixOS | |
+ | |
+--- | |
+ src/dbus.c | 6 ++++++ | |
+ src/dbus.h | 1 + | |
+ src/network.c | 28 ++++++++++++++++++++++++++++ | |
+ 3 files changed, 35 insertions(+) | |
+ | |
+diff --git a/src/dbus.c b/src/dbus.c | |
+index ceede5c..f8b8109 100644 | |
+--- a/src/dbus.c | |
++++ b/src/dbus.c | |
+@@ -114,6 +114,12 @@ struct l_dbus_message *dbus_error_not_supported(struct l_dbus_message *msg) | |
+ "Operation not supported"); | |
+ } | |
+ | |
++struct l_dbus_message *dbus_error_file_is_a_nix_store_path(struct l_dbus_message *msg, char *ssid) | |
++{ | |
++ return l_dbus_message_new_error(msg, IWD_SERVICE ".NotSupportNixOS", | |
++ "Cannot update SSID %s as it's configured in a file that points to a store path! Please update your NixOS config accordingly!", ssid); | |
++} | |
++ | |
+ struct l_dbus_message *dbus_error_no_agent(struct l_dbus_message *msg) | |
+ { | |
+ return l_dbus_message_new_error(msg, IWD_SERVICE ".NoAgent", | |
+diff --git a/src/dbus.h b/src/dbus.h | |
+index 045b1bc..3c10ab5 100644 | |
+--- a/src/dbus.h | |
++++ b/src/dbus.h | |
+@@ -62,6 +62,7 @@ struct l_dbus_message *dbus_error_invalid_format(struct l_dbus_message *msg); | |
+ struct l_dbus_message *dbus_error_already_exists(struct l_dbus_message *msg); | |
+ struct l_dbus_message *dbus_error_not_found(struct l_dbus_message *msg); | |
+ struct l_dbus_message *dbus_error_not_supported(struct l_dbus_message *msg); | |
++struct l_dbus_message *dbus_error_file_is_a_nix_store_path(struct l_dbus_message *msg, char *ssid); | |
+ struct l_dbus_message *dbus_error_no_agent(struct l_dbus_message *msg); | |
+ struct l_dbus_message *dbus_error_not_connected(struct l_dbus_message *msg); | |
+ struct l_dbus_message *dbus_error_not_configured(struct l_dbus_message *msg); | |
+diff --git a/src/network.c b/src/network.c | |
+index a7d59ca..38c2efb 100644 | |
+--- a/src/network.c | |
++++ b/src/network.c | |
+@@ -853,6 +853,34 @@ static struct l_dbus_message *network_connect_psk(struct network *network, | |
+ network->ask_passphrase ? "true" : "false"); | |
+ | |
+ if (network->ask_passphrase) { | |
++ FILE *handle; | |
++ handle = fopen("/var/lib/iwd/.declarative-nixos-networks", "r"); | |
++ char *line = NULL; | |
++ size_t at = 0; | |
++ if (handle != NULL && network->info != NULL) { | |
++ char *cfgpath_ = network->info->ops->get_file_path(network->info); | |
++ char *cfgpath = calloc(1, PATH_MAX); | |
++ if (realpath(cfgpath_, cfgpath) != NULL) { | |
++ char *tocheck = calloc(1, PATH_MAX); | |
++ while (getline(&line, &at, handle) != -1) { | |
++ *index(line, '\n') = '\0'; | |
++ snprintf(tocheck, PATH_MAX - 1, "/var/lib/iwd/%s", line); | |
++ if (strcmp(tocheck, cfgpath) == 0) { | |
++ free(tocheck); | |
++ free(line); | |
++ free(cfgpath); | |
++ fclose(handle); | |
++ | |
++ return dbus_error_file_is_a_nix_store_path(message, network->ssid); | |
++ } | |
++ } | |
++ free(tocheck); | |
++ } | |
++ free(cfgpath); | |
++ free(line); | |
++ fclose(handle); | |
++ } | |
++ | |
+ network->ask_passphrase = false; | |
+ | |
+ network->agent_request = | |
+-- | |
+2.28.0 | |
+ | |
diff --git a/lib/types.nix b/lib/types.nix | |
index 77105740bc2..44da71ecbc5 100644 | |
--- a/lib/types.nix | |
+++ b/lib/types.nix | |
@@ -223,6 +223,17 @@ rec { | |
merge = mergeEqualOption; | |
}; | |
+ fixedLengthString = n: lengthCheckedString n n; | |
+ | |
+ lengthCheckedString = min: max: mkOptionType { | |
+ name = "str-with-min-${toString min}-and-max-${toString max}-chars"; | |
+ description = if min == max | |
+ then "string with exactly ${toString min} chars." | |
+ else "string which must have at least ${toString min} and at most ${toString max} chars."; | |
+ inherit (types.str) merge; | |
+ check = x: isString x && stringLength x >= min && stringLength x <= max; | |
+ }; | |
+ | |
str = mkOptionType { | |
name = "str"; | |
description = "string"; | |
diff --git a/nixos/modules/services/networking/iwd.nix b/nixos/modules/services/networking/iwd.nix | |
index 6be67a8b96f..8d5d893cff7 100644 | |
--- a/nixos/modules/services/networking/iwd.nix | |
+++ b/nixos/modules/services/networking/iwd.nix | |
@@ -4,8 +4,110 @@ with lib; | |
let | |
cfg = config.networking.wireless.iwd; | |
+ | |
+ declarativeNetworks = pkgs.writeText "declarative-nixos-networks" (concatStringsSep "\n" (mapAttrsToList (ssid: cfg: "${ssid}.${cfg.kind}") cfg.networks)); | |
+ | |
+ encoder = pkgs.writeScriptBin "encoder" '' | |
+ #! ${pkgs.runtimeShell} -e | |
+ | |
+ # Extract file-ext from network names | |
+ ext="$(sed -re 's/.*\.(8021x|open|psk)$/\1/' <<< "$*")" | |
+ to_enc="$(sed -re "s/(.*)\.$ext/\1/g" <<< "$*")" | |
+ | |
+ # Encode ssid (excluding file-extensio) as base64 if needed | |
+ [[ "$to_enc" =~ ^[[:alnum:]]+$ ]] && { echo "$to_enc.$ext"; exit 0; } | |
+ echo "=$(printf "$to_enc" | ${pkgs.unixtools.xxd}/bin/xxd -pu).$ext" | |
+ ''; | |
in { | |
- options.networking.wireless.iwd.enable = mkEnableOption "iwd"; | |
+ options.networking.wireless.iwd = { | |
+ enable = mkEnableOption "iwd"; | |
+ | |
+ interfaces = mkOption { | |
+ type = types.nullOr (types.listOf types.str); | |
+ example = literalExample '' | |
+ [ "wlp2s0" ] | |
+ ''; | |
+ default = null; | |
+ description = '' | |
+ List of interfaces to use. | |
+ ''; | |
+ }; | |
+ | |
+ networks = mkOption { | |
+ default = {}; | |
+ example = literalExample '' | |
+ { "karlsruhe.freifunk.net" = {}; | |
+ "secured".passphrase = "12345678"; | |
+ "network-with-psk".psk = "bf4c086e055e492373a0f59ff614f61fc2d597a56db94e17a165f9ef1d42c066"; | |
+ }; | |
+ ''; | |
+ | |
+ description = '' | |
+ Declarative configuration of wifi networks for | |
+ <citerefentry><refentrytitle>iwd</refentrytitle><manvolnum>8</manvolnum></citerefentry>. | |
+ | |
+ All networks will be stored in | |
+ <literal>/var/lib/iwd/<name>.<type></literal>. | |
+ | |
+ Since each network is stored in its own file, declarative networks can be used in an | |
+ environment with imperatively added networks via | |
+ <citerefentry><refentrytitle>iwctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>. | |
+ ''; | |
+ | |
+ type = types.attrsOf (types.submodule ({ config, ... }: { | |
+ config.kind = if config.eapConfig != null then "8021x" | |
+ else if (config.psk != null || config.passphrase != null) then "psk" | |
+ else "open"; | |
+ | |
+ options = { | |
+ kind = mkOption { | |
+ internal = true; | |
+ readOnly = true; | |
+ type = types.enum [ "open" "psk" "8021x" ]; | |
+ }; | |
+ | |
+ eapConfig = mkOption { | |
+ type = with types; nullOr (attrsOf (oneOf [ str path ])); | |
+ default = null; | |
+ }; | |
+ | |
+ psk = mkOption { | |
+ type = with types; nullOr (oneOf [ str path ]); | |
+ default = null; | |
+ description = '' | |
+ WPA PSK for the currently defined network. This can be generated by using | |
+ <citerefentry><refentrytitle>wpa_passphrase</refentrytitle><manvolnum>8</manvolnum></citerefentry>. | |
+ ''; | |
+ }; | |
+ | |
+ passphrase = mkOption { | |
+ type = with types; nullOr (oneOf [ str path ]); | |
+ default = null; | |
+ description = '' | |
+ Raw passphrase for the currently defined network. | |
+ ''; | |
+ }; | |
+ | |
+ autoConnect = mkOption { | |
+ default = true; | |
+ type = types.bool; | |
+ description = '' | |
+ Disable automatic connection to the network. | |
+ ''; | |
+ }; | |
+ | |
+ hidden = mkOption { | |
+ default = false; | |
+ type = types.bool; | |
+ description = '' | |
+ Used for hidden networks that don't respond to scans unless | |
+ their SSID is explicitly specified. | |
+ ''; | |
+ }; | |
+ }; | |
+ })); | |
+ }; | |
+ }; | |
config = mkIf cfg.enable { | |
assertions = [{ | |
@@ -13,7 +115,18 @@ in { | |
message = '' | |
Only one wireless daemon is allowed at the time: networking.wireless.enable and networking.wireless.iwd.enable are mutually exclusive. | |
''; | |
- }]; | |
+ }] ++ (flatten (flip mapAttrsToList cfg.networks (name: value: [ | |
+ { assertion = with value; psk != null -> passphrase == null; | |
+ message = '' | |
+ `psk` and `passphrase` are mutually exclusive! | |
+ ''; | |
+ } | |
+ { assertion = with value; eapConfig != null -> psk == null && passphrase == null; | |
+ message = '' | |
+ `psk` and `passphrase` must be undeclared if `eapConfig` is defined! | |
+ ''; | |
+ } | |
+ ]))); | |
# for iwctl | |
environment.systemPackages = [ pkgs.iwd ]; | |
@@ -22,8 +135,47 @@ in { | |
systemd.packages = [ pkgs.iwd ]; | |
- systemd.services.iwd.wantedBy = [ "multi-user.target" ]; | |
+ systemd.services.iwd = mkMerge [ | |
+ { wantedBy = [ "multi-user.target" ]; | |
+ serviceConfig.ExecStart = mkIf (cfg.interfaces != null) [ | |
+ "" | |
+ "${pkgs.iwd}/libexec/iwd -i ${concatStringsSep " -i " cfg.interfaces}" | |
+ ]; | |
+ } | |
+ (mkIf (cfg.networks != {}) { | |
+ path = [ encoder ]; | |
+ preStart = let | |
+ dataDir = "/var/lib/iwd"; | |
+ stateFile = "${dataDir}/.declarative-nixos-networks"; | |
+ in '' | |
+ # Remove declaratively defined networks and re-create those after that. | |
+ if [ -f ${stateFile} ]; then | |
+ xargs encoder < ${stateFile} | xargs -I {} rm -f ${dataDir}/{} | |
+ fi | |
+ | |
+ # Update the list of declaratively defined networks. | |
+ xargs encoder < ${declarativeNetworks} > ${stateFile} | |
+ | |
+ # Create config files for declaratively defined networks in the NixOS config. | |
+ ${concatStringsSep "\n" (flip mapAttrsToList cfg.networks (network: config: '' | |
+ filename=${dataDir}/"$(encoder '${network}.${config.kind}')" | |
+ touch "$filename" | |
+ cat >$filename <<EOF | |
+ [Security] | |
+ ${optionalString (config.passphrase != null) "Passphrase=$(<${config.passphrase})"} | |
+ ${optionalString (config.psk != null) "PreSharedKey=$(<${config.psk})"} | |
+ ${optionalString (config.eapConfig != null) (concatStrings (flip mapAttrsToList config.eapConfig (k: v: '' | |
+ ${k}=${if builtins.isPath v then "$(<${toString v})" else v} | |
+ '')))} | |
+ [Settings] | |
+ AutoConnect=${boolToString config.autoConnect} | |
+ Hidden=${boolToString config.hidden} | |
+ EOF | |
+ ''))} | |
+ ''; | |
+ }) | |
+ ]; | |
}; | |
- meta.maintainers = with lib.maintainers; [ mic92 dtzWill ]; | |
+ meta.maintainers = with lib.maintainers; [ mic92 dtzWill ma27 ]; | |
} | |
diff --git a/pkgs/os-specific/linux/ell/default.nix b/pkgs/os-specific/linux/ell/default.nix | |
index 9faeb831b4b..8d2eeb3ecaa 100644 | |
--- a/pkgs/os-specific/linux/ell/default.nix | |
+++ b/pkgs/os-specific/linux/ell/default.nix | |
@@ -30,6 +30,9 @@ stdenv.mkDerivation rec { | |
dbus | |
]; | |
+ configureFlags = [ "--enable-debug" "--disable-optimization" ]; | |
+ dontStrip = true; | |
+ | |
enableParallelBuilding = true; | |
doCheck = true; | |
diff --git a/pkgs/os-specific/linux/iwd/0001-agent-network_connect_psk-check-if-the-config-file-f.patch b/pkgs/os-specific/linux/iwd/0001-agent-network_connect_psk-check-if-the-config-file-f.patch | |
new file mode 100644 | |
index 00000000000..25341f3d034 | |
--- /dev/null | |
+++ b/pkgs/os-specific/linux/iwd/0001-agent-network_connect_psk-check-if-the-config-file-f.patch | |
@@ -0,0 +1,72 @@ | |
+From bd0a222cca9973d7662a92c794ae04b40c29d914 Mon Sep 17 00:00:00 2001 | |
+From: Maximilian Bosch <maximilian@mbosch.me> | |
+Date: Thu, 30 Jul 2020 00:43:20 +0200 | |
+Subject: [PATCH] agent/network_connect_psk: check if the config-file for the | |
+ SSID points to a store path | |
+ | |
+If the network is declaratively configured by NixOS, it must not be | |
+modified imperatively. | |
+--- | |
+ src/dbus.c | 6 ++++++ | |
+ src/dbus.h | 1 + | |
+ src/network.c | 14 +++++++++++++- | |
+ 3 files changed, 20 insertions(+), 1 deletion(-) | |
+ | |
+diff --git a/src/dbus.c b/src/dbus.c | |
+index ceede5c..f8b8109 100644 | |
+--- a/src/dbus.c | |
++++ b/src/dbus.c | |
+@@ -114,6 +114,12 @@ struct l_dbus_message *dbus_error_not_supported(struct l_dbus_message *msg) | |
+ "Operation not supported"); | |
+ } | |
+ | |
++struct l_dbus_message *dbus_error_file_is_a_nix_store_path(struct l_dbus_message *msg, char *ssid) | |
++{ | |
++ return l_dbus_message_new_error(msg, IWD_SERVICE ".NotSupportNixOS", | |
++ "Cannot update SSID %s as it's configured in a file that points to a store path! Please update your NixOS config accordingly!", ssid); | |
++} | |
++ | |
+ struct l_dbus_message *dbus_error_no_agent(struct l_dbus_message *msg) | |
+ { | |
+ return l_dbus_message_new_error(msg, IWD_SERVICE ".NoAgent", | |
+diff --git a/src/dbus.h b/src/dbus.h | |
+index ebae85d..adb0241 100644 | |
+--- a/src/dbus.h | |
++++ b/src/dbus.h | |
+@@ -59,6 +59,7 @@ struct l_dbus_message *dbus_error_invalid_format(struct l_dbus_message *msg); | |
+ struct l_dbus_message *dbus_error_already_exists(struct l_dbus_message *msg); | |
+ struct l_dbus_message *dbus_error_not_found(struct l_dbus_message *msg); | |
+ struct l_dbus_message *dbus_error_not_supported(struct l_dbus_message *msg); | |
++struct l_dbus_message *dbus_error_file_is_a_nix_store_path(struct l_dbus_message *msg, char *ssid); | |
+ struct l_dbus_message *dbus_error_no_agent(struct l_dbus_message *msg); | |
+ struct l_dbus_message *dbus_error_not_connected(struct l_dbus_message *msg); | |
+ struct l_dbus_message *dbus_error_not_configured(struct l_dbus_message *msg); | |
+diff --git a/src/network.c b/src/network.c | |
+index 70541b5..d510f5e 100644 | |
+--- a/src/network.c | |
++++ b/src/network.c | |
+@@ -851,8 +851,20 @@ static struct l_dbus_message *network_connect_psk(struct network *network, | |
+ | |
+ l_debug("ask_passphrase: %s", | |
+ network->ask_passphrase ? "true" : "false"); | |
+- | |
+ if (network->ask_passphrase) { | |
++ char store_dir[] = "@storeDir@"; | |
++ char full_path[PATH_MAX]; | |
++ char *cfgpath; | |
++ if (network->info != NULL) { | |
++ cfgpath = network->info->ops->get_file_path(network->info); | |
++ int ret = readlink(cfgpath, full_path, sizeof(full_path)); | |
++ l_free(cfgpath); | |
++ | |
++ if (ret != -1 && strncmp(full_path, store_dir, strlen(store_dir)) == 0) { | |
++ return dbus_error_file_is_a_nix_store_path(message, network->ssid); | |
++ } | |
++ } | |
++ | |
+ network->ask_passphrase = false; | |
+ | |
+ network->agent_request = | |
+-- | |
+2.25.4 | |
+ | |
diff --git a/pkgs/os-specific/linux/iwd/default.nix b/pkgs/os-specific/linux/iwd/default.nix | |
index adf37a1b71b..92dc93da35a 100644 | |
--- a/pkgs/os-specific/linux/iwd/default.nix | |
+++ b/pkgs/os-specific/linux/iwd/default.nix | |
@@ -9,20 +9,29 @@ | |
, readline | |
, openssl | |
, python3Packages | |
+, substituteAll | |
}: | |
stdenv.mkDerivation rec { | |
pname = "iwd"; | |
version = "1.9"; | |
- src = fetchgit { | |
- url = "https://git.kernel.org/pub/scm/network/wireless/iwd.git"; | |
- rev = version; | |
- sha256 = "193wa13i2prfz1zr7nvwbgrxgacms57zj1n7x28yy5hmm3nnwbrd"; | |
- }; | |
+ src = ~/Projects/nixpkgs/iwd; | |
+ #src = fetchgit { | |
+ #url = "https://git.kernel.org/pub/scm/network/wireless/iwd.git"; | |
+ #rev = version; | |
+ #sha256 = "193wa13i2prfz1zr7nvwbgrxgacms57zj1n7x28yy5hmm3nnwbrd"; | |
+ #}; | |
outputs = [ "out" "man" ]; | |
+ #patches = [ | |
+ #(substituteAll { | |
+ #src = ./0001-agent-network_connect_psk-check-if-the-config-file-f.patch; | |
+ #inherit (builtins) storeDir; | |
+ #}) | |
+ #]; | |
+ | |
nativeBuildInputs = [ | |
autoreconfHook | |
docutils | |
@@ -52,9 +61,12 @@ stdenv.mkDerivation rec { | |
"--with-systemd-modloaddir=${placeholder "out"}/etc/modules-load.d/" # maybe | |
"--with-systemd-unitdir=${placeholder "out"}/lib/systemd/system/" | |
"--with-systemd-networkdir=${placeholder "out"}/lib/systemd/network/" | |
+ "--enable-debug" "--disable-optimization" | |
]; | |
- postUnpack = '' | |
+ dontStrip = true; | |
+ | |
+ postPatch = '' | |
patchShebangs . | |
''; | |
@@ -85,6 +97,6 @@ stdenv.mkDerivation rec { | |
description = "Wireless daemon for Linux"; | |
license = licenses.lgpl21; | |
platforms = platforms.linux; | |
- maintainers = with maintainers; [ dtzWill fpletz ]; | |
+ maintainers = with maintainers; [ dtzWill fpletz ma27 ]; | |
}; | |
} | |
diff --git a/snens.nix b/snens.nix | |
new file mode 100644 | |
index 00000000000..f4d74af7d72 | |
--- /dev/null | |
+++ b/snens.nix | |
@@ -0,0 +1,17 @@ | |
+import ./nixos/lib/eval-config.nix { | |
+ modules = [ | |
+ ({ pkgs, ... }: { | |
+ imports = [ ./nixos/modules/installer/cd-dvd/installation-cd-base.nix ]; | |
+ | |
+ networking.wireless.enable = false; | |
+ environment.systemPackages = [ pkgs.wpa_supplicant pkgs.gdb ]; | |
+ networking.wireless.iwd = { | |
+ enable = true; | |
+ interfaces = [ "wlp3s0" ]; | |
+ networks = { | |
+ echelon.passphrase = "/etc/echelon"; | |
+ }; | |
+ }; | |
+ }) | |
+ ]; | |
+} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment