Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos/iwd: add networks and interfaces option #75800

Closed
wants to merge 4 commits into from

Conversation

Ma27
Copy link
Member

@Ma27 Ma27 commented Dec 16, 2019

Motivation for this change

This change adds support for declarative networks with iwd(8), similar
to networking.wireless.networks and an interfaces option which tells
the service which to use (by default, the interfaces will be found
automatically).

In contrast to the wpa_supplicant module it's still possible to
add additional networks imperatively using iwctl(1) since all networks
are stored as separated files in /var/lib/iwd.

Please note that this change doesn't add support for 802.1x networks[1]
as this would currently mean that we'd have to store sensitive secrets
for those networks world-readably in the Nix-store. It's recommended to
add those networks imperatively.

This module supports open networks and networks with a WPA PSK or a raw
passphrase. If a SSID doesn't contain alphanumeric chars and -_ only,
the network-configuration will be stored as =<hex-encoded-version>.<ext>
in /var/lib/iwd.

[1] https://iwd.wiki.kernel.org/networkconfigurationsettings#x_wpawpa2_enterprise_settings

Things done
  • Tested using sandboxing (nix.useSandbox on NixOS, or option sandbox in nix.conf on non-NixOS linux)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nix-review --run "nix-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Determined the impact on package closure size (by running nix path-info -S before and after)
  • Ensured that relevant documentation is up to date
  • Fits CONTRIBUTING.md.
Notify maintainers

cc @

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/prs-ready-for-review-may-2019/3032/99

@Ma27 Ma27 requested review from Mic92 and fpletz February 2, 2020 06:52
@Ma27 Ma27 force-pushed the declarative-networks-with-iwd branch from 8dc95de to 287febb Compare February 11, 2020 13:38
@Ma27
Copy link
Member Author

Ma27 commented Feb 11, 2020

As discussed with @fpletz, we should ensure that iwd doesn't override SSID-configs managed by Nix. I added a patch which ensures that this doesn't happen if the file to update in /var/lib/iwd points to a store path.

description = ''
List of interfaces to use.
'';
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the interfaces change be done separately?
It's not needed for the network changes at all AFAICT so it's easily separated.
The reason is iwd and interface handling, especially naming, might need some careful work.

  • Interface strings: interaction and reliance on use of usePredictableInterfaceNames
  • Implications re:iwd's UseDefaultInterface (and the shipped .link file).
  • (Is there some existing interface abstraction we should be tying to?)
  • The service, I think?, if used with particular interfaces maybe should: wants, requires sys-subsystem-net-devices-${ifacename-escaped-for-systemd} (not sure)
  • iwd's help doesn't tell you, but my reading of the code in src/manager.c suggests the interface list is comma-separated not space-separated, FWIW

All said, what's the use for specifying interfaces explicitly anyway? Just curious :).

And the rest is exciting and I think close to merge-ready, hence the suggestion for splitting off the interface-related bits.
Thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All said, what's the use for specifying interfaces explicitly anyway? Just curious :).

It might be possible that I'm missing something, but iwd constantly tried to use wlan0 by default which doesn't even exist on my system.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dtzWill any updates here?

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;
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wishlist: some sort of test to ensure this all works as expected--at least to catch complete breakage. Are these details re:knownnetworks population something likely to stay the same? I suspect so, but interested if anyone has better information on this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a good suggestion how to test wireless stuff in a VM test? Otherwise I'm currently not sure how to implement this :/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dtzWill do you have an idea how to integration-test wifi connectivity? Or would it be sufficient from your PoV to check if the known-networks cmd detects the declaratively specified networks?

(the full integration-test may be helpful to test my additional patch btw since this testing it against new iwd versions always takes some time).

nixos/modules/services/networking/iwd.nix Outdated Show resolved Hide resolved
nixos/modules/services/networking/iwd.nix Outdated Show resolved Hide resolved
@Ma27 Ma27 force-pushed the declarative-networks-with-iwd branch from 287febb to b3db8d6 Compare February 15, 2020 17:38
@ofborg ofborg bot requested a review from dtzWill February 15, 2020 18:07
@Ma27 Ma27 changed the title nixos/iwd: add networks and interfaces option [do not merge] nixos/iwd: add networks and interfaces option Feb 25, 2020
@Ma27
Copy link
Member Author

