Skip to content

Instantly share code, notes, and snippets.

@Ma27
Last active November 17, 2022 12:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ma27/fc3e2bfcdd0aba7e65552a97189d7715 to your computer and use it in GitHub Desktop.
Save Ma27/fc3e2bfcdd0aba7e65552a97189d7715 to your computer and use it in GitHub Desktop.
IWD Declarative Networks with NixOS (Patch)
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/&lt;name&gt;.&lt;type&gt;</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