Skip to content

nixos/hostapd: rewrite to support multi-AP, WiFi 6, password from file, and more#222536

Merged
RaitoBezarius merged 3 commits intoNixOS:masterfrom
oddlama:master
Jul 8, 2023
Merged

nixos/hostapd: rewrite to support multi-AP, WiFi 6, password from file, and more#222536
RaitoBezarius merged 3 commits intoNixOS:masterfrom
oddlama:master

Conversation

@oddlama
Copy link
Copy Markdown
Member

@oddlama oddlama commented Mar 22, 2023

Description of changes

I've noticed that the hostapd module is quite outdated and was in need of some love. This PR tries to make the hostapd module ready for modern AP setups, WiFi 6, multi-AP functionality and other things outlined below. Later I noticed that #49171 existed but was recently closed as dead, but this PR implements all of that and more.

At this point this is basically a full rewrite of this module, which is a breaking change and was necessary to properly expose the useful parts of hostapd's config. The necessary changes for users of this module are very limited (move to correct interface attrset, refactor use of wpaPassword -> saePasswords).

Since this is my first contribution I'm unsure whether a renaming notice or something like that would be required or preferred in that case. I'm happy to receive any suggestions update this PR accordingly.

The notable module changes are:

I considered implementing this in the settings-style which seems to be preferred, but due to hostap's very unconventional config format (ini-like but sometimes order-dependent, without categories and special value formats) I opted against for now. It seems like an unproportional amount of work to make sure it stays compatible with their config format.

A second commit enables new stable features such as WiFi6 and structures the .config for the hostapd package.
These changes are important to support modern APs configurations and WiFi 6. Short overview:

  • CONFIG_IEEE80211AX support (WiFi6)
  • CONFIG_SAE_PK (pubkey authenticated WPA3, important for open APs)
  • CONFIG_DRIVER_NONE (standalone RADIUS server)
  • CONFIG_OCV (Operating Channel Validation)
  • Enable epoll on linux systems
  • Remove deprecated TKIP support
  • Fix misspelling (CONFIG_INTERNETWORKING != CONFIG_INTERWORKING)
  • The .config was restructured into sections to reflect the
    upstream defconfig order and for easier updating in the future