Ma27 commented Feb 25, 2020

As I didn't find a way to mark an already reviewed PR back as draft, I added a do no merge note at the top. I just found a weird issue where iwd segfaults when I want to connect to a certain SSID (only reproducible with this SSID) and as I'm running iwd with these changes I'd like to make sure first that this is either unrelated or gets fixed by me :)

@Ma27 Ma27 force-pushed the declarative-networks-with-iwd branch from b3db8d6 to e5196a5 Compare March 27, 2020 19:16
@Ma27
Copy link
Member Author

Ma27 commented Mar 27, 2020

Seems to be fine again with iwd 1.6 :)

@Ma27 Ma27 changed the title [do not merge] nixos/iwd: add networks and interfaces option nixos/iwd: add networks and interfaces option Mar 27, 2020
@bqv
Copy link
Contributor

bqv commented Jul 14, 2020

I've also been using this as my daily, for what it's worth. It works well and good :)

@Ma27
Copy link
Member Author

Ma27 commented Jul 14, 2020

Good to know. I'm using that as well, however I occasionally have some weird config issues I need to debug before considering this mergable.

@Ma27 Ma27 force-pushed the declarative-networks-with-iwd branch from e5196a5 to 90544ba Compare July 18, 2020 15:09
@Ma27
Copy link
Member Author

Ma27 commented Jul 18, 2020

@bqv updated the changes to work properly with iwd 1.8.

I'd be glad to have a few testers before merging this (cc @dtzWill @Mic92 @bqv @teto)

@bqv
Copy link
Contributor

bqv commented Jul 19, 2020

@bqv updated the changes to work properly with iwd 1.8.

I'd be glad to have a few testers before merging this (cc @dtzWill @Mic92 @bqv @teto)

I've just updated this. No problems so far, will update if I have any later!

@onny
Copy link
Contributor

onny commented Jul 28, 2020

Hey, what is the best way to test this PR in a running NixOS installation on Linux?

@Ma27
Copy link
Member Author

Ma27 commented Jul 28, 2020

It's unfortunately quite hacky:

{
  disabledModules = [ "services/networking/iwd.nix" ];
  imports = [ /path/to/git/checkout/of/this/branch/nixos/modules/services/networking/iwd.nix ];
}

@Mic92
Copy link
Member

Mic92 commented Jul 28, 2020

Hey, what is the best way to test this PR in a running NixOS installation on Linux?

Checkout the repo. Install hub. Than do:

$ hub checkout https://github.com/NixOS/nixpkgs/pull/75800

You can also cherry pick it to master or a release branch (not sure if it applies cleanly though)

git checkout release-20.03
hub am https://github.com/NixOS/nixpkgs/pull/75800

To install it:

nixos-rebuild -I nixpkgs=/path/to/nixpkgs switch

@Mic92
Copy link
Member

Mic92 commented Jul 28, 2020

It's unfortunately quite hacky:

{
  disabledModules = [ "services/networking/iwd.nix" ];
  imports = [ /path/to/git/checkout/of/this/branch/nixos/modules/services/networking/iwd.nix ];
}

This does not apply iwd package update though.

@Ma27
Copy link
Member Author

Ma27 commented Jul 28, 2020

Didn't test it, but why actually?

@onny
Copy link
Contributor

onny commented Jul 29, 2020

@Mic92: Thank you this worked for me!
I was able to give this PR a try. Thanks for implementing this, it is super useful!

I tried configuring it like this:

wireless.iwd = {
  enable = true;
  networks = {
    "WLAN-936189".passphrase = "3603005128703121";
    "Domestic Hacking WG".passphrase = "12345678910";
  };
};

Which results in different files and it doesn't seem iwd is still able to autoconnect:

ls -la /var/lib/iwd
[...]
lrwxrwxrwx 1 root root   48 Jul 29 12:32 '=446f6d6573746963204861636b696e67205747.psk' -> /nix/store/yvwr68q7akzklsfai3qsb3x00hj5qqnn-ssid
lrwxrwxrwx 1 root root   48 Jul 29 12:36  WLAN-936189.psk -> /nix/store/kkmrqb20zaq8qw0h0mlxxy8cm9k8c2zk-ssid

