From 491c4bf6b4596b486b12724e9124a854cc7abc26 Mon Sep 17 00:00:00 2001 From: "quentin@aristote.fr" Date: Sun, 29 Sep 2024 19:56:08 +0200 Subject: migrate hostapd config --- config/networking/services/ap.nix | 277 +++++++++++++++----------------------- 1 file changed, 109 insertions(+), 168 deletions(-) (limited to 'config/networking/services/ap.nix') diff --git a/config/networking/services/ap.nix b/config/networking/services/ap.nix index 33bae8c..2248f5d 100644 --- a/config/networking/services/ap.nix +++ b/config/networking/services/ap.nix @@ -1,187 +1,128 @@ { config, lib, - utils, - pkgs, - secrets, ... }: let - nets = config.personal.networking.networks; - makeHostapdConf = { - name, - device, - interface, - driver ? "nl80211", - ssid, - hwMode ? "g", - channel ? 0, - countryCode ? "FR", - passphrase ? secrets.wifi."${name}".passphrase, - logLevel ? 2, - extraConfig ? "", - }: - builtins.toFile "hostapd.${name}.conf" ('' - interface=${device} - driver=${driver} + ifaces = config.personal.networking.interfaces.all; + netdevServices = builtins.map (bridge: "${bridge}-netdev.service") ["wan" "iot" "guest"]; - # IEEE 802.11 - ssid=${ssid} - hw_mode=${hwMode} - channel=${toString channel} - max_num_sta=128 - auth_algs=1 - disassoc_low_ack=1 - - # DFS - ieee80211h=1 - ieee80211d=1 - country_code=${countryCode} + # common config + countryCode = "FR"; + driver = "nl80211"; + settings.max_num_sta = 128; + perBridgeCfg = radio: bridge: let + ssids = { + wan = "Quentintranet"; + iot = "Quentinternet of Things"; + guest = "Quentinvités"; + }; + iface = radio + lib.optionalString (bridge != "wan") "-${bridge}"; + in { + "${iface}" = { + ssid = ssids."${bridge}" + lib.optionalString (radio == "wlp5s0" && bridge != "guest") " (n)"; + bssid = ifaces."${iface}".machines.self.mac; - # disable low-level bridging of frames - ap_isolate=1 - bridge=${interface} + authentication.mode = "wpa3-sae"; + authentication.saePasswordsFile = "/etc/hostapd/${bridge}.sae"; - # WPA/IEEE 802.11i - wpa=2 - wpa_key_mgmt=WPA-PSK - wpa_passphrase=${passphrase} - wpa_pairwise=CCMP + logLevel = 2; # informational messages - # hostapd event logger configuration - logger_syslog=-1 - logger_syslog_level=${toString logLevel} - logger_stdout=-1 - logger_stdout_level=${toString logLevel} + apIsolate = true; + settings = { + inherit bridge; + disassoc_low_ack = 1; # WMM - wmm_enabled=1 - uapsd_advertisement_enabled=1 - wmm_ac_bk_cwmin=4 - wmm_ac_bk_cwmax=10 - wmm_ac_bk_aifs=7 - wmm_ac_bk_txop_limit=0 - wmm_ac_bk_acm=0 - wmm_ac_be_aifs=3 - wmm_ac_be_cwmin=4 - wmm_ac_be_cwmax=10 - wmm_ac_be_txop_limit=0 - wmm_ac_be_acm=0 - wmm_ac_vi_aifs=2 - wmm_ac_vi_cwmin=3 - wmm_ac_vi_cwmax=4 - wmm_ac_vi_txop_limit=94 - wmm_ac_vi_acm=0 - wmm_ac_vo_aifs=2 - wmm_ac_vo_cwmin=2 - wmm_ac_vo_cwmax=3 - wmm_ac_vo_txop_limit=47 - wmm_ac_vo_acm=0 - - # TX queue parameters - tx_queue_data3_aifs=7 - tx_queue_data3_cwmin=15 - tx_queue_data3_cwmax=1023 - tx_queue_data3_burst=0 - tx_queue_data2_aifs=3 - tx_queue_data2_cwmin=15 - tx_queue_data2_cwmax=63 - tx_queue_data2_burst=0 - tx_queue_data1_aifs=1 - tx_queue_data1_cwmin=7 - tx_queue_data1_cwmax=15 - tx_queue_data1_burst=3.0 - tx_queue_data0_aifs=1 - tx_queue_data0_cwmin=3 - tx_queue_data0_cwmax=7 - tx_queue_data0_burst=1.5 - '' - + extraConfig); - hostapdIotConf = makeHostapdConf { - name = "iot"; - inherit (nets.iot) device interface; - ssid = "Quentinternet of Things"; - hwMode = "g"; - channel = 0; - extraConfig = '' - # IEEE 802.11n - ieee80211n=1 - require_ht=0 # sonos play:1 doesn't support ht - ht_capab=[HT40+][SHORT-GI-40][TX-STBC][RX-STBC1][DSSS_CCK-40] - ''; - }; - hostapdWanConf = makeHostapdConf { - name = "wan"; - inherit (nets.wan) device interface; - ssid = "Quentintranet"; - hwMode = "a"; - channel = 36; - extraConfig = '' - # IEEE 802.11n - ieee80211n=1 - require_ht=1 - ht_capab=[HT40+][LDPC][SHORT-GI-20][SHORT-GI-40][TX-STBC][RX-STBC1][DSSS_CCK-40] - - # IEEE 802.11ac - require_vht=1 - ieee80211ac=1 - vht_oper_chwidth=1 - vht_oper_centr_freq_seg0_idx=42 - vht_capab=[MAX-MPDU-11454][RXLDPC][SHORT-GI-80][TX-STBC-2BY1][RX-STBC-1][MAX-A-MPDU-LEN-EXP7][RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN] - ''; + wmm_enabled = 1; + uapsd_advertisement_enabled = 1; + wmm_ac_bk_cwmin = 4; + wmm_ac_bk_cwmax = 10; + wmm_ac_bk_aifs = 7; + wmm_ac_bk_txop_limit = 0; + wmm_ac_bk_acm = 0; + wmm_ac_be_aifs = 3; + wmm_ac_be_cwmin = 4; + wmm_ac_be_cwmax = 10; + wmm_ac_be_txop_limit = 0; + wmm_ac_be_acm = 0; + wmm_ac_vi_aifs = 2; + wmm_ac_vi_cwmin = 3; + wmm_ac_vi_cwmax = 4; + wmm_ac_vi_txop_limit = 94; + wmm_ac_vi_acm = 0; + wmm_ac_vo_aifs = 2; + wmm_ac_vo_cwmin = 2; + wmm_ac_vo_cwmax = 3; + wmm_ac_vo_txop_limit = 47; + wmm_ac_vo_acm = 0; + # TX queue + tx_queue_data3_aifs = 7; + tx_queue_data3_cwmin = 15; + tx_queue_data3_cwmax = 1023; + tx_queue_data3_burst = 0; + tx_queue_data2_aifs = 3; + tx_queue_data2_cwmin = 15; + tx_queue_data2_cwmax = 63; + tx_queue_data2_burst = 0; + tx_queue_data1_aifs = 1; + tx_queue_data1_cwmin = 7; + tx_queue_data1_cwmax = 15; + tx_queue_data1_burst = "3.0"; + tx_queue_data0_aifs = 1; + tx_queue_data0_cwmin = 3; + tx_queue_data0_cwmax = 7; + tx_queue_data0_burst = "1.5"; + }; + }; }; in { - systemd.services.hostapd = let - subnets = with nets; [wan iot]; - netDevices = - builtins.map (subnet: "sys-subsystem-net-devices-${ - utils.escapeSystemdPath subnet.device - }.device") - subnets; - netdevServices = - builtins.map (subnet: "${subnet.interface}-netdev.service") subnets; - dependencies = lib.mkForce (netDevices ++ netdevServices); - in - lib.mkForce { - # from https://github.com/NixOS/nixpkgs/blob/23.05/nixos/modules/services/networking/hostapd.nix - # with hardening from https://github.com/NixOS/nixpkgs/blob/23.11/nixos/modules/services/networking/hostapd.nix - description = "IEEE 802.11 Host Access-Point Daemon"; + systemd.services.hostapd = { + after = netdevServices; + bindsTo = netdevServices; + }; - path = [pkgs.hostapd]; - after = dependencies; - bindsTo = dependencies; - wantedBy = ["multi-user.target"]; + services.hostapd = { + enable = true; + radios = { + wlp1s0 = { + inherit countryCode driver; + band = "5g"; + channel = 36; + wifi4 = { + enable = true; + require = true; + capabilities = ["HT40+" "LDPC" "SHORT-GI-20" "SHORT-GI-40" "TX-STBC" "RX-STBC1" "DSSS_CCK-40"]; + }; + wifi5 = { + enable = true; + require = false; + operatingChannelWidth = "80"; + capabilities = ["MAX-MPDU-11454" "RXLDPC" "SHORT-GI-80" "TX-STBC-2BY1" "RX-STBC-1" "MAX-A-MPDU-LEN-EXP7" "RX-ANTENNA-PATTERN" "TX-ANTENNA-PATTERN"]; + }; + settings = settings // {vht_oper_centr_freq_seg0_idx = 42;}; - serviceConfig = { - ExecStart = "${pkgs.hostapd}/bin/hostapd ${hostapdIotConf} ${hostapdWanConf}"; - Restart = "always"; - ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - RuntimeDirectory = "hostapd"; + networks = let + perBridgeAC = perBridgeCfg "wlp1s0"; + in + (perBridgeAC "wan") // (perBridgeAC "iot"); + }; + wlp5s0 = { + inherit countryCode driver settings; + band = "2g"; + channel = 0; + wifi4 = { + enable = true; + require = false; + capabilities = ["HT40+" "SHORT-GI-40" "TX-SBTC" "RX-SBTC1" "DSSS_CCK-40"]; + }; - # Hardening - LockPersonality = true; - MemoryDenyWriteExecute = true; - DevicePolicy = "closed"; - DeviceAllow = "/dev/rfkill rw"; - NoNewPrivileges = true; - PrivateUsers = false; # hostapd requires true 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_INET" "AF_INET6" "AF_NETLINK" "AF_UNIX" "AF_PACKET"]; - RestrictNamespaces = true; - RestrictRealtime = true; - RestrictSUIDSGID = true; - SystemCallArchitectures = "native"; - SystemCallFilter = ["@system-service" "~@privileged" "@chown"]; - UMask = "0077"; + networks = let + perBridgeN = perBridgeCfg "wlp5s0"; + in + (perBridgeN "wan") + // (perBridgeN "iot") + // (perBridgeN "guest"); }; }; + }; } -- cgit v1.2.3