The third and last commit enables WPA3-SAE-PK in wpa_supplicant, which is currently missing.
For completeness, CONFIG_IEEE80211AX is also added to the list of enabled options.

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandbox = true set in nix.conf? (See Nix manual)
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 23.05 Release Notes (or backporting 22.11 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

@github-actions github-actions bot added 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: changelog This PR adds or changes release notes 8.has: documentation This PR adds or changes documentation 8.has: module (update) This PR changes an existing module in `nixos/` labels Mar 22, 2023
@oddlama oddlama marked this pull request as ready for review March 22, 2023 13:08
@RaitoBezarius RaitoBezarius requested a review from flokli March 22, 2023 13:30
@flokli flokli requested a review from mweinelt March 22, 2023 13:31
@ofborg ofborg bot requested review from Ma27, MarcWeber and picnoir March 22, 2023 13:32
@ofborg ofborg bot added 10.rebuild-darwin: 1-10 This PR causes between 1 and 10 packages to rebuild on Darwin. 10.rebuild-darwin: 1 This PR causes 1 package to rebuild on Darwin. 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux. labels Mar 22, 2023
Copy link
Copy Markdown
Member

@mweinelt mweinelt left a comment

Choose a reason for hiding this comment

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

I did a first pass to try to get to know the broad strokes, because it's a lot to take in.

I'm not sure the package changes are going into the correct direction, in fact the package should probably reduce the config options to those that actually differ from upstream, instead of piling on more and more options.

Adding hardening to the systemd unit is a good idea, and I added some remarks about things I think we can or should refactor.

Finally, my worries about the module as a whole is that it is a whopping 1000 lines long now. It exposes a lot of options explicitly, which will likely require a lot of maintenance going forward. This is the reason for RFC42 and settings approach, in that it allows to specify a limited set of important option, while at same time providing an escape hatch by allowing custom key/value pairs at any place.

Instead of your helper functions (L28+), you could use apply in mkOption to integrate the mapping logic more tightly.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It requires capabilities in the host namespace, that is different from actually requiring root access.

I do wonder whether DynamicUser with AmbientCapabilities could do the job as well. Likely depends on the number of weird driver interfaces we enable. Probably fine for nl80211 though.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'm not sure how I can test that without a special device to test it with.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I imagine this to be a pain to debug since you don't get any meaningful errors if some capability is missing

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah, I'd postpone this for now. It's non trivial (to me) to figure out exactly what hostapd could possibly want. Missing something would break it, so better change it when we are sure about what it requires.

@oddlama
Copy link
Copy Markdown
Member Author

oddlama commented Mar 22, 2023

I'm not sure the package changes are going into the correct direction, in fact the package should probably reduce the config options to those that actually differ from upstream, instead of piling on more and more options.

In that case I can of course rebase the config for wpa_supplicant and hostapd on their current upstream defaults. Altoutgh this might have to be done periodically (e.g. when CONFIG_IEEE80211AX will become a default in the next years) to keep a clean diff.

Finally, my worries about the module as a whole is that it is a whopping 1000 lines long now. It exposes a lot of options explicitly, which will likely require a lot of maintenance going forward. This is the reason for RFC42 and settings approach, in that it allows to specify a limited set of important option, while at same time providing an escape hatch by allowing custom key/value pairs at any place.

I very briefly addressed that in the PR description, the issue is that the hostapd config is parsed by a custom C parser. The format is mostly key=value pairs, but doesn't follow this rule strictly. I opted against using settings style for now because there are several caveats that I don't know how to work around. For example:

  • sae_password is an option that can be repeated
  • The whole config is order dependent. If you write bss=wlan0_a you enter a new context which allows most (not all) options to be respecified for that sub-configuration

There are several cases of such inconveniences, and I have no idea how that could be mapped to RFC 42 without severely limiting generality. For now I just exposed some of the available options which are actually useful for AP setup.

Instead of your helper functions (L28+), you could use apply in mkOption to integrate the mapping logic more tightly.

Done.

@lovesegfault lovesegfault self-requested a review March 28, 2023 11:35
@oddlama
Copy link
Copy Markdown
Member Author

oddlama commented Mar 28, 2023

@NinjaTrappeur @gloaming @rardiol Could you also have a look at this? Your opinions would be much appreciated.

@oddlama oddlama force-pushed the master branch 2 times, most recently from a0ce14f to 020fb16 Compare April 2, 2023 14:54
@oddlama oddlama marked this pull request as draft April 2, 2023 14:55
@oddlama
Copy link
Copy Markdown
Member Author

oddlama commented Apr 2, 2023

I've added preliminary support for multiple BSS definitions per radio. I decided to do this since it is impossible to do that manually using extraConfig and in order to prevent another breaking change in the future. It is working, but I'm still ironing out some details and thus I put this back into draft mode for now. I'll update here once finished.

@GoogleBot42
Copy link
Copy Markdown
Contributor

GoogleBot42 commented Apr 4, 2023

Awesome work! I wish I discovered this a bit sooner before I delved into hostapd.

OpenWRT has some pretty nice auto configure scripts to automatically set the capabilities and calculates the center frequency. Without those extra values openwrt calculates and adds to the hostapd config, I wasn't able to get high speeds. I did make an ugly script that amends the hostapd configuration to add these capabilities by querying the hardware at service start but it is incomplete and definitely not ready to show off. I think a cool follow up to this PR might be to add some auto configure magic. :)

I do have a question about the configuration format. Here's an example:

{
    services.hostapd = {
      enable = true;
      radios = {
        wlan1 = {
          hwMode = "a";
          countryCode = "US";
          networks.wlan1 = {
            ssid = "tower";
            authentication.saePasswords = [{ password = "pass"; }]; 
          };
        };
      };
    };
}

It seems a bit odd to me that wlan1 is specified twice. Hostapd's config format is... terrible so maybe there's a need for it but otherwise I see maybe an alternative or two. Some other ideas that don't repeat the wireless interface.

{
    services.hostapd = {
      enable = true;
      radios = {
        wlan1 = {
          hwMode = "a";
          countryCode = "US";
          networks = [  # use an array
            {
              ssid = "tower";
              authentication.saePasswords = [{ password = "pass"; }]; 
            }
          ];
        };
      };
    };
}
{
    services.hostapd = {
      enable = true;
      radios = {
        wlan1 = {
          hwMode = "a";
          countryCode = "US";
          networks.tower = { # the SSID is the key;  I assume all networks *must* have an SSID right?
            authentication.saePasswords = [{ password = "pass"; }]; 
          };
        };
      };
    };
}

@oddlama
Copy link
Copy Markdown
Member Author

oddlama commented Jun 16, 2023

Thanks for the suggestions, I've now changed the following things:

  • Introduced a package option to be able to override the hostapd package
  • Removed default definitions for SSIDs
  • Moved all the runtime config generation logic to a new dynamicConfigScripts attrset, where new scripts can be added if necessary. One set per radio and one per network BSS of course. The module pre-fills some bss specific stuff to generate the mac allow/deny lists and to add passwords from files.

Awesome! I really like how this looks (and I hope I haven't annoyed you too much asking you to change all this stuff)

Not at all, I'm glad for the feedback! I believe this way the PR has come a long way from the initial draft.

Another thing I'd like to see is being able to customize config generation at runtime, like what you're doing right now for e.g. passwordFile but in an externally extensible way. This would allow NixOS configurations (or other modules) to add something such as automatically detecting ht_capab based on what the adapter says (something that OpenWrt does and I potentially wanted to try getting to work in NixOS), without having to use a nixpkgs fork.

I've also thought about that, but after seeing the amount of edge-case handling in OpenWrt I dismissed the thought for now. If you manage to do that generically this would be awesome to have in NixOS.

@dblsaiko
Copy link
Copy Markdown
Contributor

I've also thought about that, but after seeing the amount of edge-case handling in OpenWrt I dismissed the thought for now. If you manage to do that generically this would be awesome to have in NixOS.

Yeeeah, when I first took a look I kinda bailed out when seeing the two ~1.5k line shell scripts to generate this stuff, using lots of OpenWrt specific programs and other scripts. I'd still like to do it at some point though because it would be really cool to not have to worry about adapter configuration (for drivers that behave).

@oddlama oddlama added the 12.approvals: 2 This PR was reviewed and approved by two persons. label Jun 17, 2023
@Janik-Haag Janik-Haag added the 12.first-time contribution This PR is the author's first one; please be gentle! label Jun 22, 2023
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why do we maintain this list of lib functions?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah, I'd say to just use lib. everywhere, it's just three letters anyway.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Is this a relevant change though?

Since some consider with lib to be an antipattern I chose this to make the code more readable without having lib. bloating the line everywhere. Since serveral files in nixpkgs do the same thing I didn't expect this to be controversial.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's leave those nitpicks out of the PR as it's already quite hairy, complicated and probably taking a lot of patience from the author. :)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we want to reset permissions here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Shouldn't make a difference, this is an ephemeral file managed by the module either way. Or do you have something specific in mind?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I imagine this to be a pain to debug since you don't get any meaningful errors if some capability is missing

@RaitoBezarius
Copy link
Copy Markdown
Member

@oddlama Can you fix the conflicts please?

@oddlama
Copy link
Copy Markdown
Member Author

oddlama commented Jun 24, 2023

@oddlama Can you fix the conflicts please?

Done :)

@oddlama
Copy link
Copy Markdown
Member Author

oddlama commented Jun 26, 2023

Latest commit changes the RFC42 settings such that they show an error when redefining non-list symbols with different values, instead of silently making a list of them.

@oddlama
Copy link
Copy Markdown
Member Author

oddlama commented Jun 26, 2023

Replaced hwMode in favor of band to make configuration experience better (we follow OpenWRT here). Also added assertion that ensures HT40- is not used with ACS (unsupported by hostapd).

oddlama added 3 commits July 2, 2023 13:31
These changes are important to support modern APs configurations.
Short overview:

- CONFIG_IEEE80211AX support (WiFi6)
- CONFIG_SAE_PK (pubkey authenticated WPA3)
- CONFIG_DRIVER_NONE (standalone RADIUS server)
- CONFIG_OCV (Operating Channel Validation)
- Enable epoll on linux systems
- Remove deprecated TKIP support
- Fix misspelling (CONFIG_INTERNETWORKING != CONFIG_INTERWORKING)
- The .config was restructured into sections to reflect the
  upstream defconfig order and for easier updating in the future
At this point this is basically a full rewrite of this module, which
is a breaking change and was necessary to properly expose the useful
parts of hostapd's config. The notable changes are:

- `hostapd` is now started with additional systemd sandbox/hardening options
- A single-daemon can now manage multiple distinct radios and BSSs, which is
  why all configuration had to be moved into `hostapd.radios`
- By default WPA3-SAE will be used, but WPA2 and WPA3-SAE-TRANSITION are
  supported, too
- Added passwordFile-like options for wpa and sae
- Add new relevant options for MAC ACL, WiFi5, WiFi6 and WiFi7 configuration
- Implements RFC42 as far as reasonable for hostapd
- Removes `with lib;`
Copy link
Copy Markdown
Member

@RaitoBezarius RaitoBezarius left a comment

Choose a reason for hiding this comment

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

This PR is one of the most excellent work I have seen in nixpkgs, @oddlama has been very patient, and I feel like it's time to move on to the next PR for more improvements in that area.

I will merge this now, feel free to revert me if that's too premature in your opinion.

@RaitoBezarius RaitoBezarius merged commit 7be8314 into NixOS:master Jul 8, 2023
@jcumming
Copy link
Copy Markdown
Contributor

jcumming commented Jul 9, 2023

Wow! Thanks for all of the work @oddlama !

This is a huge improvement over the massive string of opaque hostapd options I currently use for multi-ap.

GoogleBot42 added a commit to GoogleBot42/nix-config that referenced this pull request Aug 9, 2023
Flake lock file updates:

• Updated input 'agenix':
    'github:ryantm/agenix/2994d002dcff5353ca1ac48ec584c7f6589fe447' (2023-04-21)
  → 'github:ryantm/agenix/d8c973fd228949736dedf61b7f8cc1ece3236792' (2023-07-24)
• Added input 'agenix/home-manager':
    'github:nix-community/home-manager/32d3e39c491e2f91152c84f8ad8b003420eab0a1' (2023-04-22)
• Added input 'agenix/home-manager/nixpkgs':
    follows 'agenix/nixpkgs'
• Updated input 'deploy-rs':
    'github:serokell/deploy-rs/c2ea4e642dc50fd44b537e9860ec95867af30d39' (2023-04-21)
  → 'github:serokell/deploy-rs/724463b5a94daa810abfc64a4f87faef4e00f984' (2023-06-14)
• Updated input 'flake-utils':
    'github:numtide/flake-utils/cfacdce06f30d2b68473a46042957675eebb3401' (2023-04-11)
  → 'github:numtide/flake-utils/919d646de7be200f3bf08cb76ae1f09402b6f9b4' (2023-07-11)
• Updated input 'nix-index-database':
    'github:Mic92/nix-index-database/e3e320b19c192f40a5b98e8776e3870df62dee8a' (2023-04-25)
  → 'github:Mic92/nix-index-database/d74b8171153ae35d7d323a9b1ad6c4cf7a995591' (2023-07-30)
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/297187b30a19f147ef260abb5abd93b0706af238' (2023-04-30)
  → 'github:NixOS/nixpkgs/f024cd6abd47bdd5fa3b4a41bd357e2dde5f4195' (2023-08-05)
• Updated input 'nixpkgs-hostapd-pr':
    'NixOS/nixpkgs#222536'
  → 'NixOS/nixpkgs#222536'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: changelog This PR adds or changes release notes 8.has: documentation This PR adds or changes documentation 8.has: module (update) This PR changes an existing module in `nixos/` 10.rebuild-darwin: 1-10 This PR causes between 1 and 10 packages to rebuild on Darwin. 10.rebuild-darwin: 1 This PR causes 1 package to rebuild on Darwin. 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux. 12.approvals: 2 This PR was reviewed and approved by two persons. 12.first-time contribution This PR is the author's first one; please be gentle!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provide options for storing secrets outside the Nix store