The format inside the both profiles looks right but the essid name above looks strange. Unfortunately autoconnect does not work out of the box. I have to manually connect to the network again :(
Usually the profile would have a name like Domestic Hacking WG.psk and doesn't need the encoding.

Further I really would love to see 802.1x support, otherwise some networks would be missing in my configuration. In terms of security, I usually store sensitive variables, like passphrases or private keys encrypted in a seperate .nix-file.

@Ma27
Copy link
Member Author

Ma27 commented Jul 29, 2020

Further I really would love to see 802.1x support, otherwise some networks would be missing in my configuration

As described in the PR, big 👎. I consider 802.1x credentials to be extremely sensitive so they must not be in a world-readable store.

Usually the profile would have a name like Domestic Hacking WG.psk and doesn't need the encoding

Good catch! Spaces are indeed alloewd in the filenames. Will fix this.

@Ma27 Ma27 force-pushed the declarative-networks-with-iwd branch from 90544ba to 878847c Compare July 29, 2020 15:01
@Ma27
Copy link
Member Author

Ma27 commented Jul 29, 2020

@onny fixed the issue for you.

Also modified the preStart script to remove symlinks to /nix/store that aren't part of cfg.networks anymore.

@Ma27 Ma27 force-pushed the declarative-networks-with-iwd branch from 878847c to 109af77 Compare July 29, 2020 22:49
@Ma27
Copy link
Member Author

Ma27 commented Jul 29, 2020

I'm using this for a while now (and others seem to do this as well). I'd wait a week now to check if folks experience regressions from the changes I pushed today, after that I'd consider this mergable.

cc @dtzWill @Mic92 @onny @bqv

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/prs-already-reviewed/2617/196

@Ma27
Copy link
Member Author

Ma27 commented Jul 31, 2020

cc @infinisil as you are fairly experienced with our module-system, would you mind taking a look at this in case you have time to? :)

nixos/modules/services/networking/iwd.nix Show resolved Hide resolved
nixos/modules/services/networking/iwd.nix Outdated Show resolved Hide resolved
nixos/modules/services/networking/iwd.nix Outdated Show resolved Hide resolved
allowedChars = stringToCharacters "01234556789abcdefghijklmnopqrstuvwxyz-_ ";
skipEncoding = all (char: elem (toLower char) allowedChars) (stringToCharacters file);
in
"/var/lib/iwd/${if skipEncoding then file else "$(${encodeFileName} \"${file}\")"}.${ext}";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since nothing actually needs these values at eval time, you can instead do this check during runtime in preStart directly.

