From 96413dcfec4fdc9e6232a680185fbb2e16498423 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 28 Dec 2023 10:38:38 +0000 Subject: [PATCH] feat(router0-dmz0): AP with dynamic vlan filtering on central bridge --- .sops.yaml | 4 +- .vscode/settings.json | 2 +- flake.lock | 14 +- nix/os/devices/router0-dmz0/configuration.nix | 729 +++++++++++++----- nix/os/devices/router0-dmz0/default.nix | 11 +- nix/os/devices/router0-dmz0/flake.lock | 106 ++- nix/os/devices/router0-dmz0/flake.nix | 73 +- secrets/router0-dmz0/secrets.yaml | 6 +- 8 files changed, 696 insertions(+), 249 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/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 f7f57c3..98bc922 100644 --- a/nix/os/devices/router0-dmz0/configuration.nix +++ b/nix/os/devices/router0-dmz0/configuration.nix @@ -1,12 +1,11 @@ { - modulesPath, repoFlake, - packages', pkgs, lib, config, nodeFlake, nodeName, + localDomainName, system, ... }: let @@ -15,13 +14,71 @@ bpir3 nixos-nftables-firewall ; -in { - disabledModules = [ - # "services/networking/hostapd.nix" - ]; + 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 = "${localDomainName}"; + packet_priority = 0; + }; + + vlans = { + "10".name = "mgmt"; + "10".packet_priority = 0; + + "11".name = "dmz"; + "11".packet_priority = -5; + + "12".name = "iot"; + "12".packet_priority = -5; + + "13".name = "office"; + "13".packet_priority = -10; + + "14".name = "guests"; + "14".packet_priority = 10; + + "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 + defaultVlan.name + else + vlans."${toString vlanid}".name + "." + defaultVlan.name + ; + + bridgeInterfaceName = "br-lan"; + mkInterfaceName = { vlanid }: + if vlanid == 0 + then bridgeInterfaceName + else "${bridgeInterfaceName}.${toString vlanid}" + ; +in { imports = [ - # nodeFlake.inputs.disko.nixosModules.disko repoFlake.inputs.sops-nix.nixosModules.sops ../../profiles/common/user.nix @@ -30,9 +87,20 @@ in { nixos-nftables-firewall.nixosModules.default - # TODO - # ./network.nix - # ./monitoring.nix + { + nix.nixPath = [ + "nixpkgs=${pkgs.path}" + ]; + + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + + nix.settings.max-jobs = lib.mkDefault "auto"; + nix.settings.cores = lib.mkDefault 0; + } + { services.openssh.enable = true; services.openssh.settings.PermitRootLogin = "yes"; @@ -43,11 +111,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 = { }; } ]; @@ -94,40 +164,103 @@ in { useNetworkd = true; useDHCP = false; - # No local firewall. + # these will be configured via nftables nat.enable = lib.mkForce false; firewall.enable = lib.mkForce false; # 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 = ""; firewall = { enable = true; zones = { - lan.interfaces = ["br-lan"]; + 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"]; - }; - rules = { - lan = { - from = ["lan"]; - to = ["fw"]; + } // + # generate a zone for each vlan + lib.attrsets.mapAttrs (key: value: { + interfaces = [ (mkInterfaceName { vlanid = value.id; }) ]; + }) + vlansByName + ; + 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 { + fw = { + from = ["fw"]; verdict = "accept"; }; - outbound = { - from = ["lan"]; - to = ["lan" "wan"]; - verdict = "accept"; - }; - nat = { - from = ["lan"]; - to = ["wan"]; - masquerade = true; - }; - incoming-wan = { + office-to-dmz = { + from = ["office"]; + to = ["dmz"]; + verdict = "accept"; + }; + + lan-to-fw = { + from = ["lan"]; + to = ["fw" "lan"]; + verdict = "accept"; + }; + + lan-to-wan = { + from = ["lan"]; + to = ["wan"]; + verdict = "accept"; + }; + + 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 = 5201; to = 5201; } + ]; + 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 +269,9 @@ in { to = 22; } ]; - verdict = "drop"; + extraLines = allowIcmpLines ++ [ + "drop" + ]; }; }; }; @@ -146,61 +281,44 @@ in { systemd.network = { wait-online.anyInterface = true; netdevs = { - # Create the VLANs - "00-vlan-100" = { - Name = "vlan100"; - Kind = "vlan"; - }; - - # Create the bridge interfaces - "20-br-lan" = { + # Create the bridge interface + "20-${bridgeInterfaceName}" = { netdevConfig = { Kind = "bridge"; - Name = "br-lan"; - VLANFiltering = true; - DefaultPVID = 10; + Name = bridgeInterfaceName; }; + + extraConfig = '' + [Bridge] + STP=yes + VLANFiltering=yes + VLANProtocol=802.1q + DefaultPVID=0 + ''; }; - }; + + } + # generate the vlan devices. these will be tagged on the main bridge + // builtins.foldl' + (acc: cur: acc // cur) + {} + (builtins.map + ({ vlanid, vlanid' }: { + "20-${mkInterfaceName { inherit vlanid; }}" = { + netdevConfig = { + Kind = "vlan"; + Name = "${mkInterfaceName { inherit vlanid; }}"; + }; + vlanConfig.Id = vlanid; + }; + }) + (builtins.map + (vlanid: { inherit vlanid; vlanid' = builtins.toString vlanid; }) + vlanRange + ) + ) + ; 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,14 +350,174 @@ 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 = 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 = 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 = bridgeInterfaceName; + ConfigureWithoutCarrier = true; + }; + linkConfig.RequiredForOnline = "enslaved"; + + bridgeVLANs = [ + { + bridgeVLANConfig = { + VLAN = "${toString vlanRangeStart}-${toString vlanRangeEnd}"; + }; + } + ]; + }; + # Configure the bridge for its desired function + "40-${bridgeInterfaceName}" = { + matchConfig.Name = bridgeInterfaceName; + 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"; + linkConfig.ActivationPolicy = "always-up"; + + bridgeVLANs = [ + { + bridgeVLANConfig = { + VLAN = "${toString vlanRangeStart}-${toString vlanRangeEnd}"; + }; + } + ]; + + vlan = (builtins.map + (vlanid: (mkInterfaceName { inherit vlanid; })) + vlanRange + ); + }; + + } + + # configuration for the hostapd dynamic interfaces + # * netdev type vlan + # * host address for vlan + # * vlan config for wlan interface + // + builtins.foldl' + (acc: cur: acc // cur) + {} + (builtins.map ({ vlanid, vlanid' }: { + # 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-${mkInterfaceName { inherit vlanid; }}" = { + matchConfig.Name = "${mkInterfaceName { inherit vlanid; }}"; + address = [ + (mkVlanIpv4HostAddr { inherit vlanid; host = 1; }) + ]; + networkConfig = { + ConfigureWithoutCarrier = true; + }; + + linkConfig.RequiredForOnline = "no"; + linkConfig.ActivationPolicy = "always-up"; + + bridgeVLANs = [ + { + bridgeVLANConfig = { + VLAN = 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.${vlanid'}" = { + matchConfig.Name = "wlan0.${vlanid'}"; + networkConfig = { + Bridge = bridgeInterfaceName; + ConfigureWithoutCarrier = true; + }; + + linkConfig.RequiredForOnline = "no"; + + bridgeVLANs = [ + { + bridgeVLANConfig = { + VLAN = vlanid; + PVID = vlanid; + EgressUntagged = vlanid; + }; + } + ]; + }; + + "50-${mkInterfaceName { inherit vlanid; }}" = { + matchConfig.Name = "${mkInterfaceName { inherit vlanid; }}"; + address = [ + (mkVlanIpv4HostAddr { inherit vlanid; host = 1; }) + ]; + networkConfig = { + ConfigureWithoutCarrier = true; + }; + linkConfig.RequiredForOnline = "no"; + }; + }) + (builtins.map + (vlanid: { inherit vlanid; vlanid' = builtins.toString vlanid; }) + vlanRange + )) + ; }; # wireless access point services.hostapd = { enable = true; + package = nodeFlake.packages.${system}.hostapd_patched; radios = let - mkBssid = i: "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"; @@ -252,49 +530,93 @@ in { capabilities = ["HT40+" "LDPC" "SHORT-GI-20" "SHORT-GI-40" "TX-STBC" "RX-STBC1" "MAX-AMSDU-7935"]; }; networks = { - wlan0 = { - ssid = "justtestingwifi-wpa3"; - authentication = { - mode = "wpa3-sae"; - # saePasswordsFile = config.sops.secrets.wifiPassword.path; - saePasswords = [ - { - password = "justtestingwifi"; - # vlanid = 100; - } - ]; - }; - - # generated with https://miniwebtool.com/mac-address-generator/ + wlan0 = let + iface = "wlan0"; + in { + ssid = "mlsia"; bssid = mkBssid 0; + + # authentication.mode = "wpa3-sae"; + authentication.mode = "wpa3-sae-transition"; + + 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; + + # 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 + # 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 = bridgeInterfaceName; + vlan_naming = 1; + vlan_bridge = "br-${iface}."; + */ + + 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}.#" + ]; + + file = pkgs.writeText "hostapd.vlan" + (builtins.concatStringsSep "\n" (generated ++ wildcard)); + filePath = toString file; + in filePath; + + wpa_key_mgmt = lib.mkForce (builtins.concatStringsSep " " [ + "WPA-PSK" + + # TODO: the printer can't connect when this is on + # "WPA-PSK-SHA256" + + # 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 = 1; + sae_require_mfp = 1; + sae_groups = "19 20 21"; }; }; - wlan0-1 = { - ssid = "justtestingwifi-compat"; - authentication = { - mode = "wpa3-sae-transition"; - # saePasswordsFile = config.sops.secrets.wifiPassword.path; - saePasswords = [ - { - password = "justtestingwifi"; - # vlanid = 100; - } - ]; - wpaPskFile = pkgs.writeText "pskfile" '' - 00:00:00:00:00:00 justtestingwifi - # vlanid=100 00:00:00:00:00:00 justtestingwifi-vlan - ''; - }; + # wlan0-1 = { + # ssid = "justtestingwifi-wpa3"; + # authentication = { + # mode = "wpa3-sae"; + # saePasswordsFile = config.sops.secrets.wlan0_1_saePasswordFile.path; + # }; - # generated with https://miniwebtool.com/mac-address-generator/ - bssid = mkBssid 1; - settings = { - bridge = "br-lan"; - }; - }; + # bssid = mkBssid 1; + # settings = { + # bridge = bridgeInterfaceName; + # }; + # }; # Uncomment when needed otherwise remove # wlan0-1 = { @@ -305,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"; @@ -314,6 +636,7 @@ in { # }; }; }; + # wlan1 = { # band = "5g"; # # channels with 160 MHz width in Poland: 36, 52, 100 i 116 @@ -396,7 +719,7 @@ in { # }; # bssid = "36:b9:02:21:08:a2"; # settings = { - # bridge = "br-lan"; + # bridge = bridgeInterfaceName; # }; # }; # }; @@ -409,89 +732,98 @@ in { services.dnsmasq = { 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; + localise-queries = true; - dhcp-range = ["br-lan,192.168.10.50,192.168.10.254,24h"]; - interface = "br-lan"; - dhcp-host = "192.168.10.1"; + 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 "," [ + tag + (mkVlanIpv4HostAddr { inherit vlanid; host = 100; cidr = false; }) + (mkVlanIpv4HostAddr { inherit vlanid; host = 199; cidr = false; }) + "30m" + ]; + in + builtins.map + (vlanid: + mkDhcpRange { tag = mkInterfaceName {inherit vlanid;}; inherit vlanid; } + ) + vlanRangeWith0 + ; + + # interface = bridgeInterfaceName; + # 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 + + # 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;}},${mkVlanIpv4HostAddr { inherit vlanid; host = 0; cidr = true; }},local" + ) + vlanRangeWith0 + ; + + # TODO: compare this to using `interface-name` + dynamic-host = [ + ] ++ builtins.map + (vlanid: + builtins.concatStringsSep "," [ + # "${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: "${mkInterfaceName {inherit vlanid;}},option:domain-search,${getVlanDomain{inherit vlanid;}}") + vlanRangeWith0 + ; }; }; # 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; - # boot.kernelPackages = bpir3.packages.aarch64-linux.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. # @@ -553,5 +885,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/default.nix b/nix/os/devices/router0-dmz0/default.nix index e8d521a..9dd8d5e 100644 --- a/nix/os/devices/router0-dmz0/default.nix +++ b/nix/os/devices/router0-dmz0/default.nix @@ -1,19 +1,22 @@ { + system ? "aarch64-linux", nodeName, repoFlake, nodeFlake, + localDomainName ? "internal", ... -}: let - system = "aarch64-linux"; -in { +}: { meta.nodeSpecialArgs.${nodeName} = { inherit repoFlake nodeName nodeFlake system; packages' = repoFlake.packages.${system}; + nodePackages' = nodeFlake.packages.${system}; inherit (nodeFlake.inputs.bpir3.packages.${system}) armTrustedFirmwareMT7986 ; + + inherit localDomainName; }; meta.nodeNixpkgs.${nodeName} = @@ -23,7 +26,7 @@ in { }; ${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.lock b/nix/os/devices/router0-dmz0/flake.lock index b572ebd..089ad5e 100644 --- a/nix/os/devices/router0-dmz0/flake.lock +++ b/nix/os/devices/router0-dmz0/flake.lock @@ -7,16 +7,17 @@ ] }, "locked": { - "lastModified": 1688620001, - "narHash": "sha256-8ACxxssPiQy/lsUsT8cAaT2te8p8d8ngmPwTc/erPnU=", - "owner": "nakato", - "repo": "nixos-bpir3-example", - "rev": "4210480bdebbf3a7953e22d5d9f183f47b725bff", + "lastModified": 1703603768, + "narHash": "sha256-ZViXHNt7ClqNtlRO9iot+LxiSbBvZi/RR+/6Q7W6UV8=", + "owner": "steveej-forks", + "repo": "nixos-bpir3", + "rev": "47cb545b92c136d1482a66b940c4719c40eb5fe3", "type": "github" }, "original": { - "owner": "nakato", - "repo": "nixos-bpir3-example", + "owner": "steveej-forks", + "ref": "linux-6.6", + "repo": "nixos-bpir3", "type": "github" } }, @@ -48,11 +49,11 @@ ] }, "locked": { - "lastModified": 1695864092, - "narHash": "sha256-Hu1SkFPqO7ND95AOzBkZE2jGXSYhfZ965C03O72Kbu8=", + "lastModified": 1703532766, + "narHash": "sha256-ojjW3cuNmqL5uqDWohwLoO8dYpheM5+AfgsNmGIMwG8=", "owner": "nix-community", "repo": "disko", - "rev": "19b62324663b6b9859caf7f335d232cf4f1f6a32", + "rev": "1b191113874dee97796749bb21eac3d84735c70a", "type": "github" }, "original": { @@ -83,11 +84,11 @@ ] }, "locked": { - "lastModified": 1696145345, - "narHash": "sha256-3dM7I/d4751SLPJah0to1WBlWiyzIiuCEUwJqwBdmr4=", + "lastModified": 1703527373, + "narHash": "sha256-AjypRssRtS6F3xkf7rE3/bXkIF2WJOZLbTIspjcE1zM=", "owner": "nix-community", "repo": "home-manager", - "rev": "6f9b5b83ad1f470b3d11b8a9fe1d5ef68c7d0e30", + "rev": "80679ea5074ab7190c4cce478c600057cfb5edae", "type": "github" }, "original": { @@ -97,6 +98,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", @@ -105,11 +122,11 @@ ] }, "locked": { - "lastModified": 1695065444, - "narHash": "sha256-c39mzyE1Z95bOjNfcCpENdQUn8lgTQFXNDeDguZnKs4=", + "lastModified": 1703279052, + "narHash": "sha256-0rbG/9SwaWtXT7ZuifMq+7wvfxDpZrjr0zdMcM4KK+E=", "owner": "thelegy", "repo": "nixos-nftables-firewall", - "rev": "f1d43094940379f8aa3b7ef750b48db48b622584", + "rev": "3bf23aeb346e772d157816e6b72a742a6c97db80", "type": "github" }, "original": { @@ -118,45 +135,82 @@ "type": "github" } }, - "nixpkgs": { + "nixos-stable": { "locked": { - "lastModified": 1691788113, - "narHash": "sha256-h5dnmk0QMQI+WkP7ZGbqusr7GfeXOrYCzO7BoZpSGJ0=", - "owner": "steveej-forks", + "lastModified": 1703068421, + "narHash": "sha256-WSw5Faqlw75McIflnl5v7qVD/B3S2sLh+968bpOGrWA=", + "owner": "NixOS", "repo": "nixpkgs", - "rev": "f358ddb768fad528772ae3faf786337fe89a7568", + "rev": "d65bceaee0fb1e64363f7871bc43dc1c6ecad99f", "type": "github" }, "original": { - "owner": "steveej-forks", - "ref": "hostapd-fix", + "owner": "NixOS", + "ref": "nixos-23.11", "repo": "nixpkgs", "type": "github" } }, + "nixpkgs": { + "locked": { + "lastModified": 1703255338, + "narHash": "sha256-Z6wfYJQKmDN9xciTwU3cOiOk+NElxdZwy/FiHctCzjU=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "6df37dc6a77654682fe9f071c62b4242b5342e04", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "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", "disko": "disko", "get-flake": "get-flake", "home-manager": "home-manager", + "hostapd": "hostapd", "nixos-nftables-firewall": "nixos-nftables-firewall", "nixpkgs": "nixpkgs", + "openwrt": "openwrt", "srvos": "srvos" } }, "srvos": { "inputs": { + "nixos-stable": "nixos-stable", "nixpkgs": [ "nixpkgs" ] }, "locked": { - "lastModified": 1695864227, - "narHash": "sha256-X3ADr3UE0Cws7yRLnMyo6VbBWrbkT8KMrds8TK6IYXw=", + "lastModified": 1703469109, + "narHash": "sha256-hTQJ9uV43Vt8UXwervEj9mbDoQSN1mD3lwwPChG8jy8=", "owner": "numtide", "repo": "srvos", - "rev": "25cf328a2d83926dde264b6195d82bc6dcfb4b0c", + "rev": "52d07db520046c4775f1047e68a05dcb53bba9ec", "type": "github" }, "original": { diff --git a/nix/os/devices/router0-dmz0/flake.nix b/nix/os/devices/router0-dmz0/flake.nix index 32748fb..494551e 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"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; get-flake.url = "github:ursi/get-flake"; @@ -13,14 +12,30 @@ srvos.url = "github:numtide/srvos"; srvos.inputs.nixpkgs.follows = "nixpkgs"; - bpir3.url = "github:nakato/nixos-bpir3-example"; + 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"; - }; - # outputs = _: {}; + 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 = { self, @@ -28,24 +43,30 @@ nixpkgs, bpir3, ... - } @ attrs: let - system = "aarch64-linux"; + }: let + nativeSystem = "aarch64-linux"; nodeName = "router0-dmz0"; + 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 ../../../..; + specialArgs = (import ./default.nix { + system = nativeSystem; inherit nodeName; - inherit - (bpir3.packages.${system}) - armTrustedFirmwareMT7986 - ; - }; + + repoFlake = get-flake ../../../..; + nodeFlake = self; + }).meta.nodeSpecialArgs.${nodeName}; modules = [ @@ -64,8 +85,10 @@ inherit (bpir3Pkgs) linuxPackages_bpir3 + linuxPackages_bpir3_latest ; }) + ]; } ] @@ -75,17 +98,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 = let + mkPatchedHostapd = pkgs: pkgs.hostapd.overrideDerivation(attrs: { + patches = attrs.patches ++ [ + "${self.inputs.openwrt}/package/network/services/hostapd/patches/710-vlan_no_bridge.patch" + ]; + }); + in { + "${nativeSystem}" = { + hostapd_patched = mkPatchedHostapd pkgs; + }; + + cross = { + hostapd_patched = mkPatchedHostapd pkgsCross; + }; + }; }; } diff --git a/secrets/router0-dmz0/secrets.yaml b/secrets/router0-dmz0/secrets.yaml index ee184e9..56e013e 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: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: [] @@ -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-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: |-