nixos/hostapd: rewrite to support multi-AP, WiFi 6, password from file, and more#222536
nixos/hostapd: rewrite to support multi-AP, WiFi 6, password from file, and more#222536RaitoBezarius merged 3 commits intoNixOS:masterfrom
Conversation
mweinelt
left a comment
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
I'm not sure how I can test that without a special device to test it with.
There was a problem hiding this comment.
I imagine this to be a pain to debug since you don't get any meaningful errors if some capability is missing
There was a problem hiding this comment.
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.
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.
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:
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.
Done. |
a0ce14f to
020fb16
Compare
|
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 |
|
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 {
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"; }];
};
};
};
};
} |
|
Thanks for the suggestions, I've now changed the following things:
Not at all, I'm glad for the feedback! I believe this way the PR has come a long way from the initial draft.
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). |
There was a problem hiding this comment.
Why do we maintain this list of lib functions?
There was a problem hiding this comment.
Yeah, I'd say to just use lib. everywhere, it's just three letters anyway.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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. :)
There was a problem hiding this comment.
Do we want to reset permissions here?
There was a problem hiding this comment.
Shouldn't make a difference, this is an ephemeral file managed by the module either way. Or do you have something specific in mind?
There was a problem hiding this comment.
I imagine this to be a pain to debug since you don't get any meaningful errors if some capability is missing
|
@oddlama Can you fix the conflicts please? |
Done :) |
|
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. |
|
Replaced |
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;`
RaitoBezarius
left a comment
There was a problem hiding this comment.
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.
|
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. |
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'
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:
hostapdis now started with additional systemd sandbox/hardening optionsservices.hostapd.interfaces(similar to what RFC: hostapd: extend module to allow multiple APs. #49171 tried to accomplish)passwordFile-like options for WPA and SAE which closes Provide options for storing secrets outside the Nix store #24288.with lib;usage as per Tracking issue: remove overuses ofwith lib;#208242.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:
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.
sandbox = trueset innix.conf? (See Nix manual)nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage./result/bin/)