# Cannot use the SSID here: the hex-encode is done at build-time, not eval time
# and several special chars in a file name would break `writeText`.
file = pkgs.writeText "ssid" (generators.toINI {} ({
Settings.AutoConnect = cfg.autoConnect;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also do this at runtime by dropping the use of generators.toINI and manually constructing the INI file

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I'm not sure whether we should do this: I check if a file in /var/lib/iwd is a store-path and if that's the case, IWD now refuses to modify/remove/whatever this network configuration. This wouldn't be possible anymore with runtime-construction and thus leading to eventual consistency as iwd can simply modify the network's configuration and therefore breaking the immutability-goal of NixOS.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's still possible to do this, which imo is even nicer since it doesn't rely on checking for Nix store symlinks: Write the list of files that were deployed declaratively to /var/lib/iwd/.declarative-nixos-networks after linking them. Then in the next preStart, remove all the files given in that list first.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea and will give it a try soon :)

'';
};

passphrase = mkOption {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And manually constructing the INI file during runtime has the benefit that you can convert the psk and passphrase options to pskFile and passphraseFile respectively, which then won't force the user into putting their password in the Nix store. When constructing the INI file in preStart you can read these file paths to get the secret values.

Note that if people don't care about this, they can still do psk = pkgs.writeFile "foo-psk" "the-psk", which still puts the secret in the store.

Furthermore, 802.1x support can be added similarly, as requested by @onny.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Relevant issue: #24288

nixos/modules/services/networking/iwd.nix Outdated Show resolved Hide resolved
nixos/modules/services/networking/iwd.nix Outdated Show resolved Hide resolved
This change adds support for declarative networks with `iwd(8)`, similar
to `networking.wireless.networks` and an `interfaces` option which tells
the service which to use (by default, the interfaces will be found
automatically).

In contrast to the `wpa_supplicant` module it's still possible to
add additional networks imperatively using `iwctl(1)` since all networks
are stored as separated files in `/var/lib/iwd`.

Please note that this change doesn't add support for 802.1x networks[1]
as this would currently mean that we'd have to store sensitive secrets
for those networks world-readably in the Nix-store. It's recommended to
add those networks imperatively.

This module supports open networks and networks with a WPA PSK or a raw
passphrase. If a SSID doesn't contain alphanumeric chars and `-_` only,
the network-configuration will be stored as `=<hex-encoded-version>.<ext>`
in `/var/lib/iwd`.

[1] https://iwd.wiki.kernel.org/networkconfigurationsettings#x_wpawpa2_enterprise_settings
@Ma27 Ma27 force-pushed the declarative-networks-with-iwd branch from 109af77 to 861bc57 Compare August 2, 2020 17:42
@Ma27 Ma27 requested review from edolstra and nbp as code owners August 2, 2020 17:42
New type which can be used to define an option that expects a
`str` with a declarable length. This originates from the `iwd`-module
where this was used to validate the length of a wireless network's PSK.

It can be used like this:

   # Option expecting a string that must have at least 5 chars and
   # at most 10 chars.
   mkOption { /* ... */
     type = types.lengthCheckedString 5 10;
   }

If a string can only have a single specified length, it can be declared
like this:

   # Option expecting a string that must have exactly 23 chars.
   mkOption { /* ... */
     type = types.fixedLengthString 23;
   }
@Ma27 Ma27 force-pushed the declarative-networks-with-iwd branch from 861bc57 to 517b290 Compare August 2, 2020 17:43
@Ma27
Copy link
Member Author

Ma27 commented Aug 2, 2020

@infinisil thanks a lot for the detailedreview. I fixed most of your notes and left a comment re cfg.interfaces and runtime construction for network configs as I'm not sure whether this is a good idea here (but I'm happy to discuss though).

@Ma27
Copy link
Member Author

Ma27 commented Oct 3, 2020

After giving this a lot of thought, I decided to close this now. In fact, I started an attempt to implement the new suggestions this week and spent a lot of time & energy with my colleague @lheckemann last night to patch the C code of iwd for this PR.

First of all, let me explain why I'm stopping this effort now: unfortunately iwd assumes that it's the only process which is doing anything in /var/lib/iwd and patching the code to make sure that iwd doesn't touch networks defined by NixOS is fairly hard (e.g. removing known networks isn't supported here atm). Also, iwd has some fairly weird behavior when establishing a connection (it wasn't reproducible when our code-path was executed and when it wasn't - we spent pretty much time in gdb on that).

Apart from that I'm losing the interest in this change as I'm currently re-evaluating wpa_supplicant for my personal setup as iwd repeatedly has trouble to log into wpa2-enterprise networks (such as the wifi in my office).

However, if someone wants to continue working on this, that's perfectly fine. The current diff on my nixpkgs checkout can be found in https://gist.github.com/Ma27/fc3e2bfcdd0aba7e65552a97189d7715 and Linus added some more improvements today in https://git.sr.ht/~linuxhackerman/iwd/log.

Last but not least, @infinisil & @bqv thanks for the review. I'll check if your ideas are somehow applicable for networking.wireless.networks and would file a new PR for that if I get a result that can be included into upstream nixpkgs :)

@Ma27 Ma27 closed this Oct 3, 2020
@Ma27 Ma27 deleted the declarative-networks-with-iwd branch October 3, 2020 16:54
@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/iwd-declarative-wifi-configs-networks-credentials/11267/2

@onny onny mentioned this pull request Nov 17, 2022
13 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants