forked from mirrors_public/oddlama_nix-config
chore: wip: begin building better hostapd module
This commit is contained in:
parent
9758a6e1e9
commit
076db4963f
4 changed files with 326 additions and 59 deletions
|
@ -8,63 +8,15 @@
|
||||||
enable = true;
|
enable = true;
|
||||||
interface = "wlan1";
|
interface = "wlan1";
|
||||||
ssid = "🍯🐝💨";
|
ssid = "🍯🐝💨";
|
||||||
# We'll set the options ourselves
|
wpa = 3;
|
||||||
wpa = false;
|
|
||||||
# Use 2.4GHz, this network is ment for dumb embedded devices
|
# Use 2.4GHz, this network is ment for dumb embedded devices
|
||||||
hwMode = "g";
|
hwMode = "g";
|
||||||
# Automatic Channel Selection (ACS) is unfortunately not implemented for mt7612u.
|
# Automatic Channel Selection (ACS) is unfortunately not implemented for mt7612u.
|
||||||
channel = 13;
|
channel = 13;
|
||||||
# Respect the local regulations
|
# Respect the local regulations
|
||||||
countryCode = "DE";
|
countryCode = "DE";
|
||||||
|
# TODO away
|
||||||
logLevel = 0;
|
logLevel = 0;
|
||||||
|
|
||||||
# This is made for a Mediatek mt7612u based device (ALFA AWUS036ACM)
|
|
||||||
extraConfig = ''
|
|
||||||
utf8_ssid=1
|
|
||||||
# Enable QoS, required for 802.11n/ac/ax
|
|
||||||
wmm_enabled=1
|
|
||||||
|
|
||||||
# DFS (IEEE 802.11d, IEEE 802.11h)
|
|
||||||
# Limit to frequencies allowed in country
|
|
||||||
ieee80211d=1
|
|
||||||
# Ensure TX Power and frequencies compliance with local regulatory requirements
|
|
||||||
ieee80211h=1
|
|
||||||
|
|
||||||
# IEEE 802.11ac (WiFi 4) - MIMO and channel bonding support
|
|
||||||
ieee80211n=1
|
|
||||||
ht_capab=[LDPC][HT40+][HT40-][GF][SHORT-GI-20][SHORT-GI-40][TX-STBC][RX-STBC1]
|
|
||||||
|
|
||||||
# IEEE 802.11ac (WiFi 5) - adds wider channel-width support and MU-MIMO (multi user MIMO)
|
|
||||||
ieee80211ac=1
|
|
||||||
#vht_capab=[SHORT-GI-80][TX-STBC-2BY1][RX-STBC-1][RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN]
|
|
||||||
#vht_oper_chwidth=1
|
|
||||||
|
|
||||||
# WPA3
|
|
||||||
wpa=2
|
|
||||||
wpa_pairwise=CCMP CCMP-256
|
|
||||||
rsn_pairwise=CCMP CCMP-256
|
|
||||||
wpa_key_mgmt=SAE
|
|
||||||
# Require WPA, disable WEP
|
|
||||||
auth_algs=1
|
|
||||||
# Encrypt management frames to protect against deauthentication and similar attacks
|
|
||||||
ieee80211w=2
|
|
||||||
# Force WPA3-Personal without transition
|
|
||||||
transition_disable=0x01
|
|
||||||
# Derive PWE using both hunting-and-pecking loop and hash-to-element
|
|
||||||
sae_pwe=2
|
|
||||||
# SAE passwords can be set via wpa_passphrase but not via wpa_psk_file. This sucks
|
|
||||||
# and means we have to add the passwords in pre-start to prevent them being visible here
|
|
||||||
{{SAE_PASSWORDS}}
|
|
||||||
|
|
||||||
# Use a MAC-address access control list
|
|
||||||
macaddr_acl=1
|
|
||||||
accept_mac_file=/run/hostapd/client-macs
|
|
||||||
|
|
||||||
# Hide network and require devices to know the ssid in advance
|
|
||||||
#ignore_broadcast_ssid=1
|
|
||||||
# Don't allow clients to communicate with each other
|
|
||||||
ap_isolate=1
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
# TODO dont adverttise!
|
# TODO dont adverttise!
|
||||||
#wpa_psk_file=${config.rekey.secrets.wifi-clients.path}
|
#wpa_psk_file=${config.rekey.secrets.wifi-clients.path}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
age-encryption.org/v1
|
age-encryption.org/v1
|
||||||
-> X25519 J0OVJ0jJkIkBk0nFoeZ7QhFoH2KZtVNEaqVrPAPOMkU
|
-> X25519 JEieTSfpgYVOG4jpaPU2Ixo5gzKfA2jADiVp2mDzo3o
|
||||||
gPL8EodGaHRmGU7SjCi0A+VSHX0Jki4QTSQJqKakOmc
|
9rqppLh1oDh5+9OOIULyRc6wO6xHtuMUWlD3Cdd92cc
|
||||||
-> piv-p256 xqSe8Q ApYjO1OYkLa5P5y/CUcreVv1D+XIuzmvL22b8xOn4KCo
|
-> piv-p256 xqSe8Q AhmCYR/YwLhHnFGfM8ovMFKesiCRq3KZJHhCkZCjOI8U
|
||||||
zXbQ2bBEoNfRBccduRzhezOHir1NoFgSaNpB2Kz9iLM
|
JpsMBhEZSirrIhrJSrxzxoH3kMafZdnwSv6AqRZRqow
|
||||||
-> 3}-b-grease vM C
|
-> 0-grease HqN8M8 ;L H9mxj ?vjE*x$[
|
||||||
9zBNWTL08GkY4ZkDLmiQQqc2Di2oFiHko39JdKAzdF53kRcEkpojS0MwOhii5673
|
7V9ALzJ+IJAvP9aUkCaaGCCX/DKbqhJc7Ii/WWwhbX56NNXKAnMu+St1yfUdto86
|
||||||
Pg0s035+WayZNZkpKHelA27aA7Yo+u6kGZ0xLP2N0ZxxjgZabYau
|
qhxQbDuVBB17Ls42W0gJxYlfwb0
|
||||||
--- CkGhrXo9Gfpf5A1h9A4ZVRtdr3KOlE78J7wXOUyMJjI
|
--- XFjv9Cuf8BHmKEgxH4g6CJaVjz0L7ojFgfWhFlHs884
|
||||||
B6úµÖůĆ^áaµŇ@VÇ�hĘąą#ťG7›&…•ęőkË~ #¶_k™Hž™`ňxcčČÝk•ŐşËJ�ýwú¶ó±¸ĆĐ ‰hF¦®ž[HéĂťęަ—�!ż}UR>•g’ÔşđÍBo¨ô�5ÂĐ9VĽ$ř’‡©Ŕ˝AŰob“g ,š/
|
�ˇ´*‹Ů.•\&ĎťŰ�;?–\"ôĺŚÉj¦`›DŚSiwŚśÉAźŐ™ j€‡’51• <_ÔXńů"{‹IµpÜ«±:Ŕ±§b=Č*µţ
|
||||||
|
ł†~#´
|
5
modules/default.nix
Normal file
5
modules/default.nix
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./hostapd.nix
|
||||||
|
];
|
||||||
|
}
|
309
modules/hostapd.nix
Normal file
309
modules/hostapd.nix
Normal file
|
@ -0,0 +1,309 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
utils,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib; let
|
||||||
|
disabledModules = ["services/networking/hostapd.nix"];
|
||||||
|
|
||||||
|
cfg = config.services.hostapd;
|
||||||
|
|
||||||
|
escapedInterface = utils.escapeSystemdPath cfg.interface;
|
||||||
|
|
||||||
|
configFile = pkgs.writeText "hostapd.conf" ''
|
||||||
|
# logging (debug level)
|
||||||
|
logger_syslog=-1
|
||||||
|
logger_syslog_level=${toString cfg.logLevel}
|
||||||
|
logger_stdout=-1
|
||||||
|
logger_stdout_level=${toString cfg.logLevel}
|
||||||
|
|
||||||
|
ctrl_interface=/run/hostapd
|
||||||
|
ctrl_interface_group=${cfg.group}
|
||||||
|
|
||||||
|
interface=${cfg.interface}
|
||||||
|
driver=${cfg.driver}
|
||||||
|
utf8_ssid=1
|
||||||
|
ssid=${cfg.ssid}
|
||||||
|
hw_mode=${cfg.hwMode}
|
||||||
|
channel=${toString cfg.channel}
|
||||||
|
|
||||||
|
${optionalString cfg.wpa ''
|
||||||
|
wpa=2
|
||||||
|
wpa_pairwise=CCMP
|
||||||
|
wpa_passphrase=${cfg.wpaPassphrase}
|
||||||
|
''}
|
||||||
|
${optionalString cfg.noScan "noscan=1"}
|
||||||
|
|
||||||
|
# Enable QoS, required for 802.11n/ac/ax
|
||||||
|
wmm_enabled=1
|
||||||
|
|
||||||
|
${optionalString (cfg.countryCode != null) ''
|
||||||
|
# DFS (IEEE 802.11d, IEEE 802.11h)
|
||||||
|
# Limit to frequencies allowed in country
|
||||||
|
ieee80211d=1
|
||||||
|
country_code=${cfg.countryCode}
|
||||||
|
# Ensure TX Power and frequencies compliance with local regulatory requirements
|
||||||
|
ieee80211h=1
|
||||||
|
''}
|
||||||
|
|
||||||
|
# IEEE 802.11ac (WiFi 4) - MIMO and channel bonding support
|
||||||
|
ieee80211n=1
|
||||||
|
ht_capab=[LDPC][HT40+][HT40-][GF][SHORT-GI-20][SHORT-GI-40][TX-STBC][RX-STBC1]
|
||||||
|
|
||||||
|
# IEEE 802.11ac (WiFi 5) - adds wider channel-width support and MU-MIMO (multi user MIMO)
|
||||||
|
ieee80211ac=1
|
||||||
|
#vht_capab=[SHORT-GI-80][TX-STBC-2BY1][RX-STBC-1][RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN]
|
||||||
|
#vht_oper_chwidth=1
|
||||||
|
|
||||||
|
# WPA3
|
||||||
|
wpa=2
|
||||||
|
wpa_pairwise=CCMP CCMP-256
|
||||||
|
rsn_pairwise=CCMP CCMP-256
|
||||||
|
wpa_key_mgmt=SAE
|
||||||
|
# Require WPA, disable WEP
|
||||||
|
auth_algs=1
|
||||||
|
# Encrypt management frames to protect against deauthentication and similar attacks
|
||||||
|
ieee80211w=2
|
||||||
|
# Force WPA3-Personal without transition
|
||||||
|
transition_disable=0x01
|
||||||
|
# Derive PWE using both hunting-and-pecking loop and hash-to-element
|
||||||
|
sae_pwe=2
|
||||||
|
# SAE passwords can be set via wpa_passphrase but not via wpa_psk_file. This sucks
|
||||||
|
# and means we have to add the passwords in pre-start to prevent them being visible here
|
||||||
|
{{SAE_PASSWORDS}}
|
||||||
|
|
||||||
|
# Use a MAC-address access control list
|
||||||
|
macaddr_acl=1
|
||||||
|
${optionalString (cfg.macaddrAcl != null) ''
|
||||||
|
accept_mac_file=${cfg.macaddrAcl}
|
||||||
|
''}
|
||||||
|
|
||||||
|
# Hide network and require devices to know the ssid in advance
|
||||||
|
#ignore_broadcast_ssid=${cfg.ignoreBroadcastSsid}
|
||||||
|
# Don't allow clients to communicate with each other
|
||||||
|
ap_isolate=${cfg.apIsolate}
|
||||||
|
|
||||||
|
${cfg.extraConfig}
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
# TODO assert interfaces >= 1
|
||||||
|
|
||||||
|
options = with types; {
|
||||||
|
services.hostapd = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Whether to enable hostapd. hostapd is a user space daemon for access point and
|
||||||
|
authentication servers. It implements IEEE 802.11 access point management,
|
||||||
|
IEEE 802.1X/WPA/WPA2/EAP Authenticators, RADIUS client, EAP server, and RADIUS
|
||||||
|
authentication server.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
interfaces = mkOption {
|
||||||
|
default = {};
|
||||||
|
example = literalExpression ''
|
||||||
|
{
|
||||||
|
# WiFi 4 - 2.4GHz
|
||||||
|
"wlp2s0" = {
|
||||||
|
ssid = "";
|
||||||
|
};
|
||||||
|
# WiFi 5 - 5GHz
|
||||||
|
"wlp3s0" = {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
This option allows you to define APs for one or multiple interfaces.
|
||||||
|
Each attribute specifies a interface and associates it to its configuration.
|
||||||
|
At least one interface must be specified.
|
||||||
|
'';
|
||||||
|
type = attrsOf (submodule {
|
||||||
|
options = {
|
||||||
|
noScan = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Disables scan for overlapping BSSs in HT40+/- mode.
|
||||||
|
Caution: turning this on will likely violate regulatory requirements!
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
driver = mkOption {
|
||||||
|
default = "nl80211";
|
||||||
|
example = "none";
|
||||||
|
type = types.str;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
The driver {command}`hostapd` will use.
|
||||||
|
{var}`nl80211` is used with all Linux mac80211 drivers.
|
||||||
|
{var}`none` is used if building a standalone RADIUS server that does
|
||||||
|
not control any wireless/wired driver.
|
||||||
|
Most applications will probably use the default.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ssid = mkOption {
|
||||||
|
default = config.system.nixos.distroId;
|
||||||
|
defaultText = literalExpression "config.system.nixos.distroId";
|
||||||
|
example = "mySpecialSSID";
|
||||||
|
type = types.str;
|
||||||
|
description = lib.mdDoc "SSID to be used in IEEE 802.11 management frames.";
|
||||||
|
};
|
||||||
|
|
||||||
|
hwMode = mkOption {
|
||||||
|
default = "g";
|
||||||
|
type = types.enum ["a" "b" "g"];
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Operation mode.
|
||||||
|
(a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g).
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
channel = mkOption {
|
||||||
|
default = 7;
|
||||||
|
example = 11;
|
||||||
|
type = types.int;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Channel number (IEEE 802.11)
|
||||||
|
Please note that some drivers do not use this value from
|
||||||
|
{command}`hostapd` and the channel will need to be configured
|
||||||
|
separately with {command}`iwconfig`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
group = mkOption {
|
||||||
|
default = "wheel";
|
||||||
|
example = "network";
|
||||||
|
type = types.str;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Members of this group can control {command}`hostapd`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
wpa = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Enable WPA (IEEE 802.11i/D3.0) to authenticate with the access point.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
wpaPassphrase = mkOption {
|
||||||
|
default = "my_sekret";
|
||||||
|
example = "any_64_char_string";
|
||||||
|
type = types.str;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
WPA-PSK (pre-shared-key) passphrase. Clients will need this
|
||||||
|
passphrase to associate with this access point.
|
||||||
|
Warning: This passphrase will get put into a world-readable file in
|
||||||
|
the Nix store!
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
logLevel = mkOption {
|
||||||
|
default = 2;
|
||||||
|
type = types.int;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Levels (minimum value for logged events):
|
||||||
|
0 = verbose debugging
|
||||||
|
1 = debugging
|
||||||
|
2 = informational messages
|
||||||
|
3 = notification
|
||||||
|
4 = warning
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
countryCode = mkOption {
|
||||||
|
default = null;
|
||||||
|
example = "US";
|
||||||
|
type = with types; nullOr str;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Country code (ISO/IEC 3166-1). Used to set regulatory domain.
|
||||||
|
Set as needed to indicate country in which device is operating.
|
||||||
|
This can limit available channels and transmit power.
|
||||||
|
These two octets are used as the first two octets of the Country String
|
||||||
|
(dot11CountryString).
|
||||||
|
If set this enables IEEE 802.11d. This advertises the countryCode and
|
||||||
|
the set of allowed channels and transmit power levels based on the
|
||||||
|
regulatory limits.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
extraConfig = mkOption {
|
||||||
|
default = "";
|
||||||
|
example = ''
|
||||||
|
auth_algo=0
|
||||||
|
ieee80211n=1
|
||||||
|
ht_capab=[HT40-][SHORT-GI-40][DSSS_CCK-40]
|
||||||
|
'';
|
||||||
|
type = types.lines;
|
||||||
|
description = lib.mdDoc "Extra configuration options to put in hostapd.conf.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
###### implementation
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
environment.systemPackages = [pkgs.hostapd];
|
||||||
|
|
||||||
|
services.udev.packages = optionals (cfg.countryCode != null) [pkgs.crda];
|
||||||
|
|
||||||
|
systemd.services.hostapd = {
|
||||||
|
description = "hostapd wireless AP";
|
||||||
|
|
||||||
|
path = [pkgs.hostapd];
|
||||||
|
after = ["sys-subsystem-net-devices-${escapedInterface}.device"];
|
||||||
|
bindsTo = ["sys-subsystem-net-devices-${escapedInterface}.device"];
|
||||||
|
requiredBy = ["network-link-${cfg.interface}.service"];
|
||||||
|
wantedBy = ["multi-user.target"];
|
||||||
|
|
||||||
|
preStart = lib.mkBefore ''
|
||||||
|
grep -o '^..:..:..:..:..:..' ${config.rekey.secrets.wifi-clients.path} > /run/hostapd/client-macs
|
||||||
|
hostapd_conf=$(cat ''${systemd.services.hostapd.serviceConfig.ExecStart})
|
||||||
|
sae_passwords=$(echo -e "sae_password=aa|mac=13:13:13:13:13:13\nsae_password=aa|mac=12:12:12:12:12:12")
|
||||||
|
hostapd_conf=''${hostapd_conf//"{{SAE_PASSWORDS}}"/$sae_passwords}
|
||||||
|
echo "$hostapd_conf" > /run/hostapd/config/$interface
|
||||||
|
'';
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
ExecStart = "${pkgs.hostapd}/bin/hostapd ${configFile}";
|
||||||
|
Restart = "always";
|
||||||
|
ExecReload = "/bin/kill -HUP $MAINPID";
|
||||||
|
RuntimeDirectory = "hostapd";
|
||||||
|
|
||||||
|
# Hardening
|
||||||
|
LockPersonality = true;
|
||||||
|
MemoryDenyWriteExecute = true;
|
||||||
|
DevicePolicy = "closed";
|
||||||
|
DeviceAllow = "/dev/rfkill rw";
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
PrivateUsers = false; # hostapd requires real system root access.
|
||||||
|
PrivateTmp = true;
|
||||||
|
ProtectClock = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
ProtectHome = true;
|
||||||
|
ProtectHostname = true;
|
||||||
|
ProtectKernelLogs = true;
|
||||||
|
ProtectKernelModules = true;
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectProc = "invisible";
|
||||||
|
ProcSubset = "pid";
|
||||||
|
ProtectSystem = "strict";
|
||||||
|
RestrictAddressFamilies = ["AF_UNIX" "AF_NETLINK" "AF_INET" "AF_INET6"];
|
||||||
|
RestrictNamespaces = true;
|
||||||
|
RestrictRealtime = true;
|
||||||
|
RestrictSUIDSGID = true;
|
||||||
|
SystemCallArchitectures = "native";
|
||||||
|
SystemCallFilter = ["@system-service" "~@privileged" "@chown"];
|
||||||
|
UMask = "0077";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue