From 55ce0f0be1c9c4080c3d4a55643645e627755d2e Mon Sep 17 00:00:00 2001 From: Stefan Junker Date: Sun, 17 Dec 2023 23:28:00 +0100 Subject: [PATCH 1/7] WIP: vlan experimentation --- nix/os/devices/router0-dmz0/configuration.nix | 68 ++++++++++++------ nix/os/devices/router0-dmz0/flake.lock | 70 ++++++++++++------- nix/os/devices/router0-dmz0/flake.nix | 7 +- nix/os/devices/steveej-t14/flake.lock | 18 ++--- 4 files changed, 101 insertions(+), 62 deletions(-) diff --git a/nix/os/devices/router0-dmz0/configuration.nix b/nix/os/devices/router0-dmz0/configuration.nix index f7f57c3..632be00 100644 --- a/nix/os/devices/router0-dmz0/configuration.nix +++ b/nix/os/devices/router0-dmz0/configuration.nix @@ -146,20 +146,20 @@ in { systemd.network = { wait-online.anyInterface = true; netdevs = { - # Create the VLANs - "00-vlan-100" = { - Name = "vlan100"; - Kind = "vlan"; - }; - - # Create the bridge interfaces + # Create the bridge interface "20-br-lan" = { netdevConfig = { Kind = "bridge"; Name = "br-lan"; - VLANFiltering = true; - DefaultPVID = 10; + }; + + extraConfig = '' + [Bridge] + STP=true + VLANFiltering=yes + DefaultPVID=none + ''; }; }; networks = { @@ -239,7 +239,8 @@ in { services.hostapd = { enable = true; radios = let - mkBssid = i: "34:56:ce:0f:ed:4${builtins.toString i}"; + mkBssid = i: # generated with https://miniwebtool.com/mac-address-generator/ + "34:56:ce:0f:ed:4${builtins.toString i}"; in { wlan0 = { band = "2g"; @@ -259,13 +260,15 @@ in { # saePasswordsFile = config.sops.secrets.wifiPassword.path; saePasswords = [ { - password = "justtestingwifi"; - # vlanid = 100; + password = "normalnormal"; + } + { + password = "vlanvlan"; + vlanid = 1; } ]; }; - # generated with https://miniwebtool.com/mac-address-generator/ bssid = mkBssid 0; settings = { bridge = "br-lan"; @@ -279,20 +282,33 @@ in { # saePasswordsFile = config.sops.secrets.wifiPassword.path; saePasswords = [ { - password = "justtestingwifi"; - # vlanid = 100; + password = "normalnormal"; + } + { + password = "vlanvlan"; + vlanid = 1; } ]; - wpaPskFile = pkgs.writeText "pskfile" '' - 00:00:00:00:00:00 justtestingwifi - # vlanid=100 00:00:00:00:00:00 justtestingwifi-vlan + wpaPskFile = pkgs.writeText "wpa_psk" '' + 00:00:00:00:00:00 normalnormal + vlanid=1 00:00:00:00:00:00 vlanvlan ''; }; - # generated with https://miniwebtool.com/mac-address-generator/ bssid = mkBssid 1; settings = { bridge = "br-lan"; + + # resources on vlan tagging + # https://wireless.wiki.kernel.org/en/users/Documentation/hostapd#dynamic_vlan_tagging + # https://forum.openwrt.org/t/individual-per-passphrase-wifi-vlans-using-wpa-psk-file-no-radius-required/161696/4 + + vlan_tagged_interface = "br-lan"; + vlan_bridge = "br-vlan"; + dynamic_vlan = 1; + vlan_file = builtins.toString (pkgs.writeText "hostapd.vlan" '' + * wlan0-1.# + ''); }; }; @@ -314,6 +330,7 @@ in { # }; }; }; + # wlan1 = { # band = "5g"; # # channels with 160 MHz width in Poland: 36, 52, 100 i 116 @@ -416,9 +433,15 @@ in { bogus-priv = true; no-resolv = true; - dhcp-range = ["br-lan,192.168.10.50,192.168.10.254,24h"]; - interface = "br-lan"; - dhcp-host = "192.168.10.1"; + dhcp-range = [ + # "br-lan,192.168.10.50,192.168.10.100,24h" + "192.168.10.50,192.168.10.100,24h" + ]; + + # interface = "br-lan"; + # bind-interfaces = true; + + # dhcp-host = "192.168.10.1"; # local domains local = "/lan/"; @@ -491,7 +514,6 @@ in { system.stateVersion = "23.05"; boot.kernelPackages = pkgs.linuxPackages_bpir3; - # boot.kernelPackages = bpir3.packages.aarch64-linux.linuxPackages_bpir3; # We exclude a number of modules included in the default list. A non-insignificant amount do # not apply to embedded hardware like this, so simply skip the defaults. # diff --git a/nix/os/devices/router0-dmz0/flake.lock b/nix/os/devices/router0-dmz0/flake.lock index b572ebd..06e3d64 100644 --- a/nix/os/devices/router0-dmz0/flake.lock +++ b/nix/os/devices/router0-dmz0/flake.lock @@ -7,17 +7,16 @@ ] }, "locked": { + "dirtyRev": "4210480bdebbf3a7953e22d5d9f183f47b725bff-dirty", + "dirtyShortRev": "4210480-dirty", "lastModified": 1688620001, - "narHash": "sha256-8ACxxssPiQy/lsUsT8cAaT2te8p8d8ngmPwTc/erPnU=", - "owner": "nakato", - "repo": "nixos-bpir3-example", - "rev": "4210480bdebbf3a7953e22d5d9f183f47b725bff", - "type": "github" + "narHash": "sha256-INxwGchokdU3ESpnvmfkMWZhocM134FmhWQoyPqtg60=", + "type": "git", + "url": "file:///home/steveej/src/steveej/nixos-bpir3" }, "original": { - "owner": "nakato", - "repo": "nixos-bpir3-example", - "type": "github" + "type": "git", + "url": "file:///home/steveej/src/steveej/nixos-bpir3" } }, "dependencyDagOfSubmodule": { @@ -48,11 +47,11 @@ ] }, "locked": { - "lastModified": 1695864092, - "narHash": "sha256-Hu1SkFPqO7ND95AOzBkZE2jGXSYhfZ965C03O72Kbu8=", + "lastModified": 1702569759, + "narHash": "sha256-Ze3AdEEsVZBRJ4wn13EZpV1Uubkzi59TkC4j2G9xoFI=", "owner": "nix-community", "repo": "disko", - "rev": "19b62324663b6b9859caf7f335d232cf4f1f6a32", + "rev": "98ab91109716871f50ea8cb0e0ac7cc1e1e14714", "type": "github" }, "original": { @@ -83,11 +82,11 @@ ] }, "locked": { - "lastModified": 1696145345, - "narHash": "sha256-3dM7I/d4751SLPJah0to1WBlWiyzIiuCEUwJqwBdmr4=", + "lastModified": 1702814335, + "narHash": "sha256-Qck7BAMi3eydzT1WFOzp/SgECetyPpOn1dLgmxH2ebQ=", "owner": "nix-community", "repo": "home-manager", - "rev": "6f9b5b83ad1f470b3d11b8a9fe1d5ef68c7d0e30", + "rev": "e4dba0bd01956170667458be7b45f68170a63651", "type": "github" }, "original": { @@ -105,11 +104,11 @@ ] }, "locked": { - "lastModified": 1695065444, - "narHash": "sha256-c39mzyE1Z95bOjNfcCpENdQUn8lgTQFXNDeDguZnKs4=", + "lastModified": 1702744409, + "narHash": "sha256-dcDkc+6TF9EvfWpsLdmGz4hhrNVbQZDgFwvk5SOjYTI=", "owner": "thelegy", "repo": "nixos-nftables-firewall", - "rev": "f1d43094940379f8aa3b7ef750b48db48b622584", + "rev": "a33df9d2f586b85e8e7e546d9b99b39f3187c382", "type": "github" }, "original": { @@ -118,18 +117,34 @@ "type": "github" } }, - "nixpkgs": { + "nixos-stable": { "locked": { - "lastModified": 1691788113, - "narHash": "sha256-h5dnmk0QMQI+WkP7ZGbqusr7GfeXOrYCzO7BoZpSGJ0=", - "owner": "steveej-forks", + "lastModified": 1702346276, + "narHash": "sha256-eAQgwIWApFQ40ipeOjVSoK4TEHVd6nbSd9fApiHIw5A=", + "owner": "NixOS", "repo": "nixpkgs", - "rev": "f358ddb768fad528772ae3faf786337fe89a7568", + "rev": "cf28ee258fd5f9a52de6b9865cdb93a1f96d09b7", "type": "github" }, "original": { - "owner": "steveej-forks", - "ref": "hostapd-fix", + "owner": "NixOS", + "ref": "nixos-23.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1702312524, + "narHash": "sha256-gkZJRDBUCpTPBvQk25G0B7vfbpEYM5s5OZqghkjZsnE=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "a9bf124c46ef298113270b1f84a164865987a91c", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } @@ -147,16 +162,17 @@ }, "srvos": { "inputs": { + "nixos-stable": "nixos-stable", "nixpkgs": [ "nixpkgs" ] }, "locked": { - "lastModified": 1695864227, - "narHash": "sha256-X3ADr3UE0Cws7yRLnMyo6VbBWrbkT8KMrds8TK6IYXw=", + "lastModified": 1702518612, + "narHash": "sha256-AGqIpvEMqo0FKXslmKL8ydt01pJFs8q3nUtz7gksoig=", "owner": "numtide", "repo": "srvos", - "rev": "25cf328a2d83926dde264b6195d82bc6dcfb4b0c", + "rev": "cd802e2933c567ea91de48dbe8968f41a5d9a642", "type": "github" }, "original": { diff --git a/nix/os/devices/router0-dmz0/flake.nix b/nix/os/devices/router0-dmz0/flake.nix index 32748fb..9a714b9 100644 --- a/nix/os/devices/router0-dmz0/flake.nix +++ b/nix/os/devices/router0-dmz0/flake.nix @@ -1,7 +1,7 @@ { inputs = { - # nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - nixpkgs.url = "github:steveej-forks/nixpkgs/hostapd-fix"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + # nixpkgs.url = "github:steveej-forks/nixpkgs/hostapd-fix"; get-flake.url = "github:ursi/get-flake"; @@ -13,7 +13,8 @@ srvos.url = "github:numtide/srvos"; srvos.inputs.nixpkgs.follows = "nixpkgs"; - bpir3.url = "github:nakato/nixos-bpir3-example"; + # bpir3.url = "github:steveej-forks/nixos-bpir3"; + bpir3.url = "/home/steveej/src/steveej/nixos-bpir3"; bpir3.inputs.nixpkgs.follows = "nixpkgs"; nixos-nftables-firewall.url = "github:thelegy/nixos-nftables-firewall"; diff --git a/nix/os/devices/steveej-t14/flake.lock b/nix/os/devices/steveej-t14/flake.lock index b171000..de4e48f 100644 --- a/nix/os/devices/steveej-t14/flake.lock +++ b/nix/os/devices/steveej-t14/flake.lock @@ -7,11 +7,11 @@ ] }, "locked": { - "lastModified": 1702676849, - "narHash": "sha256-XqcREaTS38/QOsN8fk8PP325/UXHyF9enbP5ZPw5aiA=", + "lastModified": 1702814678, + "narHash": "sha256-zDtO0jV2QLoddUJinLlTQrQqCUW3dPiIWOSYgg98T7E=", "owner": "nix-community", "repo": "home-manager", - "rev": "aa99c2f4e9847cbb7e46fac0844ea1eb164b3b3a", + "rev": "1488651d02c1a7a15e284210f0d380a62d8d8cef", "type": "github" }, "original": { @@ -55,11 +55,11 @@ }, "nixpkgs-2311": { "locked": { - "lastModified": 1702346276, - "narHash": "sha256-eAQgwIWApFQ40ipeOjVSoK4TEHVd6nbSd9fApiHIw5A=", + "lastModified": 1702645756, + "narHash": "sha256-qKI6OR3TYJYQB3Q8mAZ+DG4o/BR9ptcv9UnRV2hzljc=", "owner": "nixos", "repo": "nixpkgs", - "rev": "cf28ee258fd5f9a52de6b9865cdb93a1f96d09b7", + "rev": "40c3c94c241286dd2243ea34d3aef8a488f9e4d0", "type": "github" }, "original": { @@ -71,11 +71,11 @@ }, "nixpkgs-master": { "locked": { - "lastModified": 1702743713, - "narHash": "sha256-vcoIM8IyCwGER/1CcP8j5bq8izM/uzFNipbv5MS4JSE=", + "lastModified": 1702830598, + "narHash": "sha256-NiGUGof87PAmaH8BLzC/mIhYmjd190NEA3uk2tNTBms=", "owner": "nixos", "repo": "nixpkgs", - "rev": "bb6cf10a57b762ca24e4a1b791b49e2216816cf2", + "rev": "c9bdee2a9629344cb5d7d9aa48fda1ef34deec18", "type": "github" }, "original": { -- 2.49.0 From b7e2ec02e36518a00e6d2c106f12cef348beab48 Mon Sep 17 00:00:00 2001 From: Stefan Junker Date: Sun, 24 Dec 2023 20:01:20 +0100 Subject: [PATCH 2/7] WIP: hostapd with vlan works on laptop --- .sops.yaml | 4 +- .vscode/settings.json | 2 +- nix/os/devices/router0-dmz0/configuration.nix | 447 +++++++++++------- nix/os/devices/router0-dmz0/default.nix | 1 + nix/os/devices/router0-dmz0/flake.lock | 62 ++- nix/os/devices/router0-dmz0/flake.nix | 14 +- secrets/router0-dmz0/secrets.yaml | 6 +- 7 files changed, 334 insertions(+), 202 deletions(-) diff --git a/.sops.yaml b/.sops.yaml index 4ff660e..eb17a55 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -1,4 +1,4 @@ -# This example uses YAML anchors which allows reuse of multiple keys +# This example uses YAML anchors which allows reuse of multiple keys # without having to repeat yourself. # Also see https://github.com/Mic92/dotfiles/blob/master/nixos/.sops.yaml # for a more complex example. @@ -72,4 +72,4 @@ creation_rules: - pgp: - *steveej age: - - *sj-bm-hostkey0 \ No newline at end of file + - *sj-bm-hostkey0 diff --git a/.vscode/settings.json b/.vscode/settings.json index df4ca93..0691bf9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "nixEnvSelector.nixFile": "${workspaceRoot}/shell.nix", "[nix]": { - "editor.defaultFormatter": "kamadorueda.alejandra" + "editor.defaultFormatter": "jnoortheen.nix-ide" }, } diff --git a/nix/os/devices/router0-dmz0/configuration.nix b/nix/os/devices/router0-dmz0/configuration.nix index 632be00..71d3873 100644 --- a/nix/os/devices/router0-dmz0/configuration.nix +++ b/nix/os/devices/router0-dmz0/configuration.nix @@ -15,13 +15,34 @@ bpir3 nixos-nftables-firewall ; -in { - disabledModules = [ - # "services/networking/hostapd.nix" - ]; + mkVlanIpv4HostAddr = { vlanid, host, ipv4Offset ? 20, cidr ? true }: + builtins.concatStringsSep "." + [ "192" "168" (toString (ipv4Offset + vlanid)) "${toString host}${lib.strings.optionalString cidr "/24"}" ]; + + # vlanRangeStart = 1; + # vlanRangeEnd = 20; + # vlanRange = (lib.lists.range vlanRangeStart vlanRangeEnd); + vlanRange = builtins.map (vlanid: (lib.strings.toInt vlanid)) (builtins.attrNames vlans); + vlanRangeWith0 = [ 0 ] ++ vlanRange; + + defaultVlan = { + name = "internal"; + packet_priority = 0; + }; + vlans = { + "1".name = "dmz.${defaultVlan.name}"; + "1".packet_priority = 0; + "2".name = "iot.${defaultVlan.name}"; + "2".packet_priority = -10; + "3".name = "office.${defaultVlan.name}"; + "3".packet_priority = -5; + "4".name = "guests.${defaultVlan.name}"; + "4".packet_priority = 10; + }; + getVlanDomain = { vlanid }: vlans."${toString vlanid}".name or defaultVlan.name; +in { imports = [ - # nodeFlake.inputs.disko.nixosModules.disko repoFlake.inputs.sops-nix.nixosModules.sops ../../profiles/common/user.nix @@ -30,6 +51,17 @@ in { nixos-nftables-firewall.nixosModules.default + { + nix.nixPath = [ + "nixpkgs=${pkgs.path}" + ]; + + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + } + # TODO # ./network.nix # ./monitoring.nix @@ -43,11 +75,13 @@ in { rootPasswordFile = config.sops.secrets.passwords-root.path; }; - sops.secrets.passwords-root = { - sopsFile = ../../../../secrets/${nodeName}/secrets.yaml; - neededForUsers = true; - format = "yaml"; - }; + sops.defaultSopsFile = ../../../../secrets/${nodeName}/secrets.yaml; + sops.defaultSopsFormat = "yaml"; + + sops.secrets.passwords-root.neededForUsers = true; + + sops.secrets.wlan0_saePasswordsFile = { }; + sops.secrets.wlan0_wpaPskFile = { }; } ]; @@ -101,6 +135,8 @@ in { # Use the nftables firewall instead of the base nixos scripted rules. # This flake provides a similar utility to the base nixos scripting. # https://github.com/thelegy/nixos-nftables-firewall/tree/main + + # TODO: configure packet_priority for VLANs (see https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Base_chain_priority, https://wiki.nftables.org/wiki-nftables/index.php/Setting_packet_metainformation#packet_priority) nftables = { enable = true; stopRuleset = ""; @@ -108,26 +144,69 @@ in { enable = true; zones = { lan.interfaces = ["br-lan"]; + vlan.interfaces = builtins.map (vlanid: "br-vlan.${toString vlanid}") vlanRange; + # lan.ipv4Addresses = ["192.168.0.0/16"]; wan.interfaces = ["wan" "lan0"]; }; - rules = { - lan = { + rules = let + ipv6IcmpTypes = [ + "destination-unreachable" "echo-reply" "echo-request" + "packet-too-big" "parameter-problem" "time-exceeded" + + # Without the nd-* ones ipv6 will not work. + "nd-neighbor-solicit" "nd-router-advert" "nd-neighbor-advert" + ]; + ipv4IcmpTypes = [ + "destination-unreachable" "echo-reply" "echo-request" "source-quench" "time-exceeded" + "router-advertisement" + ]; + allowIcmpLines = [ + "ip protocol icmp icmp type { ${builtins.concatStringsSep ", " ipv4IcmpTypes} } accept" + "ip6 nexthdr icmpv6 icmpv6 type { ${builtins.concatStringsSep ", " ipv6IcmpTypes} } accept" + ]; + in { + lan-to-fw = { from = ["lan"]; to = ["fw"]; verdict = "accept"; }; - outbound = { - from = ["lan"]; - to = ["lan" "wan"]; - verdict = "accept"; - }; - nat = { + + lan-to-wan = { from = ["lan"]; to = ["wan"]; - masquerade = true; + verdict = "accept"; }; - incoming-wan = { + vlan-to-wan = { + from = ["vlan"]; + to = ["wan"]; + verdict = "accept"; + }; + + vlan-to-fw = { + allowedUDPPortRanges = [ + { from = 67; to = 68; } + { from = 53; to = 53; } + ]; + allowedTCPPortRanges = [ + { from = 22; to = 22; } + { from = 53; to = 53; } + ]; + from = ["vlan"]; + to = ["fw"]; + extraLines = allowIcmpLines ++ [ + "drop" + ]; + }; + + to-wan-nat = { + from = ["lan" "vlan"]; + to = ["wan"]; + masquerade = true; + verdict = "accept"; + }; + + wan-to-fw = { from = ["wan"]; to = ["fw"]; allowedTCPPortRanges = [ @@ -136,7 +215,9 @@ in { to = 22; } ]; - verdict = "drop"; + extraLines = allowIcmpLines ++ [ + "drop" + ]; }; }; }; @@ -157,50 +238,12 @@ in { extraConfig = '' [Bridge] STP=true - VLANFiltering=yes - DefaultPVID=none + # VLANFiltering=yes + # DefaultPVID=1 ''; }; }; networks = { - # Connect the bridge ports to the bridge - "30-lan1" = { - matchConfig.Name = "lan1"; - networkConfig = { - Bridge = "br-lan"; - ConfigureWithoutCarrier = true; - }; - linkConfig.RequiredForOnline = "enslaved"; - }; - "30-lan2" = { - matchConfig.Name = "lan2"; - networkConfig = { - Bridge = "br-lan"; - ConfigureWithoutCarrier = true; - }; - linkConfig.RequiredForOnline = "enslaved"; - }; - "30-lan3" = { - matchConfig.Name = "lan3"; - networkConfig = { - Bridge = "br-lan"; - ConfigureWithoutCarrier = true; - }; - linkConfig.RequiredForOnline = "enslaved"; - }; - # Configure the bridge for its desired function - "40-br-lan" = { - matchConfig.Name = "br-lan"; - bridgeConfig = {}; - address = [ - "192.168.10.1/24" - ]; - networkConfig = { - ConfigureWithoutCarrier = true; - }; - # Don't wait for it as it also would wait for wlan and DFS which takes around 5 min - linkConfig.RequiredForOnline = "no"; - }; # use lan0 as secondary WAN interface "10-lan0-wan" = { matchConfig.Name = "lan0"; @@ -232,15 +275,88 @@ in { # make routing on this interface a dependency for network-online.target linkConfig.RequiredForOnline = "routable"; }; - }; + + # Connect the bridge ports to the bridge + "30-lan1" = { + matchConfig.Name = "lan1"; + networkConfig = { + Bridge = "br-lan"; + ConfigureWithoutCarrier = true; + }; + linkConfig.RequiredForOnline = "enslaved"; + }; + "30-lan2" = { + matchConfig.Name = "lan2"; + networkConfig = { + Bridge = "br-lan"; + ConfigureWithoutCarrier = true; + }; + linkConfig.RequiredForOnline = "enslaved"; + }; + "30-lan3" = { + matchConfig.Name = "lan3"; + networkConfig = { + Bridge = "br-lan"; + ConfigureWithoutCarrier = true; + }; + linkConfig.RequiredForOnline = "enslaved"; + }; + # Configure the bridge for its desired function + "40-br-lan" = { + matchConfig.Name = "br-lan"; + bridgeConfig = {}; + address = [ + (mkVlanIpv4HostAddr { vlanid = 0; host = 1;}) + ]; + networkConfig = { + ConfigureWithoutCarrier = true; + }; + # Don't wait for it as it also would wait for wlan and DFS which takes around 5 min + linkConfig.RequiredForOnline = "no"; + + # TODO: understand when this would be needed + # bridgeVLANs = [ + # { + # bridgeVLANConfig = { + # VLAN = "${vlanRangeStart}-${vlanRangeEnd}"; + # }; + # } + # ]; + }; + } + # VLAN interface addresses + // + lib.attrsets.foldlAttrs + (acc: _: value: acc // value) + {} + (lib.attrsets.genAttrs + (builtins.map + builtins.toString + vlanRange + ) + (vlanid: { + "50-br-vlan.${vlanid}" = { + matchConfig.Name = "br-vlan.${toString vlanid}"; + address = [ + (mkVlanIpv4HostAddr { vlanid = (lib.strings.toInt vlanid); host = 1; }) + ]; + networkConfig = { + ConfigureWithoutCarrier = true; + }; + # Don't wait for it as it also would wait for wlan and DFS which takes around 5 min + linkConfig.RequiredForOnline = "no"; + }; + }) + ); }; # wireless access point services.hostapd = { enable = true; + package = nodeFlake.packages.hostapd_main; radios = let - mkBssid = i: # generated with https://miniwebtool.com/mac-address-generator/ - "34:56:ce:0f:ed:4${builtins.toString i}"; + # generated with https://miniwebtool.com/mac-address-generator/ + mkBssid = i: "34:56:ce:0f:ed:4${toString i}"; in { wlan0 = { band = "2g"; @@ -254,64 +370,68 @@ in { }; networks = { wlan0 = { - ssid = "justtestingwifi-wpa3"; - authentication = { - mode = "wpa3-sae"; - # saePasswordsFile = config.sops.secrets.wifiPassword.path; - saePasswords = [ - { - password = "normalnormal"; - } - { - password = "vlanvlan"; - vlanid = 1; - } - ]; - }; - + ssid = "mlsia"; bssid = mkBssid 0; - settings = { - bridge = "br-lan"; - }; - }; - wlan0-1 = { - ssid = "justtestingwifi-compat"; - authentication = { - mode = "wpa3-sae-transition"; - # saePasswordsFile = config.sops.secrets.wifiPassword.path; - saePasswords = [ - { - password = "normalnormal"; - } - { - password = "vlanvlan"; - vlanid = 1; - } - ]; - wpaPskFile = pkgs.writeText "wpa_psk" '' - 00:00:00:00:00:00 normalnormal - vlanid=1 00:00:00:00:00:00 vlanvlan - ''; - }; + # manually configure something close to wpa3-sae-transition + authentication.mode = "none"; + # authentication.saePasswordsFile = config.sops.secrets.wlan0_saePasswordsFile.path; - bssid = mkBssid 1; settings = { - bridge = "br-lan"; + # bridge = "br-lan"; + + logger_stdout_level= lib.mkForce 1; + logger_syslog_level= lib.mkForce 1; # resources on vlan tagging # https://wireless.wiki.kernel.org/en/users/Documentation/hostapd#dynamic_vlan_tagging # https://forum.openwrt.org/t/individual-per-passphrase-wifi-vlans-using-wpa-psk-file-no-radius-required/161696/4 - vlan_tagged_interface = "br-lan"; - vlan_bridge = "br-vlan"; + vlan_naming = 1; + vlan_bridge = "br-vlan."; dynamic_vlan = 1; - vlan_file = builtins.toString (pkgs.writeText "hostapd.vlan" '' - * wlan0-1.# + vlan_file = toString (pkgs.writeText "hostapd.vlan" '' + * wlan0.# ''); + + wpa_psk_file = config.sops.secrets.wlan0_wpaPskFile.path; + sae_password_file = config.sops.secrets.wlan0_saePasswordsFile.path; + + ieee80211w=1; + auth_algs = 3; + sae_require_mfp = 0; + sae_groups = "19 20 21"; + wpa = 2; + wpa_key_mgmt = "WPA-PSK WPA-PSK-SHA256 SAE"; + + # worked above here + # testing below here + + # ieee80211w = 2; + + # IEEE 802.11i (authentication) related configuration + # Encrypt management frames to protect against deauthentication and similar attacks + # ieee80211w = mkDefault 1; + # sae_require_mfp = mkDefault 1; + + # sae_require_mfp = 1; + # sae_groups = "19 20 21"; }; }; + # wlan0-1 = { + # ssid = "justtestingwifi-wpa3"; + # authentication = { + # mode = "wpa3-sae"; + # saePasswordsFile = config.sops.secrets.wlan0_1_saePasswordFile.path; + # }; + + # bssid = mkBssid 1; + # settings = { + # bridge = "br-lan"; + # }; + # }; + # Uncomment when needed otherwise remove # wlan0-1 = { # ssid = "koteczkowo3"; @@ -423,94 +543,75 @@ in { services.resolved.enable = false; - services.dnsmasq = { + services.dnsmasq = let + mkIfName = { vlanid }: if vlanid == 0 then "br-lan" else "br-vlan.${toString vlanid}"; + in { enable = true; settings = { - # upstream DNS servers - server = ["9.9.9.9" "8.8.8.8" "1.1.1.1"]; # sensible behaviours domain-needed = true; bogus-priv = true; no-resolv = true; - dhcp-range = [ - # "br-lan,192.168.10.50,192.168.10.100,24h" - "192.168.10.50,192.168.10.100,24h" - ]; + dhcp-range = let + mkDhcpRange = { tag, vlanid }: builtins.concatStringsSep "," [ + tag + (mkVlanIpv4HostAddr { inherit vlanid; host = 100; cidr = false; }) + (mkVlanIpv4HostAddr { inherit vlanid; host = 199; cidr = false; }) + "5m" + ]; + in + builtins.map + (vlanid: + mkDhcpRange { tag = mkIfName {inherit vlanid;}; inherit vlanid; } + ) + vlanRange + ; # interface = "br-lan"; # bind-interfaces = true; - # dhcp-host = "192.168.10.1"; # local domains - local = "/lan/"; - domain = "lan"; + # local = "/${getVlanDomain {vlanid = 0;}/"; + # domain = getVlanDomain {vlanid = 0;}; expand-hosts = true; # don't use /etc/hosts as this would advertise ${nodeName} as localhost no-hosts = true; - address = "/${nodeName}.lan/192.168.10.1"; + + # address = "/${nodeName}.lan/${fwLanHostAddr}"; + server = [ + # upstream DNS servers + "9.9.9.9" "8.8.8.8" "1.1.1.1" + ] ++ builtins.map + (vlanid: "/${nodeName}.${getVlanDomain {inherit vlanid;}}/") + vlanRangeWith0 + ; + + # TODO: compare this to using `interface-name` + dynamic-host = [ + ] ++ builtins.map + (vlanid: + builtins.concatStringsSep "," [ + "${nodeName}.${getVlanDomain{inherit vlanid;}}" "0.0.0.1" (mkIfName {inherit vlanid;}) + ] + ) + vlanRangeWith0 + ; + + dhcp-option-force = builtins.map + (vlanid: "option:domain-search,${getVlanDomain{inherit vlanid;}}") + vlanRangeWith0 + ; + + localise-queries = true; }; }; # The service irqbalance is useful as it assigns certain IRQ calls to specific CPUs instead of letting the first CPU core to handle everything. This is supposed to increase performance by hitting CPU cache more often. services.irqbalance.enable = true; - # disko.devices = { - # disk = { - # nvme0n1 = { - # device = "/dev/nvme0n1"; - # type = "disk"; - # content = { - # type = "table"; - # format = "gpt"; - # partitions = [ - # { - # name = "var-log"; - # start = "1MiB"; - # end = "20G"; - # content = { - # type = "filesystem"; - # format = "ext4"; - # mountpoint = "/var/log"; - # }; - # } - # { - # name = "tmp"; - # start = "20G"; - # end = "60G"; - # content = { - # type = "filesystem"; - # format = "ext4"; - # mountpoint = "/tmp"; - # }; - # } - # { - # name = "var"; - # start = "60G"; - # end = "100G"; - # content = { - # type = "filesystem"; - # format = "ext4"; - # mountpoint = "/var"; - # }; - # } - # { - # name = "swap"; - # start = "100G"; - # end = "100%"; - # content = { - # type = "swap"; - # randomEncryption = false; - # }; - # } - # ]; - # }; - # }; - # }; - # }; - system.stateVersion = "23.05"; boot.kernelPackages = pkgs.linuxPackages_bpir3; diff --git a/nix/os/devices/router0-dmz0/default.nix b/nix/os/devices/router0-dmz0/default.nix index e8d521a..59652be 100644 --- a/nix/os/devices/router0-dmz0/default.nix +++ b/nix/os/devices/router0-dmz0/default.nix @@ -9,6 +9,7 @@ in { meta.nodeSpecialArgs.${nodeName} = { inherit repoFlake nodeName nodeFlake system; packages' = repoFlake.packages.${system}; + nodePackages' = nodeFlake.packages.${system}; inherit (nodeFlake.inputs.bpir3.packages.${system}) diff --git a/nix/os/devices/router0-dmz0/flake.lock b/nix/os/devices/router0-dmz0/flake.lock index 06e3d64..345a940 100644 --- a/nix/os/devices/router0-dmz0/flake.lock +++ b/nix/os/devices/router0-dmz0/flake.lock @@ -7,10 +7,11 @@ ] }, "locked": { - "dirtyRev": "4210480bdebbf3a7953e22d5d9f183f47b725bff-dirty", - "dirtyShortRev": "4210480-dirty", - "lastModified": 1688620001, - "narHash": "sha256-INxwGchokdU3ESpnvmfkMWZhocM134FmhWQoyPqtg60=", + "lastModified": 1703182100, + "narHash": "sha256-zl2G9ex86b8G6J9+QT4n9g26G8dtandIt1LlFhZiaxE=", + "ref": "refs/heads/linux-6.6", + "rev": "953a04e6792c412a664212db6a64bbaaa35bff0a", + "revCount": 31, "type": "git", "url": "file:///home/steveej/src/steveej/nixos-bpir3" }, @@ -47,11 +48,11 @@ ] }, "locked": { - "lastModified": 1702569759, - "narHash": "sha256-Ze3AdEEsVZBRJ4wn13EZpV1Uubkzi59TkC4j2G9xoFI=", + "lastModified": 1703162528, + "narHash": "sha256-pQ41wN6JlStkZOhRTIHEpuwVywLdh+xzZQW1+FzdjVs=", "owner": "nix-community", "repo": "disko", - "rev": "98ab91109716871f50ea8cb0e0ac7cc1e1e14714", + "rev": "a050895e4eb06e0738680021a701ea05dc8dbfc9", "type": "github" }, "original": { @@ -82,11 +83,11 @@ ] }, "locked": { - "lastModified": 1702814335, - "narHash": "sha256-Qck7BAMi3eydzT1WFOzp/SgECetyPpOn1dLgmxH2ebQ=", + "lastModified": 1703368619, + "narHash": "sha256-ZGPMYL7FMA6enhuwby961bBANmoFX14EA86m2/Jw5Jo=", "owner": "nix-community", "repo": "home-manager", - "rev": "e4dba0bd01956170667458be7b45f68170a63651", + "rev": "a2523ea0343b056ba240abbac90ab5f116a7aa7b", "type": "github" }, "original": { @@ -96,6 +97,22 @@ "type": "github" } }, + "hostapd": { + "flake": false, + "locked": { + "lastModified": 1703346062, + "narHash": "sha256-SHSBKIgKc5zEGhKDT2v+yGERTJHf8pe+9ZPUwJBTJKQ=", + "ref": "refs/heads/main", + "rev": "196d6c83b9cb7d298fdc92684dc37115348b159e", + "revCount": 19119, + "type": "git", + "url": "git://w1.fi/hostap.git?branch=main" + }, + "original": { + "type": "git", + "url": "git://w1.fi/hostap.git?branch=main" + } + }, "nixos-nftables-firewall": { "inputs": { "dependencyDagOfSubmodule": "dependencyDagOfSubmodule", @@ -104,11 +121,11 @@ ] }, "locked": { - "lastModified": 1702744409, - "narHash": "sha256-dcDkc+6TF9EvfWpsLdmGz4hhrNVbQZDgFwvk5SOjYTI=", + "lastModified": 1703279052, + "narHash": "sha256-0rbG/9SwaWtXT7ZuifMq+7wvfxDpZrjr0zdMcM4KK+E=", "owner": "thelegy", "repo": "nixos-nftables-firewall", - "rev": "a33df9d2f586b85e8e7e546d9b99b39f3187c382", + "rev": "3bf23aeb346e772d157816e6b72a742a6c97db80", "type": "github" }, "original": { @@ -119,11 +136,11 @@ }, "nixos-stable": { "locked": { - "lastModified": 1702346276, - "narHash": "sha256-eAQgwIWApFQ40ipeOjVSoK4TEHVd6nbSd9fApiHIw5A=", + "lastModified": 1702921762, + "narHash": "sha256-O/rP7gulApQAB47u6szEd8Pn8Biw0d84j5iuP2tcxzY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "cf28ee258fd5f9a52de6b9865cdb93a1f96d09b7", + "rev": "d02ffbbe834b5599fc5f134e644e49397eb07188", "type": "github" }, "original": { @@ -135,11 +152,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1702312524, - "narHash": "sha256-gkZJRDBUCpTPBvQk25G0B7vfbpEYM5s5OZqghkjZsnE=", + "lastModified": 1703255338, + "narHash": "sha256-Z6wfYJQKmDN9xciTwU3cOiOk+NElxdZwy/FiHctCzjU=", "owner": "nixos", "repo": "nixpkgs", - "rev": "a9bf124c46ef298113270b1f84a164865987a91c", + "rev": "6df37dc6a77654682fe9f071c62b4242b5342e04", "type": "github" }, "original": { @@ -155,6 +172,7 @@ "disko": "disko", "get-flake": "get-flake", "home-manager": "home-manager", + "hostapd": "hostapd", "nixos-nftables-firewall": "nixos-nftables-firewall", "nixpkgs": "nixpkgs", "srvos": "srvos" @@ -168,11 +186,11 @@ ] }, "locked": { - "lastModified": 1702518612, - "narHash": "sha256-AGqIpvEMqo0FKXslmKL8ydt01pJFs8q3nUtz7gksoig=", + "lastModified": 1703258052, + "narHash": "sha256-gWGQxht/xRJRnA+35aHtpmev7snsM+2GBdaPyarXNqU=", "owner": "numtide", "repo": "srvos", - "rev": "cd802e2933c567ea91de48dbe8968f41a5d9a642", + "rev": "0c7eefd13776730f33ea28fb984dd95cb5357e8e", "type": "github" }, "original": { diff --git a/nix/os/devices/router0-dmz0/flake.nix b/nix/os/devices/router0-dmz0/flake.nix index 9a714b9..24f5f16 100644 --- a/nix/os/devices/router0-dmz0/flake.nix +++ b/nix/os/devices/router0-dmz0/flake.nix @@ -19,9 +19,10 @@ nixos-nftables-firewall.url = "github:thelegy/nixos-nftables-firewall"; nixos-nftables-firewall.inputs.nixpkgs.follows = "nixpkgs"; - }; - # outputs = _: {}; + hostapd.url = "git://w1.fi/hostap.git?branch=main"; + hostapd.flake = false; + }; outputs = { self, @@ -32,6 +33,7 @@ } @ attrs: let system = "aarch64-linux"; nodeName = "router0-dmz0"; + pkgs = nixpkgs.legacyPackages.${system}; mkNixosConfiguration = {extraModules ? [], ...} @ attrs: nixpkgs.lib.nixosSystem ( @@ -67,6 +69,7 @@ linuxPackages_bpir3 ; }) + ]; } ] @@ -88,5 +91,12 @@ ]; }; }; + + packages = { + hostapd_main = pkgs.hostapd.overrideDerivation(attrs: { + src = self.inputs.hostapd; + version = self.inputs.hostapd.rev; + }); + }; }; } diff --git a/secrets/router0-dmz0/secrets.yaml b/secrets/router0-dmz0/secrets.yaml index ee184e9..ade560c 100644 --- a/secrets/router0-dmz0/secrets.yaml +++ b/secrets/router0-dmz0/secrets.yaml @@ -4,6 +4,8 @@ ssh_host_ed25519_key: ENC[AES256_GCM,data:XQjTqNADLhisxPBIJ7x0bs3qgQk0u4q9HKSDuk ssh_host_ed25519_key_pub: ENC[AES256_GCM,data:MQ0q/I6clKNz6uzoztGA06vOjIbpK6Dsf3WbgddRA0B8nEJ4EUmRBT0KkX3o+LZmQPhmURHWWFtOSqvAzkyoxAoBZEh98H3IDsLE5PgcNbxK3dAh36+AAMPLzVFnHLyaWLQW,iv:9XIw29PkSHCeU7C2GuSJ+J+mBrwOrbSMmm7kOtCkiyI=,tag:x3JqFF08f2eVfOrrQ1gzYw==,type:str] ssh_host_rsa_key: ENC[AES256_GCM,data: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,iv:mXE8xpXFBYSJce9pg+g3OedMS9+ZHOHHwydCY0NbGRQ=,tag:cEqbUu9Y1PFKXwaeqioXWA==,type:str] ssh_host_rsa_key_pub: ENC[AES256_GCM,data:N60bGf/6KNRhVUq1EIbPVo3aBDDKEpMBr5+Gt3+FMPt3uQEaKk8jBg5mOdxWMTPoLg1ZP/Pme8afoM+Skc0b50WnpErF3Ox1w+4eM0oMJYOhIvHLGURNM3Dba5MgA7YfhPdTsVdjD2yks2vYqhdtEvzTTgCJbFimVJlp+wDqE6czPgMjD03c7oJDtv38OBtc1vRMzVw3cIuyxz2yNnXQxiMgTR6pZN7+Brami2dfXOHEVgymmlU5PRE8Ykerq2fB36N5uqu4/xSPaHaM+/f2OA/TLlYYB+sGMDExZfbO/vsiRBLvTY/f4KG2mEkmH+IFH1bk6UF47xTFEe8tHN/TlLo+9OmjZTph221ZYnOsIqBY+F822ctZEe8Ikz9Ti4F1ApvxxRcWHajbgQnDJdDiHJvt3OHal4rNBtYwxxV/MDZtvKSVxmFwgx7nwNP0oKhAigQkU7Mvp1q5p3dZsdbGCUeFm2S5/qIxWPfr7wg4xocLNSsLW1EpGo6A2RUXWIV+lPuZd9dNEjGC5zKKAgMI94is6MtMXgqlFqTcZuQ9hvhoVDcFhVSJylu8pzk9d/tKviwcd98jHAhdfGpnc9eJbtyBU6/HvxLzQpsbFjwa3LGirEdtgxRZn2nJx++0U6XuLcbGwjOVAhkde6g2vFv5hsC6KaZQcp4AFvMvEdJyrnb0b2TOeOD8zEljb8u2q/eexCRSjGpobEINwu5qV+tF9eHIJ1YFzhCSmmLGKXjc7bC8uv5ffl39JmAbUrffd18zqae+Xpijd+QzwF425NG9+PksAt+PPzt4SDgGfKBIpMNFxIb18oo88z4YDLuNzRy/HVF90JV0LlAxES4ZOxoWUjJPrR6dGxNRANYOyFGmoN+yG3B9kd1NRGRNGh5P9EtZBxlPIi24djzF1n4GQSW1NFDgoGcxaXhk0PlpPxwuHK0X9FkFDDzQUYNBhx7py+hev5rBUCs7Yhj5xgcM88fdLRZi8MulNws=,iv:8c3hDcJ8wzTugmJ3Mhzx/qEXnnlpFefBmRTG/MqyeEg=,tag:uSz6+CYu9uQa0C2DXnHPUA==,type:str] +wlan0_saePasswordsFile: ENC[AES256_GCM,data:Lq81rCQNUmrZi047UxvFI+Sg6YfBzPaTkK23FTwyfEtMIgHlAtY7lrW7lqR1iDEafOlK0uX8dUkQXRZzjuIbhP3UP/WYUtZ/RxoQdoQI9HAFXBG8g3RgD3OsW/3RY6VLkNFD5p3PST8wGpO1iXZzjJC8UH9WeAg3CcKdtPK+,iv:5rcrcVsbYaDhUTseIIDIC6oFEonCFkx9kYsA5DhMu8I=,tag:QQ3jX6kPiAd9IJfS7TkuvA==,type:str] +wlan0_wpaPskFile: ENC[AES256_GCM,data:rgPROqPL6wd4RacWU1loCG6v0h4Rh30sWdVuDKu72byzh1wyufP5+hNdJkw4zb69IdVmQGRekt9HGX6sQ4DlZz2MrDTYPH1dj+IXpJEHxCPM07a2rwCm+X9mgEkOkr2NURXVVaf9H7EpVnyXYvcNYmAVn9ZwC7rbYS3Xg7Y5OzMOQ7zabtw/8C1EZiJ9hZAzN8jyE1Gu9bgWSaRqGjLI08zbh6UqiNiTTcZhH5Wr2Z3sIfqlr6QJoQp+rAD2yQm6qefOJZWM+1ZlPtv1VCW8AN6oGKiVVdlK,iv:jEnkYarguNECjO2cTjSSgshJMszCuRAjqLQpDzXyTxs=,tag:Rx1wR3L3LCErHMud9goY5g==,type:str] sops: kms: [] gcp_kms: [] @@ -19,8 +21,8 @@ sops: THRNR0tEUzhPdFFhWWxvZlpKYmZKM2MKxc5s1jsci8jPOrvZAoofVNvHT4o9P6yv J8rALQQXgql6obK51Q/Doyzvo1RJ0T7epiWEAZm5B3vDrf6KqbWBYw== -----END AGE ENCRYPTED FILE----- - lastmodified: "2023-08-11T16:46:38Z" - mac: ENC[AES256_GCM,data:W9aRsPPRKro6rGbNvBV8bftPklQn6LN6Lq+G45vYTVRZs5t0F1qFqUpXDXKTrZ040mkYnECi7JSRWeJvyfGqHK5KPY1uWtBxDoghYfO/J7VXBNv+NbROO4KoAKYAoOpZSECVqXgm6U69G1GGu8yyrDPDFAcfbFXivXqH+e7t42A=,iv:uUndgDmUHBYCKvb2LHC9zRp+eBwcy6107ocaJFniV6o=,tag:VGKODnvz107hvEoCT0risw==,type:str] + lastmodified: "2023-12-24T18:56:12Z" + mac: ENC[AES256_GCM,data:PF4gJL0u0vbU5o79IYWByWo4bZgZ7qWw/+mJN+YNzG4Jti+2D7gwKOs9edCHUuSti8iVov1RciretQHfkis5JDydykjb03uMaV8r6lVCmB8i/JARHEr5Amq0wld30qHaCtCayTTWQNA05jdzZB4a2dSIAqJh/R5YTaJ7HY+eZ38=,iv:3ZEFA4YR5BfcOlA+0Zevk7MaLJN0zPbfLOP2Ci/I3bg=,tag:vLhoKPTNIE7U2VcGiH964Q==,type:str] pgp: - created_at: "2023-08-11T16:15:11Z" enc: |- -- 2.49.0 From c365970cdfc540a933ae3a13fceec4d240b58e54 Mon Sep 17 00:00:00 2001 From: Stefan Junker Date: Mon, 25 Dec 2023 00:03:23 +0100 Subject: [PATCH 3/7] WIP: router0-dmz0: snapshot with working VLAN assignment for WPA-PSK --- nix/os/devices/router0-dmz0/configuration.nix | 87 +++++++++++-------- secrets/router0-dmz0/secrets.yaml | 8 +- 2 files changed, 57 insertions(+), 38 deletions(-) diff --git a/nix/os/devices/router0-dmz0/configuration.nix b/nix/os/devices/router0-dmz0/configuration.nix index 71d3873..b1d1fa0 100644 --- a/nix/os/devices/router0-dmz0/configuration.nix +++ b/nix/os/devices/router0-dmz0/configuration.nix @@ -30,17 +30,29 @@ name = "internal"; packet_priority = 0; }; + vlans = { - "1".name = "dmz.${defaultVlan.name}"; - "1".packet_priority = 0; - "2".name = "iot.${defaultVlan.name}"; - "2".packet_priority = -10; - "3".name = "office.${defaultVlan.name}"; - "3".packet_priority = -5; - "4".name = "guests.${defaultVlan.name}"; + "1".name = "dmz"; + "1".packet_priority = -5; + + "2".name = "iot"; + "2".packet_priority = -5; + + "3".name = "office"; + "3".packet_priority = -10; + + "4".name = "guests"; "4".packet_priority = 10; + + "5".name = "smarties"; }; - getVlanDomain = { vlanid }: vlans."${toString vlanid}".name or defaultVlan.name; + getVlanDomain = { vlanid }: + if vlanid == 0 + then + defaultVlan.name + else + vlans."${toString vlanid}".name + "." + defaultVlan.name + ; in { imports = [ repoFlake.inputs.sops-nix.nixosModules.sops @@ -147,7 +159,10 @@ in { vlan.interfaces = builtins.map (vlanid: "br-vlan.${toString vlanid}") vlanRange; # lan.ipv4Addresses = ["192.168.0.0/16"]; wan.interfaces = ["wan" "lan0"]; - }; + } // + # TODO: generate a zone for each vlan + {} + ; rules = let ipv6IcmpTypes = [ "destination-unreachable" "echo-reply" "echo-request" @@ -373,49 +388,53 @@ in { ssid = "mlsia"; bssid = mkBssid 0; - # manually configure something close to wpa3-sae-transition - authentication.mode = "none"; - # authentication.saePasswordsFile = config.sops.secrets.wlan0_saePasswordsFile.path; + # authentication.mode = "wpa3-sae"; + authentication.mode = "wpa3-sae-transition"; + + authentication.wpaPskFile = config.sops.secrets.wlan0_wpaPskFile.path; + authentication.saePasswordsFile = config.sops.secrets.wlan0_saePasswordsFile.path; settings = { # bridge = "br-lan"; - logger_stdout_level= lib.mkForce 1; - logger_syslog_level= lib.mkForce 1; + # wpa_psk_file = config.sops.secrets.wlan0_wpaPskFile.path; + # not yet supported on hostapd 2.10 + # sae_password_file = config.sops.secrets.wlan0_saePasswordsFile.path; + + logger_stdout_level= lib.mkForce 0; + logger_syslog_level= lib.mkForce 0; # resources on vlan tagging # https://wireless.wiki.kernel.org/en/users/Documentation/hostapd#dynamic_vlan_tagging # https://forum.openwrt.org/t/individual-per-passphrase-wifi-vlans-using-wpa-psk-file-no-radius-required/161696/4 + vlan_tagged_interface = "br-lan"; vlan_naming = 1; vlan_bridge = "br-vlan."; dynamic_vlan = 1; vlan_file = toString (pkgs.writeText "hostapd.vlan" '' + # Optional wildcard entry matching all VLAN IDs. The first # in the interface + # name will be replaced with the VLAN ID. The network interfaces are created + # (and removed) dynamically based on the use. + # see https://w1.fi/cgit/hostap/tree/hostapd/hostapd.vlan * wlan0.# ''); - wpa_psk_file = config.sops.secrets.wlan0_wpaPskFile.path; - sae_password_file = config.sops.secrets.wlan0_saePasswordsFile.path; + wpa_key_mgmt = lib.mkForce (builtins.concatStringsSep " " [ + "WPA-PSK" - ieee80211w=1; - auth_algs = 3; - sae_require_mfp = 0; - sae_groups = "19 20 21"; - wpa = 2; - wpa_key_mgmt = "WPA-PSK WPA-PSK-SHA256 SAE"; + # TODO: the printer can't connect when this is on + # "WPA-PSK-SHA256" - # worked above here - # testing below here - - # ieee80211w = 2; + # unfortunately SAE doesn't support VLAN passwords in the way i'd like to use them + # "SAE" + ]); # IEEE 802.11i (authentication) related configuration # Encrypt management frames to protect against deauthentication and similar attacks - # ieee80211w = mkDefault 1; - # sae_require_mfp = mkDefault 1; - - # sae_require_mfp = 1; - # sae_groups = "19 20 21"; + ieee80211w = 1; + sae_require_mfp = 1; + sae_groups = "19 20 21"; }; }; @@ -565,7 +584,7 @@ in { (vlanid: mkDhcpRange { tag = mkIfName {inherit vlanid;}; inherit vlanid; } ) - vlanRange + vlanRangeWith0 ; # interface = "br-lan"; @@ -585,7 +604,7 @@ in { # upstream DNS servers "9.9.9.9" "8.8.8.8" "1.1.1.1" ] ++ builtins.map - (vlanid: "/${nodeName}.${getVlanDomain {inherit vlanid;}}/") + (vlanid: "/${getVlanDomain {inherit vlanid;}}/") vlanRangeWith0 ; @@ -601,7 +620,7 @@ in { ; dhcp-option-force = builtins.map - (vlanid: "option:domain-search,${getVlanDomain{inherit vlanid;}}") + (vlanid: "${mkIfName {inherit vlanid;}},option:domain-search,${getVlanDomain{inherit vlanid;}}") vlanRangeWith0 ; diff --git a/secrets/router0-dmz0/secrets.yaml b/secrets/router0-dmz0/secrets.yaml index ade560c..911924f 100644 --- a/secrets/router0-dmz0/secrets.yaml +++ b/secrets/router0-dmz0/secrets.yaml @@ -4,8 +4,8 @@ ssh_host_ed25519_key: ENC[AES256_GCM,data:XQjTqNADLhisxPBIJ7x0bs3qgQk0u4q9HKSDuk ssh_host_ed25519_key_pub: ENC[AES256_GCM,data:MQ0q/I6clKNz6uzoztGA06vOjIbpK6Dsf3WbgddRA0B8nEJ4EUmRBT0KkX3o+LZmQPhmURHWWFtOSqvAzkyoxAoBZEh98H3IDsLE5PgcNbxK3dAh36+AAMPLzVFnHLyaWLQW,iv:9XIw29PkSHCeU7C2GuSJ+J+mBrwOrbSMmm7kOtCkiyI=,tag:x3JqFF08f2eVfOrrQ1gzYw==,type:str] ssh_host_rsa_key: ENC[AES256_GCM,data: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,iv:mXE8xpXFBYSJce9pg+g3OedMS9+ZHOHHwydCY0NbGRQ=,tag:cEqbUu9Y1PFKXwaeqioXWA==,type:str] ssh_host_rsa_key_pub: ENC[AES256_GCM,data:N60bGf/6KNRhVUq1EIbPVo3aBDDKEpMBr5+Gt3+FMPt3uQEaKk8jBg5mOdxWMTPoLg1ZP/Pme8afoM+Skc0b50WnpErF3Ox1w+4eM0oMJYOhIvHLGURNM3Dba5MgA7YfhPdTsVdjD2yks2vYqhdtEvzTTgCJbFimVJlp+wDqE6czPgMjD03c7oJDtv38OBtc1vRMzVw3cIuyxz2yNnXQxiMgTR6pZN7+Brami2dfXOHEVgymmlU5PRE8Ykerq2fB36N5uqu4/xSPaHaM+/f2OA/TLlYYB+sGMDExZfbO/vsiRBLvTY/f4KG2mEkmH+IFH1bk6UF47xTFEe8tHN/TlLo+9OmjZTph221ZYnOsIqBY+F822ctZEe8Ikz9Ti4F1ApvxxRcWHajbgQnDJdDiHJvt3OHal4rNBtYwxxV/MDZtvKSVxmFwgx7nwNP0oKhAigQkU7Mvp1q5p3dZsdbGCUeFm2S5/qIxWPfr7wg4xocLNSsLW1EpGo6A2RUXWIV+lPuZd9dNEjGC5zKKAgMI94is6MtMXgqlFqTcZuQ9hvhoVDcFhVSJylu8pzk9d/tKviwcd98jHAhdfGpnc9eJbtyBU6/HvxLzQpsbFjwa3LGirEdtgxRZn2nJx++0U6XuLcbGwjOVAhkde6g2vFv5hsC6KaZQcp4AFvMvEdJyrnb0b2TOeOD8zEljb8u2q/eexCRSjGpobEINwu5qV+tF9eHIJ1YFzhCSmmLGKXjc7bC8uv5ffl39JmAbUrffd18zqae+Xpijd+QzwF425NG9+PksAt+PPzt4SDgGfKBIpMNFxIb18oo88z4YDLuNzRy/HVF90JV0LlAxES4ZOxoWUjJPrR6dGxNRANYOyFGmoN+yG3B9kd1NRGRNGh5P9EtZBxlPIi24djzF1n4GQSW1NFDgoGcxaXhk0PlpPxwuHK0X9FkFDDzQUYNBhx7py+hev5rBUCs7Yhj5xgcM88fdLRZi8MulNws=,iv:8c3hDcJ8wzTugmJ3Mhzx/qEXnnlpFefBmRTG/MqyeEg=,tag:uSz6+CYu9uQa0C2DXnHPUA==,type:str] -wlan0_saePasswordsFile: ENC[AES256_GCM,data:Lq81rCQNUmrZi047UxvFI+Sg6YfBzPaTkK23FTwyfEtMIgHlAtY7lrW7lqR1iDEafOlK0uX8dUkQXRZzjuIbhP3UP/WYUtZ/RxoQdoQI9HAFXBG8g3RgD3OsW/3RY6VLkNFD5p3PST8wGpO1iXZzjJC8UH9WeAg3CcKdtPK+,iv:5rcrcVsbYaDhUTseIIDIC6oFEonCFkx9kYsA5DhMu8I=,tag:QQ3jX6kPiAd9IJfS7TkuvA==,type:str] -wlan0_wpaPskFile: ENC[AES256_GCM,data:rgPROqPL6wd4RacWU1loCG6v0h4Rh30sWdVuDKu72byzh1wyufP5+hNdJkw4zb69IdVmQGRekt9HGX6sQ4DlZz2MrDTYPH1dj+IXpJEHxCPM07a2rwCm+X9mgEkOkr2NURXVVaf9H7EpVnyXYvcNYmAVn9ZwC7rbYS3Xg7Y5OzMOQ7zabtw/8C1EZiJ9hZAzN8jyE1Gu9bgWSaRqGjLI08zbh6UqiNiTTcZhH5Wr2Z3sIfqlr6QJoQp+rAD2yQm6qefOJZWM+1ZlPtv1VCW8AN6oGKiVVdlK,iv:jEnkYarguNECjO2cTjSSgshJMszCuRAjqLQpDzXyTxs=,tag:Rx1wR3L3LCErHMud9goY5g==,type:str] +wlan0_saePasswordsFile: ENC[AES256_GCM,data:p0M99C2Q6UrLzp5XZ/AvPpukzgaiZqFIWbIRGFFOOKygVt5r2zk4SZ6vCvoZQ0AfdlL+R6xsKZ4V6u9CZJsmHGgWewoTbszi4AGhWrwoFjhrWb+LWMBGZI7lOWjGclR0BoDgRYTtVDQDiLqUWjxQJBX7cgG2vf4V/ajnokRClNe1bRPN4fzaQskb,iv:g8m1SKRSAumXAQdFL6PlUeq2YWjl3LGDDv6nq9aA0yk=,tag:ODCqjfB2kEepcaJEzVEYFA==,type:str] +wlan0_wpaPskFile: ENC[AES256_GCM,data:TnQ794CQ8jEBT7BTynPpU0S1VpT2oS2rgKmaxfkW7v3mhV4ijgnsypixkCD6GmQdAL0vsKFq0tu76TqeqcpJ1tWTGdfg3UtTmZ/ARFu2y3jYVNhmFziBpYlOAd2e/oo0DpXhYUVZN3TvALF1dJ7aGt8XQewTaIYQBL04aietPXPHzPvecOLwNhnxMer6BAZG0HC/wpuwmmQ0CsR7Wbw/6Efn25oGXvITbndVbZoyC85bsckptYTSQmORKZH0Ew==,iv:UzOFbHZT37uDfaLVmOFGUG/Pv3kmq3pZLaZ0mkBCUQc=,tag:oq+dZefYEPneXiNeXVgHSw==,type:str] sops: kms: [] gcp_kms: [] @@ -21,8 +21,8 @@ sops: THRNR0tEUzhPdFFhWWxvZlpKYmZKM2MKxc5s1jsci8jPOrvZAoofVNvHT4o9P6yv J8rALQQXgql6obK51Q/Doyzvo1RJ0T7epiWEAZm5B3vDrf6KqbWBYw== -----END AGE ENCRYPTED FILE----- - lastmodified: "2023-12-24T18:56:12Z" - mac: ENC[AES256_GCM,data:PF4gJL0u0vbU5o79IYWByWo4bZgZ7qWw/+mJN+YNzG4Jti+2D7gwKOs9edCHUuSti8iVov1RciretQHfkis5JDydykjb03uMaV8r6lVCmB8i/JARHEr5Amq0wld30qHaCtCayTTWQNA05jdzZB4a2dSIAqJh/R5YTaJ7HY+eZ38=,iv:3ZEFA4YR5BfcOlA+0Zevk7MaLJN0zPbfLOP2Ci/I3bg=,tag:vLhoKPTNIE7U2VcGiH964Q==,type:str] + lastmodified: "2023-12-24T22:39:23Z" + mac: ENC[AES256_GCM,data:eNbO9GqcrcKg3qAMZDkOOcihUhWeXWCUHrbdiIIKomdp8hZdou6He1Dd5hPZJMrwuTfiYx9NcuRph/XXXYEMLIfRhb2Kw2LoKW4e/gZDj6rFSnRx/kqg/+oZLnnsZWnNYEhQTOEknpYNsjoBd1YOHqj9EvdABLCELvB9KfL7DnQ=,iv:bXlTOq1qeFldVH9dBotUoxHDNh/pG6eJOzS2SBI2R8s=,tag:foDEWwGMiYXpS6LiRual5w==,type:str] pgp: - created_at: "2023-08-11T16:15:11Z" enc: |- -- 2.49.0 From 8bcb433257cc672ed89befa090089d4165ff15d9 Mon Sep 17 00:00:00 2001 From: Stefan Junker Date: Tue, 26 Dec 2023 00:37:20 +0100 Subject: [PATCH 4/7] WIP: router0-dmz0: use bridge vlan filtering for the dynamic wlan interfaces --- nix/os/devices/router0-dmz0/configuration.nix | 252 +++++++++++++----- nix/os/devices/router0-dmz0/flake.nix | 6 + secrets/router0-dmz0/secrets.yaml | 8 +- 3 files changed, 202 insertions(+), 64 deletions(-) diff --git a/nix/os/devices/router0-dmz0/configuration.nix b/nix/os/devices/router0-dmz0/configuration.nix index b1d1fa0..497ba07 100644 --- a/nix/os/devices/router0-dmz0/configuration.nix +++ b/nix/os/devices/router0-dmz0/configuration.nix @@ -16,35 +16,46 @@ nixos-nftables-firewall ; - mkVlanIpv4HostAddr = { vlanid, host, ipv4Offset ? 20, cidr ? true }: - builtins.concatStringsSep "." - [ "192" "168" (toString (ipv4Offset + vlanid)) "${toString host}${lib.strings.optionalString cidr "/24"}" ]; - - # vlanRangeStart = 1; - # vlanRangeEnd = 20; - # vlanRange = (lib.lists.range vlanRangeStart vlanRangeEnd); + vlanRangeStart = builtins.head vlanRange; + vlanRangeEnd = builtins.elemAt vlanRange ((builtins.length vlanRange)-1); vlanRange = builtins.map (vlanid: (lib.strings.toInt vlanid)) (builtins.attrNames vlans); vlanRangeWith0 = [ 0 ] ++ vlanRange; + mkVlanIpv4HostAddr = { vlanid, host, thirdIpv4SegmentMin ? 20, cidr ? true }: let + # reserve the first subnet for vlanid == 0 + # number the other subnets continously from there + offset = + if vlanid == 0 + then thirdIpv4SegmentMin + else thirdIpv4SegmentMin + 1 - vlanRangeStart; + + in + builtins.concatStringsSep "." + [ "192" "168" (toString (vlanid + offset)) "${toString host}${lib.strings.optionalString cidr "/24"}" ]; + defaultVlan = { name = "internal"; packet_priority = 0; }; vlans = { - "1".name = "dmz"; - "1".packet_priority = -5; + "10".name = "mgmt"; + "10".packet_priority = 0; - "2".name = "iot"; - "2".packet_priority = -5; + "11".name = "dmz"; + "11".packet_priority = -5; - "3".name = "office"; - "3".packet_priority = -10; + "12".name = "iot"; + "12".packet_priority = -5; - "4".name = "guests"; - "4".packet_priority = 10; + "13".name = "office"; + "13".packet_priority = -10; - "5".name = "smarties"; + "14".name = "guests"; + "14".packet_priority = 10; + + "15".name = "iot2"; + "15".packet_priority = -10; }; getVlanDomain = { vlanid }: if vlanid == 0 @@ -72,6 +83,9 @@ in { "nix-command" "flakes" ]; + + nix.settings.max-jobs = lib.mkDefault "auto"; + nix.settings.cores = lib.mkDefault 0; } # TODO @@ -155,8 +169,8 @@ in { firewall = { enable = true; zones = { - lan.interfaces = ["br-lan"]; - vlan.interfaces = builtins.map (vlanid: "br-vlan.${toString vlanid}") vlanRange; + lan.interfaces = [ "br-lan" ]; + vlan.interfaces = builtins.map (vlanid: "br-lan.${toString vlanid}") vlanRange; # lan.ipv4Addresses = ["192.168.0.0/16"]; wan.interfaces = ["wan" "lan0"]; } // @@ -180,9 +194,14 @@ in { "ip6 nexthdr icmpv6 icmpv6 type { ${builtins.concatStringsSep ", " ipv6IcmpTypes} } accept" ]; in { + fw = { + from = ["fw"]; + verdict = "accept"; + }; + lan-to-fw = { from = ["lan"]; - to = ["fw"]; + to = ["fw" "lan"]; verdict = "accept"; }; @@ -206,6 +225,7 @@ in { allowedTCPPortRanges = [ { from = 22; to = 22; } { from = 53; to = 53; } + { from = 5201; to = 5201; } ]; from = ["vlan"]; to = ["fw"]; @@ -247,16 +267,25 @@ in { netdevConfig = { Kind = "bridge"; Name = "br-lan"; - }; extraConfig = '' [Bridge] - STP=true - # VLANFiltering=yes - # DefaultPVID=1 + STP=yes + VLANFiltering=yes + VLANProtocol=802.1q + DefaultPVID=0 ''; }; + + # TODO: generate one of these for each vlanid + "20-br-lan.15" = { + netdevConfig = { + Kind = "vlan"; + Name = "br-lan.15"; + }; + vlanConfig.Id = 15; + }; }; networks = { # use lan0 as secondary WAN interface @@ -308,6 +337,7 @@ in { }; linkConfig.RequiredForOnline = "enslaved"; }; + "30-lan3" = { matchConfig.Name = "lan3"; networkConfig = { @@ -315,6 +345,15 @@ in { ConfigureWithoutCarrier = true; }; linkConfig.RequiredForOnline = "enslaved"; + + bridgeVLANs = [ + { + bridgeVLANConfig = { + VLAN = "${toString vlanRangeStart}-${toString vlanRangeEnd}"; + }; + } + ]; + }; # Configure the bridge for its desired function "40-br-lan" = { @@ -328,40 +367,112 @@ in { }; # Don't wait for it as it also would wait for wlan and DFS which takes around 5 min linkConfig.RequiredForOnline = "no"; + linkConfig.ActivationPolicy = "always-up"; - # TODO: understand when this would be needed - # bridgeVLANs = [ - # { - # bridgeVLANConfig = { - # VLAN = "${vlanRangeStart}-${vlanRangeEnd}"; - # }; - # } - # ]; - }; - } - # VLAN interface addresses - // - lib.attrsets.foldlAttrs - (acc: _: value: acc // value) - {} - (lib.attrsets.genAttrs - (builtins.map - builtins.toString - vlanRange - ) - (vlanid: { - "50-br-vlan.${vlanid}" = { - matchConfig.Name = "br-vlan.${toString vlanid}"; - address = [ - (mkVlanIpv4HostAddr { vlanid = (lib.strings.toInt vlanid); host = 1; }) - ]; - networkConfig = { - ConfigureWithoutCarrier = true; + bridgeVLANs = [ + { + bridgeVLANConfig = { + VLAN = "${toString vlanRangeStart}-${toString vlanRangeEnd}"; }; - # Don't wait for it as it also would wait for wlan and DFS which takes around 5 min - linkConfig.RequiredForOnline = "no"; + } + ]; + + vlan = [ + "br-lan.15" + ]; + }; + + # TODO: generate one of these for each vlanid + "41-br-lan.15" = let + vlanid = 15; + in { + matchConfig.Name = "br-lan.15"; + address = [ + (mkVlanIpv4HostAddr { inherit vlanid; host = 1; }) + ]; + networkConfig = { + ConfigureWithoutCarrier = true; + }; + + linkConfig.RequiredForOnline = "no"; + linkConfig.ActivationPolicy = "always-up"; + + bridgeVLANs = [ + { + bridgeVLANConfig = { + # TODO debug this: each vlanid is native to each port + VLAN = vlanid; + }; + } + ]; + }; + + # TODO: generate one of these for each vlanid + # configure the wlan interface as a bridge member that + # * only gets traffic for vid 15 + # * untags traffic after receiving it + # * tags traffic that comes out of it + "41-wlan0.15" = let + vlanid = 15; + in { + matchConfig.Name = "wlan0.15"; + networkConfig = { + Bridge = "br-lan"; + ConfigureWithoutCarrier = true; + }; + + linkConfig.RequiredForOnline = "no"; + + bridgeVLANs = [ + { + bridgeVLANConfig = { + # TODO debug this: each vlanid is native to each port + VLAN = vlanid; + PVID = vlanid; + EgressUntagged = vlanid; + }; + } + ]; + }; + + } + + # configuration for the hostapd dynamic interfaces + # TODO: refactor this to configure the following per vlanid + # * netdev type vlan + # * host address for vlan + # * vlan config for wlan interface + // + builtins.foldl' + (acc: cur: acc // cur) + {} + (builtins.map + ({ vlanid, vlanid' }: { + "50-br-lan.${vlanid'}" = { + matchConfig.Name = "br-lan.${vlanid'}"; + address = [ + (mkVlanIpv4HostAddr { inherit vlanid; host = 1; }) + ]; + networkConfig = { + ConfigureWithoutCarrier = true; }; - }) + linkConfig.RequiredForOnline = "no"; + + bridgeVLANs = [ + { + bridgeVLANConfig = { + # TODO debug this: each vlanid is native to each port + VLAN = vlanid; + PVID = vlanid; + }; + } + ]; + }; + }) + (builtins.map + (vlanid: { inherit vlanid; vlanid' = builtins.toString vlanid; }) + vlanRange + ) ); }; @@ -384,15 +495,17 @@ in { capabilities = ["HT40+" "LDPC" "SHORT-GI-20" "SHORT-GI-40" "TX-STBC" "RX-STBC1" "MAX-AMSDU-7935"]; }; networks = { - wlan0 = { + wlan0 = let + iface = "wlan0"; + in { ssid = "mlsia"; bssid = mkBssid 0; # authentication.mode = "wpa3-sae"; authentication.mode = "wpa3-sae-transition"; - authentication.wpaPskFile = config.sops.secrets.wlan0_wpaPskFile.path; - authentication.saePasswordsFile = config.sops.secrets.wlan0_saePasswordsFile.path; + authentication.wpaPskFile = config.sops.secrets."${iface}_wpaPskFile".path; + authentication.saePasswordsFile = config.sops.secrets."${iface}_saePasswordsFile".path; settings = { # bridge = "br-lan"; @@ -410,16 +523,18 @@ in { vlan_tagged_interface = "br-lan"; vlan_naming = 1; - vlan_bridge = "br-vlan."; + vlan_bridge = "br-${iface}."; dynamic_vlan = 1; vlan_file = toString (pkgs.writeText "hostapd.vlan" '' # Optional wildcard entry matching all VLAN IDs. The first # in the interface # name will be replaced with the VLAN ID. The network interfaces are created # (and removed) dynamically based on the use. # see https://w1.fi/cgit/hostap/tree/hostapd/hostapd.vlan - * wlan0.# + * ${iface}.# ''); + vlan_no_bridge = 1; + wpa_key_mgmt = lib.mkForce (builtins.concatStringsSep " " [ "WPA-PSK" @@ -563,7 +678,7 @@ in { services.resolved.enable = false; services.dnsmasq = let - mkIfName = { vlanid }: if vlanid == 0 then "br-lan" else "br-vlan.${toString vlanid}"; + mkIfName = { vlanid }: if vlanid == 0 then "br-lan" else "br-lan.${toString vlanid}"; in { enable = true; settings = { @@ -695,5 +810,22 @@ in { environment.systemPackages = [ pkgs.ethtool + pkgs.neovim + + (pkgs.writeShellScriptBin "dbg-ip" '' + echo links: + ip -br -c l + echo + echo addresses: + ip -br -c a + echo + echo vlans: + bridge -c vlan + '') + + (pkgs.writeShellScriptBin "dbg-dnsmasq" '' + # get the rendered in-use config + pgrep -a dnsmasq | grep -Eo '[^ ]*conf' | xargs cat | grep -Eo '[^=]*conf' | xargs cat + '') ]; } diff --git a/nix/os/devices/router0-dmz0/flake.nix b/nix/os/devices/router0-dmz0/flake.nix index 24f5f16..bd9e3b4 100644 --- a/nix/os/devices/router0-dmz0/flake.nix +++ b/nix/os/devices/router0-dmz0/flake.nix @@ -96,6 +96,12 @@ hostapd_main = pkgs.hostapd.overrideDerivation(attrs: { src = self.inputs.hostapd; version = self.inputs.hostapd.rev; + patches = attrs.patches ++ [ + (builtins.fetchurl { + url = "https://raw.githubusercontent.com/openwrt/openwrt/main/package/network/services/hostapd/patches/710-vlan_no_bridge.patch"; + sha256 = "sha256:1p6fjjdwx5xrxyvllfrmvdkiji7bgx997k1qmp199bbic1fq6ks9"; + }) + ]; }); }; }; diff --git a/secrets/router0-dmz0/secrets.yaml b/secrets/router0-dmz0/secrets.yaml index 911924f..56e013e 100644 --- a/secrets/router0-dmz0/secrets.yaml +++ b/secrets/router0-dmz0/secrets.yaml @@ -4,8 +4,8 @@ ssh_host_ed25519_key: ENC[AES256_GCM,data:XQjTqNADLhisxPBIJ7x0bs3qgQk0u4q9HKSDuk ssh_host_ed25519_key_pub: ENC[AES256_GCM,data:MQ0q/I6clKNz6uzoztGA06vOjIbpK6Dsf3WbgddRA0B8nEJ4EUmRBT0KkX3o+LZmQPhmURHWWFtOSqvAzkyoxAoBZEh98H3IDsLE5PgcNbxK3dAh36+AAMPLzVFnHLyaWLQW,iv:9XIw29PkSHCeU7C2GuSJ+J+mBrwOrbSMmm7kOtCkiyI=,tag:x3JqFF08f2eVfOrrQ1gzYw==,type:str] ssh_host_rsa_key: ENC[AES256_GCM,data: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,iv:mXE8xpXFBYSJce9pg+g3OedMS9+ZHOHHwydCY0NbGRQ=,tag:cEqbUu9Y1PFKXwaeqioXWA==,type:str] ssh_host_rsa_key_pub: ENC[AES256_GCM,data:N60bGf/6KNRhVUq1EIbPVo3aBDDKEpMBr5+Gt3+FMPt3uQEaKk8jBg5mOdxWMTPoLg1ZP/Pme8afoM+Skc0b50WnpErF3Ox1w+4eM0oMJYOhIvHLGURNM3Dba5MgA7YfhPdTsVdjD2yks2vYqhdtEvzTTgCJbFimVJlp+wDqE6czPgMjD03c7oJDtv38OBtc1vRMzVw3cIuyxz2yNnXQxiMgTR6pZN7+Brami2dfXOHEVgymmlU5PRE8Ykerq2fB36N5uqu4/xSPaHaM+/f2OA/TLlYYB+sGMDExZfbO/vsiRBLvTY/f4KG2mEkmH+IFH1bk6UF47xTFEe8tHN/TlLo+9OmjZTph221ZYnOsIqBY+F822ctZEe8Ikz9Ti4F1ApvxxRcWHajbgQnDJdDiHJvt3OHal4rNBtYwxxV/MDZtvKSVxmFwgx7nwNP0oKhAigQkU7Mvp1q5p3dZsdbGCUeFm2S5/qIxWPfr7wg4xocLNSsLW1EpGo6A2RUXWIV+lPuZd9dNEjGC5zKKAgMI94is6MtMXgqlFqTcZuQ9hvhoVDcFhVSJylu8pzk9d/tKviwcd98jHAhdfGpnc9eJbtyBU6/HvxLzQpsbFjwa3LGirEdtgxRZn2nJx++0U6XuLcbGwjOVAhkde6g2vFv5hsC6KaZQcp4AFvMvEdJyrnb0b2TOeOD8zEljb8u2q/eexCRSjGpobEINwu5qV+tF9eHIJ1YFzhCSmmLGKXjc7bC8uv5ffl39JmAbUrffd18zqae+Xpijd+QzwF425NG9+PksAt+PPzt4SDgGfKBIpMNFxIb18oo88z4YDLuNzRy/HVF90JV0LlAxES4ZOxoWUjJPrR6dGxNRANYOyFGmoN+yG3B9kd1NRGRNGh5P9EtZBxlPIi24djzF1n4GQSW1NFDgoGcxaXhk0PlpPxwuHK0X9FkFDDzQUYNBhx7py+hev5rBUCs7Yhj5xgcM88fdLRZi8MulNws=,iv:8c3hDcJ8wzTugmJ3Mhzx/qEXnnlpFefBmRTG/MqyeEg=,tag:uSz6+CYu9uQa0C2DXnHPUA==,type:str] -wlan0_saePasswordsFile: ENC[AES256_GCM,data:p0M99C2Q6UrLzp5XZ/AvPpukzgaiZqFIWbIRGFFOOKygVt5r2zk4SZ6vCvoZQ0AfdlL+R6xsKZ4V6u9CZJsmHGgWewoTbszi4AGhWrwoFjhrWb+LWMBGZI7lOWjGclR0BoDgRYTtVDQDiLqUWjxQJBX7cgG2vf4V/ajnokRClNe1bRPN4fzaQskb,iv:g8m1SKRSAumXAQdFL6PlUeq2YWjl3LGDDv6nq9aA0yk=,tag:ODCqjfB2kEepcaJEzVEYFA==,type:str] -wlan0_wpaPskFile: ENC[AES256_GCM,data:TnQ794CQ8jEBT7BTynPpU0S1VpT2oS2rgKmaxfkW7v3mhV4ijgnsypixkCD6GmQdAL0vsKFq0tu76TqeqcpJ1tWTGdfg3UtTmZ/ARFu2y3jYVNhmFziBpYlOAd2e/oo0DpXhYUVZN3TvALF1dJ7aGt8XQewTaIYQBL04aietPXPHzPvecOLwNhnxMer6BAZG0HC/wpuwmmQ0CsR7Wbw/6Efn25oGXvITbndVbZoyC85bsckptYTSQmORKZH0Ew==,iv:UzOFbHZT37uDfaLVmOFGUG/Pv3kmq3pZLaZ0mkBCUQc=,tag:oq+dZefYEPneXiNeXVgHSw==,type:str] +wlan0_saePasswordsFile: ENC[AES256_GCM,data:ylY1LwMYlHdvYIVPIIr65BuxkW/BHCikkbGO5nNSU9WVekWiDXNIt2EQ2sYcdqnvZMGvcG0G4SQvCwpNO8ihh/RqcLYpTxldI8zwSqAwvATu7prV8l2bCvBQ+NXZ3yAW,iv:L6ncjd0u316gF/3InI7cuqO1kDpH7ahWGcsssYfb2YU=,tag:IAqt8vSDjW3OasOTJ44PeQ==,type:str] +wlan0_wpaPskFile: ENC[AES256_GCM,data:I/30uOrCPoWqnNq4WelPsDMevrmO+TuzmNrjMtPeCLS5MncX7BnX20YV5LxLsLCJS0NmCEqE58pgpeQEaUUcR0YRejCdO0yZnpMRbla6IR/irNSR/xctDQmMV6HYe6IKWE2d2LA/qWTkj+uBGJ0NtAsPIRLknuCwT8SLjClzF4/WCdoqHvxhBCESxhd3OTYr9op9uxk94iRxKsFfUBuNnckIeT/tQKqOQIHlkpperGBNRtTZ9q+Glb6lqFO1o/BJ8tAGpw0qyNO48jrRAtiIG3sauMH+UPWp86AYPhwQjwA6iDReFoH5KhZsohJSTX4vwoj46yycOTPu/loHrxySBSrYuRyOuIv7mwpRVZgJP+c3ZcngVncE3YQhLA==,iv:AlQIFKqcFSnyH1LrRN/XaTTocsMjZM20YHWcz7S3gCE=,tag:octNvum5lOOUOS6ALJ0x4g==,type:str] sops: kms: [] gcp_kms: [] @@ -21,8 +21,8 @@ sops: THRNR0tEUzhPdFFhWWxvZlpKYmZKM2MKxc5s1jsci8jPOrvZAoofVNvHT4o9P6yv J8rALQQXgql6obK51Q/Doyzvo1RJ0T7epiWEAZm5B3vDrf6KqbWBYw== -----END AGE ENCRYPTED FILE----- - lastmodified: "2023-12-24T22:39:23Z" - mac: ENC[AES256_GCM,data:eNbO9GqcrcKg3qAMZDkOOcihUhWeXWCUHrbdiIIKomdp8hZdou6He1Dd5hPZJMrwuTfiYx9NcuRph/XXXYEMLIfRhb2Kw2LoKW4e/gZDj6rFSnRx/kqg/+oZLnnsZWnNYEhQTOEknpYNsjoBd1YOHqj9EvdABLCELvB9KfL7DnQ=,iv:bXlTOq1qeFldVH9dBotUoxHDNh/pG6eJOzS2SBI2R8s=,tag:foDEWwGMiYXpS6LiRual5w==,type:str] + lastmodified: "2023-12-25T21:25:35Z" + mac: ENC[AES256_GCM,data:Sk3eyBaxhL7cX78YprYsv75oO+auEoxxGHCk1MRYGcAkat3vrc2vXjmKn6SsVQC8SWvu2YR2dOGU85Z7FCUUmmnwKeh+1PKMsurwfrNkB4umADXjaESNUWNevzAK9LR4pI1I6rGzl7mFEFYGEPd948JMOfkIfwNm1KMmETGkkI0=,iv:UzfDF94UFjPuEgRkpkRyLxSwZGymZclboHYQ/HxulJQ=,tag:MIBhvegV4NaZF+nGShotPw==,type:str] pgp: - created_at: "2023-08-11T16:15:11Z" enc: |- -- 2.49.0 From c0a8792af70f61e770acd93c12f2f54869d86081 Mon Sep 17 00:00:00 2001 From: Stefan Junker Date: Tue, 26 Dec 2023 16:18:33 +0100 Subject: [PATCH 5/7] feat(router0-dmz0): AP with dynamic vlan filtering on central bridge --- flake.lock | 14 +- nix/os/devices/router0-dmz0/configuration.nix | 163 ++++++++++-------- nix/os/devices/router0-dmz0/default.nix | 5 +- nix/os/devices/router0-dmz0/flake.lock | 62 ++++--- nix/os/devices/router0-dmz0/flake.nix | 71 +++++--- 5 files changed, 189 insertions(+), 126 deletions(-) diff --git a/flake.lock b/flake.lock index b026e10..ea8adae 100644 --- a/flake.lock +++ b/flake.lock @@ -27,11 +27,11 @@ "stable": "stable" }, "locked": { - "lastModified": 1688224393, - "narHash": "sha256-rsAvFNhRFzTF7qyb6WprLFghJnRxMFjvD2e5/dqMp4I=", + "lastModified": 1699171528, + "narHash": "sha256-ZsN6y+tgN5w84oAqRQpMhIvQM39ZNSZoZvn2AK0QYr4=", "owner": "zhaofengli", "repo": "colmena", - "rev": "19384f3ee2058c56021e4465a3ec57e84a47d8dd", + "rev": "665603956a1c3040d756987bc7a810ffe86a3b15", "type": "github" }, "original": { @@ -746,16 +746,16 @@ }, "stable": { "locked": { - "lastModified": 1669735802, - "narHash": "sha256-qtG/o/i5ZWZLmXw108N2aPiVsxOcidpHJYNkT45ry9Q=", + "lastModified": 1696039360, + "narHash": "sha256-g7nIUV4uq1TOVeVIDEZLb005suTWCUjSY0zYOlSBsyE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "731cc710aeebecbf45a258e977e8b68350549522", + "rev": "32dcb45f66c0487e92db8303a798ebc548cadedc", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-22.11", + "ref": "nixos-23.05", "repo": "nixpkgs", "type": "github" } diff --git a/nix/os/devices/router0-dmz0/configuration.nix b/nix/os/devices/router0-dmz0/configuration.nix index 497ba07..f62b0e8 100644 --- a/nix/os/devices/router0-dmz0/configuration.nix +++ b/nix/os/devices/router0-dmz0/configuration.nix @@ -1,7 +1,5 @@ { - modulesPath, repoFlake, - packages', pkgs, lib, config, @@ -154,7 +152,7 @@ in { useNetworkd = true; useDHCP = false; - # No local firewall. + # these will be configured via nftables nat.enable = lib.mkForce false; firewall.enable = lib.mkForce false; @@ -278,15 +276,27 @@ in { ''; }; - # TODO: generate one of these for each vlanid - "20-br-lan.15" = { - netdevConfig = { - Kind = "vlan"; - Name = "br-lan.15"; - }; - vlanConfig.Id = 15; - }; - }; + } + # generate the vlan devices. these will be tagged on the main bridge + // builtins.foldl' + (acc: cur: acc // cur) + {} + (builtins.map + ({ vlanid, vlanid' }: { + "20-br-lan.${vlanid'}" = { + netdevConfig = { + Kind = "vlan"; + Name = "br-lan.${vlanid'}"; + }; + vlanConfig.Id = vlanid; + }; + }) + (builtins.map + (vlanid: { inherit vlanid; vlanid' = builtins.toString vlanid; }) + vlanRange + ) + ) + ; networks = { # use lan0 as secondary WAN interface "10-lan0-wan" = { @@ -377,16 +387,28 @@ in { } ]; - vlan = [ - "br-lan.15" - ]; + vlan = (builtins.map + (vlanid: "br-lan.${builtins.toString vlanid}") + vlanRange + ); }; - # TODO: generate one of these for each vlanid - "41-br-lan.15" = let - vlanid = 15; - in { - matchConfig.Name = "br-lan.15"; + } + + # configuration for the hostapd dynamic interfaces + # TODO: refactor this to configure the following per vlanid + # * netdev type vlan + # * host address for vlan + # * vlan config for wlan interface + // + builtins.foldl' + (acc: cur: acc // cur) + {} + (builtins.map ({ vlanid, vlanid' }: { + # set an address on the tagged br-lan device. + # this address will be picked up by dnsmasq. + "41-br-lan.${vlanid'}" = { + matchConfig.Name = "br-lan.${vlanid'}"; address = [ (mkVlanIpv4HostAddr { inherit vlanid; host = 1; }) ]; @@ -407,15 +429,12 @@ in { ]; }; - # TODO: generate one of these for each vlanid # configure the wlan interface as a bridge member that # * only gets traffic for vid 15 # * untags traffic after receiving it # * tags traffic that comes out of it - "41-wlan0.15" = let - vlanid = 15; - in { - matchConfig.Name = "wlan0.15"; + "41-wlan0.${vlanid'}" = { + matchConfig.Name = "wlan0.${vlanid'}"; networkConfig = { Bridge = "br-lan"; ConfigureWithoutCarrier = true; @@ -435,51 +454,38 @@ in { ]; }; - } - - # configuration for the hostapd dynamic interfaces - # TODO: refactor this to configure the following per vlanid - # * netdev type vlan - # * host address for vlan - # * vlan config for wlan interface - // - builtins.foldl' - (acc: cur: acc // cur) - {} - (builtins.map - ({ vlanid, vlanid' }: { - "50-br-lan.${vlanid'}" = { - matchConfig.Name = "br-lan.${vlanid'}"; - address = [ - (mkVlanIpv4HostAddr { inherit vlanid; host = 1; }) - ]; - networkConfig = { - ConfigureWithoutCarrier = true; - }; - linkConfig.RequiredForOnline = "no"; - - bridgeVLANs = [ - { - bridgeVLANConfig = { - # TODO debug this: each vlanid is native to each port - VLAN = vlanid; - PVID = vlanid; - }; - } - ]; + "50-br-lan.${vlanid'}" = { + matchConfig.Name = "br-lan.${vlanid'}"; + address = [ + (mkVlanIpv4HostAddr { inherit vlanid; host = 1; }) + ]; + networkConfig = { + ConfigureWithoutCarrier = true; }; - }) - (builtins.map - (vlanid: { inherit vlanid; vlanid' = builtins.toString vlanid; }) - vlanRange - ) - ); + linkConfig.RequiredForOnline = "no"; + + bridgeVLANs = [ + { + bridgeVLANConfig = { + # TODO debug this: each vlanid is native to each port + VLAN = vlanid; + PVID = vlanid; + }; + } + ]; + }; + }) + (builtins.map + (vlanid: { inherit vlanid; vlanid' = builtins.toString vlanid; }) + vlanRange + )) + ; }; # wireless access point services.hostapd = { enable = true; - package = nodeFlake.packages.hostapd_main; + package = nodeFlake.packages.${system}.hostapd_patched; radios = let # generated with https://miniwebtool.com/mac-address-generator/ mkBssid = i: "34:56:ce:0f:ed:4${toString i}"; @@ -521,19 +527,34 @@ in { # https://wireless.wiki.kernel.org/en/users/Documentation/hostapd#dynamic_vlan_tagging # https://forum.openwrt.org/t/individual-per-passphrase-wifi-vlans-using-wpa-psk-file-no-radius-required/161696/4 + dynamic_vlan = 1; + + vlan_no_bridge = 1; + + /* not used due to the above vlan_no_bridge setting vlan_tagged_interface = "br-lan"; vlan_naming = 1; vlan_bridge = "br-${iface}."; - dynamic_vlan = 1; - vlan_file = toString (pkgs.writeText "hostapd.vlan" '' + */ + + vlan_file = let + generated = builtins.map (vlanid: + "${builtins.toString vlanid} ${iface}.${builtins.toString vlanid}" + ) vlanRange + ; + + wildcard = [ # Optional wildcard entry matching all VLAN IDs. The first # in the interface # name will be replaced with the VLAN ID. The network interfaces are created # (and removed) dynamically based on the use. # see https://w1.fi/cgit/hostap/tree/hostapd/hostapd.vlan - * ${iface}.# - ''); + "* ${iface}.#" + ]; - vlan_no_bridge = 1; + file = pkgs.writeText "hostapd.vlan" + (builtins.concatStringsSep "\n" (generated ++ wildcard)); + filePath = toString file; + in filePath; wpa_key_mgmt = lib.mkForce (builtins.concatStringsSep " " [ "WPA-PSK" @@ -692,7 +713,7 @@ in { tag (mkVlanIpv4HostAddr { inherit vlanid; host = 100; cidr = false; }) (mkVlanIpv4HostAddr { inherit vlanid; host = 199; cidr = false; }) - "5m" + "30m" ]; in builtins.map @@ -748,7 +769,7 @@ in { system.stateVersion = "23.05"; - boot.kernelPackages = pkgs.linuxPackages_bpir3; + boot.kernelPackages = pkgs.linuxPackages_bpir3_latest; # We exclude a number of modules included in the default list. A non-insignificant amount do # not apply to embedded hardware like this, so simply skip the defaults. # diff --git a/nix/os/devices/router0-dmz0/default.nix b/nix/os/devices/router0-dmz0/default.nix index 59652be..e29beb2 100644 --- a/nix/os/devices/router0-dmz0/default.nix +++ b/nix/os/devices/router0-dmz0/default.nix @@ -1,11 +1,10 @@ { + system ? "aarch64-linux", nodeName, repoFlake, nodeFlake, ... -}: let - system = "aarch64-linux"; -in { +}: { meta.nodeSpecialArgs.${nodeName} = { inherit repoFlake nodeName nodeFlake system; packages' = repoFlake.packages.${system}; diff --git a/nix/os/devices/router0-dmz0/flake.lock b/nix/os/devices/router0-dmz0/flake.lock index 345a940..089ad5e 100644 --- a/nix/os/devices/router0-dmz0/flake.lock +++ b/nix/os/devices/router0-dmz0/flake.lock @@ -7,17 +7,18 @@ ] }, "locked": { - "lastModified": 1703182100, - "narHash": "sha256-zl2G9ex86b8G6J9+QT4n9g26G8dtandIt1LlFhZiaxE=", - "ref": "refs/heads/linux-6.6", - "rev": "953a04e6792c412a664212db6a64bbaaa35bff0a", - "revCount": 31, - "type": "git", - "url": "file:///home/steveej/src/steveej/nixos-bpir3" + "lastModified": 1703603768, + "narHash": "sha256-ZViXHNt7ClqNtlRO9iot+LxiSbBvZi/RR+/6Q7W6UV8=", + "owner": "steveej-forks", + "repo": "nixos-bpir3", + "rev": "47cb545b92c136d1482a66b940c4719c40eb5fe3", + "type": "github" }, "original": { - "type": "git", - "url": "file:///home/steveej/src/steveej/nixos-bpir3" + "owner": "steveej-forks", + "ref": "linux-6.6", + "repo": "nixos-bpir3", + "type": "github" } }, "dependencyDagOfSubmodule": { @@ -48,11 +49,11 @@ ] }, "locked": { - "lastModified": 1703162528, - "narHash": "sha256-pQ41wN6JlStkZOhRTIHEpuwVywLdh+xzZQW1+FzdjVs=", + "lastModified": 1703532766, + "narHash": "sha256-ojjW3cuNmqL5uqDWohwLoO8dYpheM5+AfgsNmGIMwG8=", "owner": "nix-community", "repo": "disko", - "rev": "a050895e4eb06e0738680021a701ea05dc8dbfc9", + "rev": "1b191113874dee97796749bb21eac3d84735c70a", "type": "github" }, "original": { @@ -83,11 +84,11 @@ ] }, "locked": { - "lastModified": 1703368619, - "narHash": "sha256-ZGPMYL7FMA6enhuwby961bBANmoFX14EA86m2/Jw5Jo=", + "lastModified": 1703527373, + "narHash": "sha256-AjypRssRtS6F3xkf7rE3/bXkIF2WJOZLbTIspjcE1zM=", "owner": "nix-community", "repo": "home-manager", - "rev": "a2523ea0343b056ba240abbac90ab5f116a7aa7b", + "rev": "80679ea5074ab7190c4cce478c600057cfb5edae", "type": "github" }, "original": { @@ -136,11 +137,11 @@ }, "nixos-stable": { "locked": { - "lastModified": 1702921762, - "narHash": "sha256-O/rP7gulApQAB47u6szEd8Pn8Biw0d84j5iuP2tcxzY=", + "lastModified": 1703068421, + "narHash": "sha256-WSw5Faqlw75McIflnl5v7qVD/B3S2sLh+968bpOGrWA=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "d02ffbbe834b5599fc5f134e644e49397eb07188", + "rev": "d65bceaee0fb1e64363f7871bc43dc1c6ecad99f", "type": "github" }, "original": { @@ -166,6 +167,24 @@ "type": "github" } }, + "openwrt": { + "flake": false, + "locked": { + "lastModified": 1691699580, + "narHash": "sha256-CV+ufXPEr5Nz2O2FBnnuPeHNsFQ7c5s0uW39u/q3cUo=", + "ref": "main", + "rev": "847984c773d819d5579d5abae4b80a4983103ed9", + "revCount": 58166, + "type": "git", + "url": "https://github.com/openwrt/openwrt.git" + }, + "original": { + "ref": "main", + "rev": "847984c773d819d5579d5abae4b80a4983103ed9", + "type": "git", + "url": "https://github.com/openwrt/openwrt.git" + } + }, "root": { "inputs": { "bpir3": "bpir3", @@ -175,6 +194,7 @@ "hostapd": "hostapd", "nixos-nftables-firewall": "nixos-nftables-firewall", "nixpkgs": "nixpkgs", + "openwrt": "openwrt", "srvos": "srvos" } }, @@ -186,11 +206,11 @@ ] }, "locked": { - "lastModified": 1703258052, - "narHash": "sha256-gWGQxht/xRJRnA+35aHtpmev7snsM+2GBdaPyarXNqU=", + "lastModified": 1703469109, + "narHash": "sha256-hTQJ9uV43Vt8UXwervEj9mbDoQSN1mD3lwwPChG8jy8=", "owner": "numtide", "repo": "srvos", - "rev": "0c7eefd13776730f33ea28fb984dd95cb5357e8e", + "rev": "52d07db520046c4775f1047e68a05dcb53bba9ec", "type": "github" }, "original": { diff --git a/nix/os/devices/router0-dmz0/flake.nix b/nix/os/devices/router0-dmz0/flake.nix index bd9e3b4..027bdac 100644 --- a/nix/os/devices/router0-dmz0/flake.nix +++ b/nix/os/devices/router0-dmz0/flake.nix @@ -1,7 +1,6 @@ { inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - # nixpkgs.url = "github:steveej-forks/nixpkgs/hostapd-fix"; get-flake.url = "github:ursi/get-flake"; @@ -13,15 +12,29 @@ srvos.url = "github:numtide/srvos"; srvos.inputs.nixpkgs.follows = "nixpkgs"; - # bpir3.url = "github:steveej-forks/nixos-bpir3"; - bpir3.url = "/home/steveej/src/steveej/nixos-bpir3"; + bpir3.url = + "github:steveej-forks/nixos-bpir3/linux-6.6" + # "/home/steveej/src/steveej/nixos-bpir3" + ; + bpir3.inputs.nixpkgs.follows = "nixpkgs"; + nixos-nftables-firewall.url = "github:thelegy/nixos-nftables-firewall"; nixos-nftables-firewall.inputs.nixpkgs.follows = "nixpkgs"; hostapd.url = "git://w1.fi/hostap.git?branch=main"; hostapd.flake = false; + + openwrt.url = "git+https://github.com/openwrt/openwrt.git?ref=main&rev=847984c773d819d5579d5abae4b80a4983103ed9"; + openwrt.flake = false; + + # TODO: would be nice if this worked but it throws an error when using the input as a patch: + # error: flake input has unsupported input type 'file' + # hostapd_patch_vlan_no_bridge = { + # url = "file+https://raw.githubusercontent.com/openwrt/openwrt/847984c773d819d5579d5abae4b80a4983103ed9/package/network/services/hostapd/patches/710-vlan_no_bridge.patch"; + # flake = false; + # }; }; outputs = { @@ -30,25 +43,31 @@ nixpkgs, bpir3, ... - } @ attrs: let - system = "aarch64-linux"; + }: let + nativeSystem = "aarch64-linux"; nodeName = "router0-dmz0"; - pkgs = nixpkgs.legacyPackages.${system}; + + pkgs = nixpkgs.legacyPackages.${nativeSystem}; + pkgsCross = import self.inputs.nixpkgs { + system = "x86_64-linux"; + crossSystem = { + config = "aarch64-unknown-linux-gnu"; + }; + }; mkNixosConfiguration = {extraModules ? [], ...} @ attrs: nixpkgs.lib.nixosSystem ( nixpkgs.lib.attrsets.recursiveUpdate attrs { - specialArgs = { - nodeFlake = self; - repoFlake = get-flake ../../../..; + # TODO: it would be nice if this were the same as meta.nodeSpecialArgs.${nodeName} as in the default.nix + specialArgs = (import ./default.nix { + system = nativeSystem; inherit nodeName; - inherit - (bpir3.packages.${system}) - armTrustedFirmwareMT7986 - ; - }; + + repoFlake = get-flake ../../../..; + nodeFlake = self; + }).meta.nodeSpecialArgs.${nodeName}; modules = [ @@ -67,6 +86,7 @@ inherit (bpir3Pkgs) linuxPackages_bpir3 + linuxPackages_bpir3_latest ; }) @@ -79,30 +99,33 @@ in { nixosConfigurations = { native = mkNixosConfiguration { - inherit system; + system = nativeSystem; }; cross = mkNixosConfiguration { extraModules = [ { nixpkgs.buildPlatform.system = "x86_64-linux"; - nixpkgs.hostPlatform.system = system; + nixpkgs.hostPlatform.system = nativeSystem; } ]; }; }; - packages = { - hostapd_main = pkgs.hostapd.overrideDerivation(attrs: { - src = self.inputs.hostapd; - version = self.inputs.hostapd.rev; + packages = let + mkPatchedHostapd = pkgs: pkgs.hostapd.overrideDerivation(attrs: { patches = attrs.patches ++ [ - (builtins.fetchurl { - url = "https://raw.githubusercontent.com/openwrt/openwrt/main/package/network/services/hostapd/patches/710-vlan_no_bridge.patch"; - sha256 = "sha256:1p6fjjdwx5xrxyvllfrmvdkiji7bgx997k1qmp199bbic1fq6ks9"; - }) + "${self.inputs.openwrt}/package/network/services/hostapd/patches/710-vlan_no_bridge.patch" ]; }); + in { + "${nativeSystem}" = { + hostapd_patched = mkPatchedHostapd pkgs; + }; + + cross = { + hostapd_patched = mkPatchedHostapd pkgsCross; + }; }; }; } -- 2.49.0 From 5299051f86b4e90418276c6ccf5c61f57a461049 Mon Sep 17 00:00:00 2001 From: Stefan Junker Date: Tue, 26 Dec 2023 22:44:11 +0100 Subject: [PATCH 6/7] chore: remove and extend info on TODO comments --- nix/os/devices/router0-dmz0/configuration.nix | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/nix/os/devices/router0-dmz0/configuration.nix b/nix/os/devices/router0-dmz0/configuration.nix index f62b0e8..2279647 100644 --- a/nix/os/devices/router0-dmz0/configuration.nix +++ b/nix/os/devices/router0-dmz0/configuration.nix @@ -86,9 +86,6 @@ in { nix.settings.cores = lib.mkDefault 0; } - # TODO - # ./network.nix - # ./monitoring.nix { services.openssh.enable = true; services.openssh.settings.PermitRootLogin = "yes"; @@ -396,7 +393,6 @@ in { } # configuration for the hostapd dynamic interfaces - # TODO: refactor this to configure the following per vlanid # * netdev type vlan # * host address for vlan # * vlan config for wlan interface @@ -405,8 +401,9 @@ in { (acc: cur: acc // cur) {} (builtins.map ({ vlanid, vlanid' }: { - # set an address on the tagged br-lan device. - # this address will be picked up by dnsmasq. + # configure the tagged vlan device with an address and vlan filtering. + # dnsmasq is configured to serve the respective /24 range on each tagged device. + # this device only receives traffic for the given vlanid and sends tagged traffic to the bridge. "41-br-lan.${vlanid'}" = { matchConfig.Name = "br-lan.${vlanid'}"; address = [ @@ -422,7 +419,6 @@ in { bridgeVLANs = [ { bridgeVLANConfig = { - # TODO debug this: each vlanid is native to each port VLAN = vlanid; }; } @@ -445,7 +441,6 @@ in { bridgeVLANs = [ { bridgeVLANConfig = { - # TODO debug this: each vlanid is native to each port VLAN = vlanid; PVID = vlanid; EgressUntagged = vlanid; @@ -463,16 +458,6 @@ in { ConfigureWithoutCarrier = true; }; linkConfig.RequiredForOnline = "no"; - - bridgeVLANs = [ - { - bridgeVLANConfig = { - # TODO debug this: each vlanid is native to each port - VLAN = vlanid; - PVID = vlanid; - }; - } - ]; }; }) (builtins.map -- 2.49.0 From ecfe589b60d9d789f26cc4b3f2e8c5d9d697dfbc Mon Sep 17 00:00:00 2001 From: Stefan Junker Date: Thu, 28 Dec 2023 11:22:39 +0100 Subject: [PATCH 7/7] router0-dmz0: dnssec, local names, code cleanup --- nix/os/devices/router0-dmz0/configuration.nix | 151 +++++++++++++----- nix/os/devices/router0-dmz0/default.nix | 5 +- nix/os/devices/router0-dmz0/flake.nix | 1 - 3 files changed, 114 insertions(+), 43 deletions(-) diff --git a/nix/os/devices/router0-dmz0/configuration.nix b/nix/os/devices/router0-dmz0/configuration.nix index 2279647..98bc922 100644 --- a/nix/os/devices/router0-dmz0/configuration.nix +++ b/nix/os/devices/router0-dmz0/configuration.nix @@ -5,6 +5,7 @@ config, nodeFlake, nodeName, + localDomainName, system, ... }: let @@ -32,7 +33,7 @@ [ "192" "168" (toString (vlanid + offset)) "${toString host}${lib.strings.optionalString cidr "/24"}" ]; defaultVlan = { - name = "internal"; + name = "${localDomainName}"; packet_priority = 0; }; @@ -55,6 +56,13 @@ "15".name = "iot2"; "15".packet_priority = -10; }; + + vlansByName = lib.attrsets.mapAttrs' (vlanid': attrs: + lib.attrsets.nameValuePair + attrs.name + (attrs // { id = lib.strings.toInt vlanid'; id' = vlanid';}) + ) vlans; + getVlanDomain = { vlanid }: if vlanid == 0 then @@ -62,6 +70,13 @@ else vlans."${toString vlanid}".name + "." + defaultVlan.name ; + + bridgeInterfaceName = "br-lan"; + mkInterfaceName = { vlanid }: + if vlanid == 0 + then bridgeInterfaceName + else "${bridgeInterfaceName}.${toString vlanid}" + ; in { imports = [ repoFlake.inputs.sops-nix.nixosModules.sops @@ -164,13 +179,16 @@ in { firewall = { enable = true; zones = { - lan.interfaces = [ "br-lan" ]; - vlan.interfaces = builtins.map (vlanid: "br-lan.${toString vlanid}") vlanRange; + lan.interfaces = [ (mkInterfaceName {vlanid = 0;}) ]; + vlan.interfaces = builtins.map (vlanid: (mkInterfaceName {inherit vlanid;})) vlanRange; # lan.ipv4Addresses = ["192.168.0.0/16"]; wan.interfaces = ["wan" "lan0"]; } // - # TODO: generate a zone for each vlan - {} + # generate a zone for each vlan + lib.attrsets.mapAttrs (key: value: { + interfaces = [ (mkInterfaceName { vlanid = value.id; }) ]; + }) + vlansByName ; rules = let ipv6IcmpTypes = [ @@ -194,6 +212,12 @@ in { verdict = "accept"; }; + office-to-dmz = { + from = ["office"]; + to = ["dmz"]; + verdict = "accept"; + }; + lan-to-fw = { from = ["lan"]; to = ["fw" "lan"]; @@ -258,10 +282,10 @@ in { wait-online.anyInterface = true; netdevs = { # Create the bridge interface - "20-br-lan" = { + "20-${bridgeInterfaceName}" = { netdevConfig = { Kind = "bridge"; - Name = "br-lan"; + Name = bridgeInterfaceName; }; extraConfig = '' @@ -280,10 +304,10 @@ in { {} (builtins.map ({ vlanid, vlanid' }: { - "20-br-lan.${vlanid'}" = { + "20-${mkInterfaceName { inherit vlanid; }}" = { netdevConfig = { Kind = "vlan"; - Name = "br-lan.${vlanid'}"; + Name = "${mkInterfaceName { inherit vlanid; }}"; }; vlanConfig.Id = vlanid; }; @@ -331,24 +355,45 @@ in { "30-lan1" = { matchConfig.Name = "lan1"; networkConfig = { - Bridge = "br-lan"; + Bridge = bridgeInterfaceName; ConfigureWithoutCarrier = true; }; linkConfig.RequiredForOnline = "enslaved"; + + bridgeVLANs = [ + { + bridgeVLANConfig = { + VLAN = vlansByName.dmz.id; + PVID = vlansByName.dmz.id; + EgressUntagged = vlansByName.dmz.id; + }; + } + ]; }; + "30-lan2" = { matchConfig.Name = "lan2"; networkConfig = { - Bridge = "br-lan"; + Bridge = bridgeInterfaceName; ConfigureWithoutCarrier = true; }; linkConfig.RequiredForOnline = "enslaved"; + + bridgeVLANs = [ + { + bridgeVLANConfig = { + VLAN = vlansByName.office.id; + PVID = vlansByName.office.id; + EgressUntagged = vlansByName.office.id; + }; + } + ]; }; "30-lan3" = { matchConfig.Name = "lan3"; networkConfig = { - Bridge = "br-lan"; + Bridge = bridgeInterfaceName; ConfigureWithoutCarrier = true; }; linkConfig.RequiredForOnline = "enslaved"; @@ -360,11 +405,10 @@ in { }; } ]; - }; # Configure the bridge for its desired function - "40-br-lan" = { - matchConfig.Name = "br-lan"; + "40-${bridgeInterfaceName}" = { + matchConfig.Name = bridgeInterfaceName; bridgeConfig = {}; address = [ (mkVlanIpv4HostAddr { vlanid = 0; host = 1;}) @@ -385,7 +429,7 @@ in { ]; vlan = (builtins.map - (vlanid: "br-lan.${builtins.toString vlanid}") + (vlanid: (mkInterfaceName { inherit vlanid; })) vlanRange ); }; @@ -404,8 +448,8 @@ in { # configure the tagged vlan device with an address and vlan filtering. # dnsmasq is configured to serve the respective /24 range on each tagged device. # this device only receives traffic for the given vlanid and sends tagged traffic to the bridge. - "41-br-lan.${vlanid'}" = { - matchConfig.Name = "br-lan.${vlanid'}"; + "41-${mkInterfaceName { inherit vlanid; }}" = { + matchConfig.Name = "${mkInterfaceName { inherit vlanid; }}"; address = [ (mkVlanIpv4HostAddr { inherit vlanid; host = 1; }) ]; @@ -432,7 +476,7 @@ in { "41-wlan0.${vlanid'}" = { matchConfig.Name = "wlan0.${vlanid'}"; networkConfig = { - Bridge = "br-lan"; + Bridge = bridgeInterfaceName; ConfigureWithoutCarrier = true; }; @@ -449,8 +493,8 @@ in { ]; }; - "50-br-lan.${vlanid'}" = { - matchConfig.Name = "br-lan.${vlanid'}"; + "50-${mkInterfaceName { inherit vlanid; }}" = { + matchConfig.Name = "${mkInterfaceName { inherit vlanid; }}"; address = [ (mkVlanIpv4HostAddr { inherit vlanid; host = 1; }) ]; @@ -498,15 +542,17 @@ in { authentication.wpaPskFile = config.sops.secrets."${iface}_wpaPskFile".path; authentication.saePasswordsFile = config.sops.secrets."${iface}_saePasswordsFile".path; + # see https://w1.fi/cgit/hostap/plain/hostapd/hostapd.conf for reference settings = { - # bridge = "br-lan"; + # bridge = bridgeInterfaceName; # wpa_psk_file = config.sops.secrets.wlan0_wpaPskFile.path; # not yet supported on hostapd 2.10 # sae_password_file = config.sops.secrets.wlan0_saePasswordsFile.path; - logger_stdout_level= lib.mkForce 0; - logger_syslog_level= lib.mkForce 0; + # enables debug logging + # logger_stdout_level= lib.mkForce 0; + # logger_syslog_level= lib.mkForce 0; # resources on vlan tagging # https://wireless.wiki.kernel.org/en/users/Documentation/hostapd#dynamic_vlan_tagging @@ -517,7 +563,7 @@ in { vlan_no_bridge = 1; /* not used due to the above vlan_no_bridge setting - vlan_tagged_interface = "br-lan"; + vlan_tagged_interface = bridgeInterfaceName; vlan_naming = 1; vlan_bridge = "br-${iface}."; */ @@ -568,7 +614,7 @@ in { # bssid = mkBssid 1; # settings = { - # bridge = "br-lan"; + # bridge = bridgeInterfaceName; # }; # }; @@ -581,7 +627,7 @@ in { # managementFrameProtection = "optional"; # bssid = "e6:02:43:07:00:00"; # settings = { - # bridge = "br-lan"; + # bridge = bridgeInterfaceName; # wpa = lib.mkForce 2; # wpa_key_mgmt = "WPA-PSK"; # wpa_pairwise = "CCMP"; @@ -673,7 +719,7 @@ in { # }; # bssid = "36:b9:02:21:08:a2"; # settings = { - # bridge = "br-lan"; + # bridge = bridgeInterfaceName; # }; # }; # }; @@ -683,15 +729,24 @@ in { services.resolved.enable = false; - services.dnsmasq = let - mkIfName = { vlanid }: if vlanid == 0 then "br-lan" else "br-lan.${toString vlanid}"; - in { + services.dnsmasq = { enable = true; settings = { - # sensible behaviours domain-needed = true; bogus-priv = true; no-resolv = true; + localise-queries = true; + + proxy-dnssec = true; + conntrack = true; + + log-debug = true; + log-queries = true; + + # disable negative caching + no-negcache = true; + local-ttl = 0; + dhcp-ttl = 0; dhcp-range = let mkDhcpRange = { tag, vlanid }: builtins.concatStringsSep "," [ @@ -703,12 +758,12 @@ in { in builtins.map (vlanid: - mkDhcpRange { tag = mkIfName {inherit vlanid;}; inherit vlanid; } + mkDhcpRange { tag = mkInterfaceName {inherit vlanid;}; inherit vlanid; } ) vlanRangeWith0 ; - # interface = "br-lan"; + # interface = bridgeInterfaceName; # bind-interfaces = true; # dhcp-host = "192.168.10.1"; @@ -720,12 +775,27 @@ in { # don't use /etc/hosts as this would advertise ${nodeName} as localhost no-hosts = true; + # address = "/${nodeName}.lan/${fwLanHostAddr}"; server = [ - # upstream DNS servers - "9.9.9.9" "8.8.8.8" "1.1.1.1" + # upstream DNS servers + + # https://dnsforge.de/ + "176.9.93.198" + "176.9.1.117" + "2a01:4f8:151:34aa::198" + "2a01:4f8:141:316d::117" + + # cloudflare and google + # "9.9.9.9" "8.8.8.8" "1.1.1.1" + ]; + + domain = [ + "/${getVlanDomain {vlanid = 0;}}/,local" ] ++ builtins.map - (vlanid: "/${getVlanDomain {inherit vlanid;}}/") + (vlanid: + "${getVlanDomain {inherit vlanid;}},${mkVlanIpv4HostAddr { inherit vlanid; host = 0; cidr = true; }},local" + ) vlanRangeWith0 ; @@ -734,18 +804,17 @@ in { ] ++ builtins.map (vlanid: builtins.concatStringsSep "," [ - "${nodeName}.${getVlanDomain{inherit vlanid;}}" "0.0.0.1" (mkIfName {inherit vlanid;}) + # "${getVlanDomain{inherit vlanid;}}" "0.0.0.1" (mkInterfaceName {inherit vlanid;}) + "${nodeName}.${getVlanDomain{inherit vlanid;}}" "0.0.0.1" (mkInterfaceName {inherit vlanid;}) ] ) vlanRangeWith0 ; dhcp-option-force = builtins.map - (vlanid: "${mkIfName {inherit vlanid;}},option:domain-search,${getVlanDomain{inherit vlanid;}}") + (vlanid: "${mkInterfaceName {inherit vlanid;}},option:domain-search,${getVlanDomain{inherit vlanid;}}") vlanRangeWith0 ; - - localise-queries = true; }; }; diff --git a/nix/os/devices/router0-dmz0/default.nix b/nix/os/devices/router0-dmz0/default.nix index e29beb2..9dd8d5e 100644 --- a/nix/os/devices/router0-dmz0/default.nix +++ b/nix/os/devices/router0-dmz0/default.nix @@ -3,6 +3,7 @@ nodeName, repoFlake, nodeFlake, + localDomainName ? "internal", ... }: { meta.nodeSpecialArgs.${nodeName} = { @@ -14,6 +15,8 @@ (nodeFlake.inputs.bpir3.packages.${system}) armTrustedFirmwareMT7986 ; + + inherit localDomainName; }; meta.nodeNixpkgs.${nodeName} = @@ -23,7 +26,7 @@ }; ${nodeName} = { - deployment.targetHost = "router0.dmz0.noosphere.life"; + deployment.targetHost = "${nodeName}.${localDomainName}"; deployment.replaceUnknownProfiles = true; # nixpkgs.pkgs = nodeFlake.inputs.nixpkgs.legacyPackages.${system}; diff --git a/nix/os/devices/router0-dmz0/flake.nix b/nix/os/devices/router0-dmz0/flake.nix index 027bdac..494551e 100644 --- a/nix/os/devices/router0-dmz0/flake.nix +++ b/nix/os/devices/router0-dmz0/flake.nix @@ -60,7 +60,6 @@ nixpkgs.lib.attrsets.recursiveUpdate attrs { - # TODO: it would be nice if this were the same as meta.nodeSpecialArgs.${nodeName} as in the default.nix specialArgs = (import ./default.nix { system = nativeSystem; inherit nodeName; -- 2.49.0