WIP: router0-dmz0: use bridge vlan filtering for the dynamic wlan interfaces
This commit is contained in:
parent
c365970cdf
commit
8bcb433257
3 changed files with 202 additions and 64 deletions
|
@ -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
|
||||
'')
|
||||
];
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue