feat(router0-dmz0): AP with dynamic vlan filtering on central bridge

This commit is contained in:
steveej 2023-12-26 16:18:33 +01:00
parent 8bcb433257
commit c0a8792af7
5 changed files with 189 additions and 126 deletions

14
flake.lock generated
View file

@ -27,11 +27,11 @@
"stable": "stable" "stable": "stable"
}, },
"locked": { "locked": {
"lastModified": 1688224393, "lastModified": 1699171528,
"narHash": "sha256-rsAvFNhRFzTF7qyb6WprLFghJnRxMFjvD2e5/dqMp4I=", "narHash": "sha256-ZsN6y+tgN5w84oAqRQpMhIvQM39ZNSZoZvn2AK0QYr4=",
"owner": "zhaofengli", "owner": "zhaofengli",
"repo": "colmena", "repo": "colmena",
"rev": "19384f3ee2058c56021e4465a3ec57e84a47d8dd", "rev": "665603956a1c3040d756987bc7a810ffe86a3b15",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -746,16 +746,16 @@
}, },
"stable": { "stable": {
"locked": { "locked": {
"lastModified": 1669735802, "lastModified": 1696039360,
"narHash": "sha256-qtG/o/i5ZWZLmXw108N2aPiVsxOcidpHJYNkT45ry9Q=", "narHash": "sha256-g7nIUV4uq1TOVeVIDEZLb005suTWCUjSY0zYOlSBsyE=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "731cc710aeebecbf45a258e977e8b68350549522", "rev": "32dcb45f66c0487e92db8303a798ebc548cadedc",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-22.11", "ref": "nixos-23.05",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }

View file

@ -1,7 +1,5 @@
{ {
modulesPath,
repoFlake, repoFlake,
packages',
pkgs, pkgs,
lib, lib,
config, config,
@ -154,7 +152,7 @@ in {
useNetworkd = true; useNetworkd = true;
useDHCP = false; useDHCP = false;
# No local firewall. # these will be configured via nftables
nat.enable = lib.mkForce false; nat.enable = lib.mkForce false;
firewall.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" = { # 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 = { netdevConfig = {
Kind = "vlan"; Kind = "vlan";
Name = "br-lan.15"; Name = "br-lan.${vlanid'}";
};
vlanConfig.Id = 15;
}; };
vlanConfig.Id = vlanid;
}; };
})
(builtins.map
(vlanid: { inherit vlanid; vlanid' = builtins.toString vlanid; })
vlanRange
)
)
;
networks = { networks = {
# use lan0 as secondary WAN interface # use lan0 as secondary WAN interface
"10-lan0-wan" = { "10-lan0-wan" = {
@ -377,16 +387,28 @@ in {
} }
]; ];
vlan = [ vlan = (builtins.map
"br-lan.15" (vlanid: "br-lan.${builtins.toString vlanid}")
]; vlanRange
);
}; };
# TODO: generate one of these for each vlanid }
"41-br-lan.15" = let
vlanid = 15; # configuration for the hostapd dynamic interfaces
in { # TODO: refactor this to configure the following per vlanid
matchConfig.Name = "br-lan.15"; # * 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 = [ address = [
(mkVlanIpv4HostAddr { inherit vlanid; host = 1; }) (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 # configure the wlan interface as a bridge member that
# * only gets traffic for vid 15 # * only gets traffic for vid 15
# * untags traffic after receiving it # * untags traffic after receiving it
# * tags traffic that comes out of it # * tags traffic that comes out of it
"41-wlan0.15" = let "41-wlan0.${vlanid'}" = {
vlanid = 15; matchConfig.Name = "wlan0.${vlanid'}";
in {
matchConfig.Name = "wlan0.15";
networkConfig = { networkConfig = {
Bridge = "br-lan"; Bridge = "br-lan";
ConfigureWithoutCarrier = true; ConfigureWithoutCarrier = true;
@ -435,19 +454,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
//
builtins.foldl'
(acc: cur: acc // cur)
{}
(builtins.map
({ vlanid, vlanid' }: {
"50-br-lan.${vlanid'}" = { "50-br-lan.${vlanid'}" = {
matchConfig.Name = "br-lan.${vlanid'}"; matchConfig.Name = "br-lan.${vlanid'}";
address = [ address = [
@ -472,14 +478,14 @@ in {
(builtins.map (builtins.map
(vlanid: { inherit vlanid; vlanid' = builtins.toString vlanid; }) (vlanid: { inherit vlanid; vlanid' = builtins.toString vlanid; })
vlanRange vlanRange
) ))
); ;
}; };
# wireless access point # wireless access point
services.hostapd = { services.hostapd = {
enable = true; enable = true;
package = nodeFlake.packages.hostapd_main; package = nodeFlake.packages.${system}.hostapd_patched;
radios = let radios = let
# generated with https://miniwebtool.com/mac-address-generator/ # generated with https://miniwebtool.com/mac-address-generator/
mkBssid = i: "34:56:ce:0f:ed:4${toString i}"; 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://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 # 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_tagged_interface = "br-lan";
vlan_naming = 1; vlan_naming = 1;
vlan_bridge = "br-${iface}."; 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 # 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 # name will be replaced with the VLAN ID. The network interfaces are created
# (and removed) dynamically based on the use. # (and removed) dynamically based on the use.
# see https://w1.fi/cgit/hostap/tree/hostapd/hostapd.vlan # 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_key_mgmt = lib.mkForce (builtins.concatStringsSep " " [
"WPA-PSK" "WPA-PSK"
@ -692,7 +713,7 @@ in {
tag tag
(mkVlanIpv4HostAddr { inherit vlanid; host = 100; cidr = false; }) (mkVlanIpv4HostAddr { inherit vlanid; host = 100; cidr = false; })
(mkVlanIpv4HostAddr { inherit vlanid; host = 199; cidr = false; }) (mkVlanIpv4HostAddr { inherit vlanid; host = 199; cidr = false; })
"5m" "30m"
]; ];
in in
builtins.map builtins.map
@ -748,7 +769,7 @@ in {
system.stateVersion = "23.05"; 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 # 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. # not apply to embedded hardware like this, so simply skip the defaults.
# #

View file

@ -1,11 +1,10 @@
{ {
system ? "aarch64-linux",
nodeName, nodeName,
repoFlake, repoFlake,
nodeFlake, nodeFlake,
... ...
}: let }: {
system = "aarch64-linux";
in {
meta.nodeSpecialArgs.${nodeName} = { meta.nodeSpecialArgs.${nodeName} = {
inherit repoFlake nodeName nodeFlake system; inherit repoFlake nodeName nodeFlake system;
packages' = repoFlake.packages.${system}; packages' = repoFlake.packages.${system};

View file

@ -7,17 +7,18 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1703182100, "lastModified": 1703603768,
"narHash": "sha256-zl2G9ex86b8G6J9+QT4n9g26G8dtandIt1LlFhZiaxE=", "narHash": "sha256-ZViXHNt7ClqNtlRO9iot+LxiSbBvZi/RR+/6Q7W6UV8=",
"ref": "refs/heads/linux-6.6", "owner": "steveej-forks",
"rev": "953a04e6792c412a664212db6a64bbaaa35bff0a", "repo": "nixos-bpir3",
"revCount": 31, "rev": "47cb545b92c136d1482a66b940c4719c40eb5fe3",
"type": "git", "type": "github"
"url": "file:///home/steveej/src/steveej/nixos-bpir3"
}, },
"original": { "original": {
"type": "git", "owner": "steveej-forks",
"url": "file:///home/steveej/src/steveej/nixos-bpir3" "ref": "linux-6.6",
"repo": "nixos-bpir3",
"type": "github"
} }
}, },
"dependencyDagOfSubmodule": { "dependencyDagOfSubmodule": {
@ -48,11 +49,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1703162528, "lastModified": 1703532766,
"narHash": "sha256-pQ41wN6JlStkZOhRTIHEpuwVywLdh+xzZQW1+FzdjVs=", "narHash": "sha256-ojjW3cuNmqL5uqDWohwLoO8dYpheM5+AfgsNmGIMwG8=",
"owner": "nix-community", "owner": "nix-community",
"repo": "disko", "repo": "disko",
"rev": "a050895e4eb06e0738680021a701ea05dc8dbfc9", "rev": "1b191113874dee97796749bb21eac3d84735c70a",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -83,11 +84,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1703368619, "lastModified": 1703527373,
"narHash": "sha256-ZGPMYL7FMA6enhuwby961bBANmoFX14EA86m2/Jw5Jo=", "narHash": "sha256-AjypRssRtS6F3xkf7rE3/bXkIF2WJOZLbTIspjcE1zM=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "a2523ea0343b056ba240abbac90ab5f116a7aa7b", "rev": "80679ea5074ab7190c4cce478c600057cfb5edae",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -136,11 +137,11 @@
}, },
"nixos-stable": { "nixos-stable": {
"locked": { "locked": {
"lastModified": 1702921762, "lastModified": 1703068421,
"narHash": "sha256-O/rP7gulApQAB47u6szEd8Pn8Biw0d84j5iuP2tcxzY=", "narHash": "sha256-WSw5Faqlw75McIflnl5v7qVD/B3S2sLh+968bpOGrWA=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "d02ffbbe834b5599fc5f134e644e49397eb07188", "rev": "d65bceaee0fb1e64363f7871bc43dc1c6ecad99f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -166,6 +167,24 @@
"type": "github" "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": { "root": {
"inputs": { "inputs": {
"bpir3": "bpir3", "bpir3": "bpir3",
@ -175,6 +194,7 @@
"hostapd": "hostapd", "hostapd": "hostapd",
"nixos-nftables-firewall": "nixos-nftables-firewall", "nixos-nftables-firewall": "nixos-nftables-firewall",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"openwrt": "openwrt",
"srvos": "srvos" "srvos": "srvos"
} }
}, },
@ -186,11 +206,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1703258052, "lastModified": 1703469109,
"narHash": "sha256-gWGQxht/xRJRnA+35aHtpmev7snsM+2GBdaPyarXNqU=", "narHash": "sha256-hTQJ9uV43Vt8UXwervEj9mbDoQSN1mD3lwwPChG8jy8=",
"owner": "numtide", "owner": "numtide",
"repo": "srvos", "repo": "srvos",
"rev": "0c7eefd13776730f33ea28fb984dd95cb5357e8e", "rev": "52d07db520046c4775f1047e68a05dcb53bba9ec",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -1,7 +1,6 @@
{ {
inputs = { inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
# nixpkgs.url = "github:steveej-forks/nixpkgs/hostapd-fix";
get-flake.url = "github:ursi/get-flake"; get-flake.url = "github:ursi/get-flake";
@ -13,15 +12,29 @@
srvos.url = "github:numtide/srvos"; srvos.url = "github:numtide/srvos";
srvos.inputs.nixpkgs.follows = "nixpkgs"; srvos.inputs.nixpkgs.follows = "nixpkgs";
# bpir3.url = "github:steveej-forks/nixos-bpir3"; bpir3.url =
bpir3.url = "/home/steveej/src/steveej/nixos-bpir3"; "github:steveej-forks/nixos-bpir3/linux-6.6"
# "/home/steveej/src/steveej/nixos-bpir3"
;
bpir3.inputs.nixpkgs.follows = "nixpkgs"; bpir3.inputs.nixpkgs.follows = "nixpkgs";
nixos-nftables-firewall.url = "github:thelegy/nixos-nftables-firewall"; nixos-nftables-firewall.url = "github:thelegy/nixos-nftables-firewall";
nixos-nftables-firewall.inputs.nixpkgs.follows = "nixpkgs"; nixos-nftables-firewall.inputs.nixpkgs.follows = "nixpkgs";
hostapd.url = "git://w1.fi/hostap.git?branch=main"; hostapd.url = "git://w1.fi/hostap.git?branch=main";
hostapd.flake = false; 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 = { outputs = {
@ -30,25 +43,31 @@
nixpkgs, nixpkgs,
bpir3, bpir3,
... ...
} @ attrs: let }: let
system = "aarch64-linux"; nativeSystem = "aarch64-linux";
nodeName = "router0-dmz0"; 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: mkNixosConfiguration = {extraModules ? [], ...} @ attrs:
nixpkgs.lib.nixosSystem ( nixpkgs.lib.nixosSystem (
nixpkgs.lib.attrsets.recursiveUpdate nixpkgs.lib.attrsets.recursiveUpdate
attrs attrs
{ {
specialArgs = { # TODO: it would be nice if this were the same as meta.nodeSpecialArgs.${nodeName} as in the default.nix
nodeFlake = self; specialArgs = (import ./default.nix {
repoFlake = get-flake ../../../..; system = nativeSystem;
inherit nodeName; inherit nodeName;
inherit
(bpir3.packages.${system}) repoFlake = get-flake ../../../..;
armTrustedFirmwareMT7986 nodeFlake = self;
; }).meta.nodeSpecialArgs.${nodeName};
};
modules = modules =
[ [
@ -67,6 +86,7 @@
inherit inherit
(bpir3Pkgs) (bpir3Pkgs)
linuxPackages_bpir3 linuxPackages_bpir3
linuxPackages_bpir3_latest
; ;
}) })
@ -79,30 +99,33 @@
in { in {
nixosConfigurations = { nixosConfigurations = {
native = mkNixosConfiguration { native = mkNixosConfiguration {
inherit system; system = nativeSystem;
}; };
cross = mkNixosConfiguration { cross = mkNixosConfiguration {
extraModules = [ extraModules = [
{ {
nixpkgs.buildPlatform.system = "x86_64-linux"; nixpkgs.buildPlatform.system = "x86_64-linux";
nixpkgs.hostPlatform.system = system; nixpkgs.hostPlatform.system = nativeSystem;
} }
]; ];
}; };
}; };
packages = { packages = let
hostapd_main = pkgs.hostapd.overrideDerivation(attrs: { mkPatchedHostapd = pkgs: pkgs.hostapd.overrideDerivation(attrs: {
src = self.inputs.hostapd;
version = self.inputs.hostapd.rev;
patches = attrs.patches ++ [ patches = attrs.patches ++ [
(builtins.fetchurl { "${self.inputs.openwrt}/package/network/services/hostapd/patches/710-vlan_no_bridge.patch"
url = "https://raw.githubusercontent.com/openwrt/openwrt/main/package/network/services/hostapd/patches/710-vlan_no_bridge.patch";
sha256 = "sha256:1p6fjjdwx5xrxyvllfrmvdkiji7bgx997k1qmp199bbic1fq6ks9";
})
]; ];
}); });
in {
"${nativeSystem}" = {
hostapd_patched = mkPatchedHostapd pkgs;
};
cross = {
hostapd_patched = mkPatchedHostapd pkgsCross;
};
}; };
}; };
} }