2024-02-08 20:53:22 +01:00
{
repoFlake ,
pkgs ,
lib ,
config ,
nodeFlake ,
nodeName ,
localDomainName ,
system ,
. . .
} : let
2023-08-10 21:45:49 +02:00
inherit
( nodeFlake . inputs )
nixos-nftables-firewall
2024-06-02 23:27:14 +02:00
nixos-sbc
2023-08-10 21:45:49 +02:00
;
2023-12-28 10:38:38 +00:00
vlanRangeStart = builtins . head vlanRange ;
2024-01-18 23:35:54 +01:00
vlanRangeEnd = builtins . elemAt vlanRange ( ( builtins . length vlanRange ) - 1 ) ;
2023-12-28 10:38:38 +00:00
vlanRange = builtins . map ( vlanid : ( lib . strings . toInt vlanid ) ) ( builtins . attrNames vlans ) ;
2024-02-08 20:53:22 +01:00
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
2023-12-28 10:38:38 +00:00
builtins . concatStringsSep " . "
2024-02-08 20:53:22 +01:00
[ " 1 9 2 " " 1 6 8 " ( toString ( vlanid + offset ) ) " ${ toString host } ${ lib . strings . optionalString cidr " / 2 4 " } " ] ;
2023-12-28 10:38:38 +00:00
defaultVlan = {
name = " ${ localDomainName } " ;
packet_priority = 0 ;
} ;
vlans = {
" 1 0 " . name = " m g m t " ;
" 1 0 " . packet_priority = 0 ;
" 1 1 " . name = " d m z " ;
" 1 1 " . packet_priority = -5 ;
" 1 2 " . name = " i o t " ;
" 1 2 " . packet_priority = -5 ;
" 1 3 " . name = " o f f i c e " ;
" 1 3 " . packet_priority = -10 ;
" 1 4 " . name = " g u e s t s " ;
" 1 4 " . packet_priority = 10 ;
" 1 5 " . name = " i o t 2 " ;
" 1 5 " . packet_priority = -10 ;
} ;
2024-02-08 20:53:22 +01:00
vlansByName =
lib . attrsets . mapAttrs'
(
vlanid' : attrs :
lib . attrsets . nameValuePair
2024-01-18 23:35:54 +01:00
attrs . name
2024-02-08 20:53:22 +01:00
( attrs
// {
id = lib . strings . toInt vlanid' ;
id' = vlanid' ;
} )
2024-01-18 23:35:54 +01:00
)
vlans ;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
getVlanDomain = { vlanid }:
2023-12-28 10:38:38 +00:00
if vlanid = = 0
2024-02-08 20:53:22 +01:00
then defaultVlan . name
else vlans . " ${ toString vlanid } " . name + " . " + defaultVlan . name ;
2023-12-28 10:38:38 +00:00
bridgeInterfaceName = " b r - l a n " ;
2024-02-08 20:53:22 +01:00
mkInterfaceName = { vlanid }:
2023-12-28 10:38:38 +00:00
if vlanid = = 0
then bridgeInterfaceName
2024-02-08 20:53:22 +01:00
else " ${ bridgeInterfaceName } . ${ toString vlanid } " ;
2024-01-18 23:35:54 +01:00
2024-06-02 23:27:14 +02:00
dmzExposedHost = " s j - s r v 1 . d m z . i n t e r n a l " ;
dmzExposedHostIpv4 = mkVlanIpv4HostAddr {
vlanid = vlansByName . dmz . id ;
host = 99 ;
cidr = false ;
} ;
# "sj-srv1.dmz.internal";
2024-02-08 20:53:22 +01:00
in {
2023-08-10 21:45:49 +02:00
imports = [
2024-06-02 23:27:14 +02:00
nixos-sbc . nixosModules . default
nixos-sbc . nixosModules . boards . bananapi . bpir3
{
sbc . version = " 0 . 2 " ;
sbc . bootstrap . rootFilesystem = " b t r f s " ;
sbc . wireless . wifi . acceptRegulatoryResponsibility = true ;
}
2023-08-10 21:45:49 +02:00
repoFlake . inputs . sops-nix . nixosModules . sops
../../profiles/common/user.nix
2024-06-02 23:27:14 +02:00
../../snippets/nix-settings.nix
2023-08-10 21:45:49 +02:00
nixos-nftables-firewall . nixosModules . default
{
services . openssh . enable = true ;
services . openssh . settings . PermitRootLogin = " y e s " ;
users . commonUsers = {
enable = true ;
enableNonRoot = false ;
rootPasswordFile = config . sops . secrets . passwords-root . path ;
} ;
2023-12-28 10:38:38 +00:00
sops . defaultSopsFile = ../../../../secrets / $ { nodeName } /secrets.yaml ;
sops . defaultSopsFormat = " y a m l " ;
sops . secrets . passwords-root . neededForUsers = true ;
2024-02-08 20:53:22 +01:00
sops . secrets . wlan0_saePasswordsFile = { } ;
sops . secrets . wlan0_wpaPskFile = { } ;
2023-08-10 21:45:49 +02:00
}
] ;
# sops.secrets.ssh_host_ed25519_key = {
# sopsFile = ../../../../secrets/${nodeName}/secrets.yaml;
# format = "yaml";
# path = "/etc/ssh/ssh_host_ed25519_key";
# mode = "0600";
# };
# sops.secrets.ssh_host_ed25519_key_pub = {
# sopsFile = ../../../../secrets/${nodeName}/secrets.yaml;
# format = "yaml";
# path = "/etc/ssh/ssh_host_ed25519_key.pub";
# mode = "0600";
# };
# sops.secrets.ssh_host_rsa_key = {
# sopsFile = ../../../../secrets/${nodeName}/secrets.yaml;
# format = "yaml";
# path = "/etc/ssh/ssh_host_rsa_key";
# mode = "0600";
# };
# sops.secrets.ssh_host_rsa_key_pub = {
# sopsFile = ../../../../secrets/${nodeName}/secrets.yaml;
# format = "yaml";
# path = "/etc/ssh/ssh_host_rsa_key.pub";
# mode = "0644";
# };
boot = {
kernel = {
sysctl = {
" n e t . i p v 4 . c o n f . a l l . f o r w a r d i n g " = true ;
" n e t . i p v 6 . c o n f . a l l . f o r w a r d i n g " = true ;
} ;
} ;
} ;
networking = {
hostName = nodeName ;
useNetworkd = true ;
useDHCP = false ;
2023-12-28 10:38:38 +00:00
# these will be configured via nftables
2023-08-10 21:45:49 +02:00
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
2023-12-28 10:38:38 +00:00
# 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)
2024-02-08 20:53:22 +01:00
nftables = {
enable = true ;
stopRuleset = " " ;
chains = {
prerouting = {
" e x p o s e H o s t " = {
after = [ " h o o k " ] ;
rules = let
wanInterfaces = builtins . concatStringsSep " , " config . networking . nftables . firewall . zones . wan . interfaces ;
2024-06-02 23:27:14 +02:00
in [
" i i f n a m e { ${ wanInterfaces } } t c p d p o r t 2 2 0 r e d i r e c t t o 2 2 "
" i i f n a m e { ${ wanInterfaces } } d n a t i p t o ${ dmzExposedHostIpv4 } "
] ;
2023-12-28 13:56:57 +01:00
} ;
} ;
2024-02-08 20:53:22 +01:00
} ;
2023-12-28 13:56:57 +01:00
2024-02-08 20:53:22 +01:00
firewall = {
enable = true ;
zones =
{
lan . interfaces = [ ( mkInterfaceName { vlanid = 0 ; } ) ] ;
vlan . interfaces = builtins . map ( vlanid : ( mkInterfaceName { inherit vlanid ; } ) ) vlanRange ;
2024-01-18 23:35:54 +01:00
# lan.ipv4Addresses = ["192.168.0.0/16"];
2024-02-08 20:53:22 +01:00
wan . interfaces = [ " w a n " " l a n 0 " ] ;
2024-06-01 10:55:40 +02:00
vpn . interfaces = [ " w g 0 " " w g 1 " ] ;
2024-02-08 20:53:22 +01:00
}
//
2023-12-28 10:38:38 +00:00
# generate a zone for each vlan
2024-01-18 23:35:54 +01:00
lib . attrsets . mapAttrs
2024-02-08 20:53:22 +01:00
( key : value : {
interfaces = [ ( mkInterfaceName { vlanid = value . id ; } ) ] ;
} )
vlansByName ;
rules = let
ipv6IcmpTypes = [
" d e s t i n a t i o n - u n r e a c h a b l e "
" e c h o - r e p l y "
" e c h o - r e q u e s t "
" p a c k e t - t o o - b i g "
" p a r a m e t e r - p r o b l e m "
" t i m e - e x c e e d e d "
# Without the nd-* ones ipv6 will not work.
" n d - n e i g h b o r - s o l i c i t "
" n d - r o u t e r - a d v e r t "
" n d - n e i g h b o r - a d v e r t "
] ;
ipv4IcmpTypes = [
" d e s t i n a t i o n - u n r e a c h a b l e "
" e c h o - r e p l y "
" e c h o - r e q u e s t "
" s o u r c e - q u e n c h "
" t i m e - e x c e e d e d "
" r o u t e r - a d v e r t i s e m e n t "
] ;
allowIcmpLines = [
" i p p r o t o c o l i c m p i c m p t y p e { ${ builtins . concatStringsSep " , " ipv4IcmpTypes } } a c c e p t "
" i p 6 n e x t h d r i c m p v 6 i c m p v 6 t y p e { ${ builtins . concatStringsSep " , " ipv6IcmpTypes } } a c c e p t "
] ;
in {
fw = {
from = [ " f w " ] ;
verdict = " a c c e p t " ;
} ;
2024-01-18 23:35:54 +01:00
2024-02-08 20:53:22 +01:00
office-to-dmz = {
from = [ " o f f i c e " ] ;
to = [ " d m z " ] ;
verdict = " a c c e p t " ;
} ;
2024-01-18 23:35:54 +01:00
2024-02-08 20:53:22 +01:00
lan-to-fw = {
from = [ " l a n " ] ;
to = [ " f w " " l a n " ] ;
verdict = " a c c e p t " ;
} ;
2024-01-18 23:35:54 +01:00
2024-02-08 20:53:22 +01:00
lan-to-wan = {
from = [ " l a n " ] ;
to = [ " w a n " ] ;
verdict = " a c c e p t " ;
} ;
2024-01-18 23:35:54 +01:00
2024-02-08 20:53:22 +01:00
vlan-to-wan = {
from = [ " v l a n " ] ;
to = [ " w a n " ] ;
verdict = " a c c e p t " ;
} ;
2024-01-18 23:35:54 +01:00
2024-02-08 20:53:22 +01:00
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 = [ " v l a n " ] ;
to = [ " f w " ] ;
extraLines =
allowIcmpLines
++ [
" d r o p "
] ;
} ;
2024-01-18 23:35:54 +01:00
2024-02-08 20:53:22 +01:00
to-wan-nat = {
from = [ " l a n " " v l a n " ] ;
to = [ " w a n " ] ;
masquerade = true ;
verdict = " a c c e p t " ;
} ;
2024-01-18 23:35:54 +01:00
2024-02-08 20:53:22 +01:00
wan-to-dmz = {
from = [ " w a n " ] ;
to = [ " d m z " ] ;
verdict = " a c c e p t " ;
} ;
2024-01-18 23:35:54 +01:00
2024-02-08 20:53:22 +01:00
wan-to-fw = {
from = [ " w a n " ] ;
to = [ " f w " ] ;
allowedTCPPortRanges = [
{
from = 22 ;
to = 22 ;
}
] ;
extraLines =
allowIcmpLines
++ [
" d r o p "
] ;
} ;
2024-06-01 10:55:40 +02:00
to-vpn-nat = {
from = [ " l a n " " v l a n " ] ;
to = [ " v p n " ] ;
masquerade = false ;
verdict = " a c c e p t " ;
} ;
2023-08-10 21:45:49 +02:00
} ;
} ;
2024-02-08 20:53:22 +01:00
} ;
2023-08-10 21:45:49 +02:00
} ;
2024-05-25 21:23:43 +02:00
sops . secrets . wg0-privatekey = {
mode = " 4 4 0 " ;
group = " s y s t e m d - n e t w o r k " ;
} ;
sops . secrets . wg1-privatekey = {
mode = " 4 4 0 " ;
group = " s y s t e m d - n e t w o r k " ;
} ;
sops . secrets . wg0-peer0-psk = {
mode = " 4 4 0 " ;
group = " s y s t e m d - n e t w o r k " ;
} ;
sops . secrets . wg1-peer0-psk = {
mode = " 4 4 0 " ;
group = " s y s t e m d - n e t w o r k " ;
} ;
2023-08-10 21:45:49 +02:00
systemd . network = {
wait-online . anyInterface = true ;
2024-05-25 21:23:43 +02:00
netdevs = let
2024-05-26 22:32:38 +02:00
router0-nmfk_wg0Endpoint = " ${ repoFlake . colmena . router0-nfmnk . deployment . targetHost } : ${
2024-05-25 21:23:43 +02:00
builtins . toString
repoFlake
. nixosConfigurations
. router0-nfmnk
. config
. systemd
. network
. netdevs
. wg0
. wireguardConfig
. ListenPort
} " ;
2024-05-26 22:32:38 +02:00
router0-nmfk_wg1Endpoint = " ${ repoFlake . colmena . router0-nfmnk . deployment . targetHost } : ${
builtins . toString
repoFlake
. nixosConfigurations
. router0-nfmnk
. config
. systemd
. network
. netdevs
. wg1
. wireguardConfig
. ListenPort
} " ;
2024-05-25 21:23:43 +02:00
in
2024-02-08 20:53:22 +01:00
{
# Create the bridge interface
" 2 0 - ${ bridgeInterfaceName } " = {
netdevConfig = {
Kind = " b r i d g e " ;
Name = bridgeInterfaceName ;
} ;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
extraConfig = ''
[ Bridge ]
STP = yes
VLANFiltering = yes
VLANProtocol = 802 . 1 q
DefaultPVID = 0
'' ;
} ;
2024-05-25 21:23:43 +02:00
wg0 = {
enable = true ;
netdevConfig = {
Name = " w g 0 " ;
Kind = " w i r e g u a r d " ;
} ;
wireguardConfig = {
PrivateKeyFile = builtins . toString config . sops . secrets . wg0-privatekey . path ;
2024-05-26 22:32:38 +02:00
FirewallMark = 100 ;
2024-05-25 21:23:43 +02:00
} ;
wireguardPeers = [
{
wireguardPeerConfig = {
AllowedIPs = [
2024-06-01 10:55:40 +02:00
# this allows all traffic to be routed through this interface
" 0 . 0 . 0 . 0 / 0 "
# # alternatively, specific destinations could be allowed
# # remote peer wg addr
# "10.0.0.0/32"
# "1.1.1.1/32"
# # ifconfig.co.
# "172.67.168.106"
# "104.21.54.91"
2024-05-25 21:23:43 +02:00
] ;
PersistentKeepalive = 15 ;
PresharedKeyFile = builtins . toString config . sops . secrets . wg0-peer0-psk . path ;
PublicKey = " / R P D d q P z r 9 i R c 7 z R 0 b R k t 9 a S 2 Q C t + b 2 K 3 W b s N g 8 X a m M = " ;
2024-05-26 22:32:38 +02:00
Endpoint = router0-nmfk_wg0Endpoint ;
2024-05-25 21:23:43 +02:00
} ;
}
] ;
} ;
2024-05-26 22:32:38 +02:00
wg1 = {
enable = true ;
netdevConfig = {
Name = " w g 1 " ;
Kind = " w i r e g u a r d " ;
} ;
wireguardConfig = {
PrivateKeyFile = builtins . toString config . sops . secrets . wg1-privatekey . path ;
FirewallMark = 101 ;
} ;
wireguardPeers = [
{
wireguardPeerConfig = {
AllowedIPs = [
2024-06-01 10:55:40 +02:00
# this allows all traffic to be routed through this interface
" 0 . 0 . 0 . 0 / 0 "
2024-05-26 22:32:38 +02:00
] ;
PersistentKeepalive = 15 ;
PresharedKeyFile = builtins . toString config . sops . secrets . wg1-peer0-psk . path ;
PublicKey = " / R P D d q P z r 9 i R c 7 z R 0 b R k t 9 a S 2 Q C t + b 2 K 3 W b s N g 8 X a m M = " ;
Endpoint = router0-nmfk_wg1Endpoint ;
} ;
}
] ;
} ;
2024-02-08 20:53:22 +01:00
}
# generate the vlan devices. these will be tagged on the main bridge
// builtins . foldl'
2023-12-28 10:38:38 +00:00
( acc : cur : acc // cur )
2024-02-08 20:53:22 +01:00
{ }
(
builtins . map
( {
vlanid ,
vlanid' ,
} : {
" 2 0 - ${ mkInterfaceName { inherit vlanid ; } } " = {
2023-12-28 10:38:38 +00:00
netdevConfig = {
Kind = " v l a n " ;
2024-02-08 20:53:22 +01:00
Name = " ${ mkInterfaceName { inherit vlanid ; } } " ;
2023-12-28 10:38:38 +00:00
} ;
vlanConfig . Id = vlanid ;
} ;
} )
2024-02-08 20:53:22 +01:00
(
builtins . map
( vlanid : {
inherit vlanid ;
vlanid' = builtins . toString vlanid ;
} )
2023-12-28 10:38:38 +00:00
vlanRange
)
2024-02-08 20:53:22 +01:00
) ;
networks =
{
2024-05-26 22:32:38 +02:00
# places options here that should always exist
" l o " = {
matchConfig . Name = " l o " ;
# these are roughly equivalent to:
# ip rule add fwmark 100 priority 0 table 100
# ip rule add fwmark 100 priority 1 prohibit
# ip rule add fwmark 101 priority 0 table 101
# ip rule add fwmark 101 priority 1 prohibit
routingPolicyRules = [
{
routingPolicyRuleConfig = {
FirewallMark = 101 ;
Priority = 30000 ;
Table = 101 ;
} ;
}
{
routingPolicyRuleConfig = {
FirewallMark = 101 ;
Priority = 30001 ;
Table = 101 ;
Type = " p r o h i b i t " ;
} ;
}
{
routingPolicyRuleConfig = {
FirewallMark = 100 ;
Priority = 30000 ;
Table = 100 ;
} ;
}
{
routingPolicyRuleConfig = {
FirewallMark = 100 ;
Priority = 30001 ;
Table = 100 ;
Type = " p r o h i b i t " ;
} ;
}
] ;
} ;
2024-02-08 20:53:22 +01:00
# use lan0 as secondary WAN interface
" 1 0 - l a n 0 - w a n " = {
matchConfig . Name = " l a n 0 " ;
networkConfig = {
# start a DHCP Client for IPv4 Addressing/Routing
DHCP = " i p v 4 " ;
# accept Router Advertisements for Stateless IPv6 Autoconfiguraton (SLAAC)
IPv6AcceptRA = true ;
DNSOverTLS = true ;
DNSSEC = true ;
IPv6PrivacyExtensions = false ;
IPForward = true ;
} ;
linkConfig . RequiredForOnline = " n o " ;
2024-05-26 22:32:38 +02:00
# similar to
# ip route add default via 172.16.0.1 table 101
routes = [
{
routeConfig = {
Gateway = " _ d h c p 4 " ;
Table = 101 ;
} ;
}
] ;
2023-12-28 10:38:38 +00:00
} ;
2024-02-08 20:53:22 +01:00
" 1 0 - w a n " = {
matchConfig . Name = " w a n " ;
networkConfig = {
# start a DHCP Client for IPv4 Addressing/Routing
DHCP = " i p v 4 " ;
# accept Router Advertisements for Stateless IPv6 Autoconfiguraton (SLAAC)
IPv6AcceptRA = true ;
DNSOverTLS = true ;
DNSSEC = true ;
IPv6PrivacyExtensions = false ;
IPForward = true ;
} ;
# make routing on this interface a dependency for network-online.target
2024-05-26 22:32:38 +02:00
# linkConfig.RequiredForOnline = "routable";
linkConfig . RequiredForOnline = " n o " ;
# similar to
# ip route add default via 192.168.0.1 table 100
routes = [
{
routeConfig = {
Gateway = " _ d h c p 4 " ;
Table = 100 ;
} ;
}
] ;
2023-08-10 21:45:49 +02:00
} ;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
# Connect the bridge ports to the bridge
" 3 0 - l a n 1 " = {
matchConfig . Name = " l a n 1 " ;
networkConfig = {
Bridge = bridgeInterfaceName ;
ConfigureWithoutCarrier = true ;
} ;
linkConfig . RequiredForOnline = " e n s l a v e d " ;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
bridgeVLANs = [
{
bridgeVLANConfig = {
VLAN = vlansByName . dmz . id ;
PVID = vlansByName . dmz . id ;
EgressUntagged = vlansByName . dmz . id ;
} ;
}
] ;
2023-08-10 21:45:49 +02:00
} ;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
" 3 0 - l a n 2 " = {
matchConfig . Name = " l a n 2 " ;
networkConfig = {
Bridge = bridgeInterfaceName ;
ConfigureWithoutCarrier = true ;
} ;
linkConfig . RequiredForOnline = " e n s l a v e d " ;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
bridgeVLANs = [
{
bridgeVLANConfig = {
VLAN = vlansByName . office . id ;
PVID = vlansByName . office . id ;
EgressUntagged = vlansByName . office . id ;
} ;
}
] ;
2023-08-10 21:45:49 +02:00
} ;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
" 3 0 - l a n 3 " = {
matchConfig . Name = " l a n 3 " ;
networkConfig = {
Bridge = bridgeInterfaceName ;
ConfigureWithoutCarrier = true ;
} ;
linkConfig . RequiredForOnline = " e n s l a v e d " ;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
bridgeVLANs = [
{
bridgeVLANConfig = {
VLAN = " ${ toString vlanRangeStart } - ${ toString vlanRangeEnd } " ;
} ;
}
] ;
} ;
# Configure the bridge for its desired function
" 4 0 - ${ 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 = " n o " ;
linkConfig . ActivationPolicy = " a l w a y s - u p " ;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
bridgeVLANs = [
{
bridgeVLANConfig = {
VLAN = " ${ toString vlanRangeStart } - ${ toString vlanRangeEnd } " ;
} ;
}
] ;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
vlan = (
builtins . map
( vlanid : ( mkInterfaceName { inherit vlanid ; } ) )
vlanRange
) ;
} ;
2024-05-25 21:23:43 +02:00
" 5 0 - w g 0 " = {
enable = true ;
matchConfig . Name = " w g 0 " ;
address = [
2024-05-26 22:32:38 +02:00
" 1 0 . 0 . 0 . 1 / 3 1 "
] ;
2024-06-01 10:55:40 +02:00
routes = [
{
routeConfig = {
Destination = " 1 8 5 . 1 4 3 . 1 0 1 . 4 2 / 3 2 " ;
MultiPathRoute = " 1 0 . 0 . 0 . 0 1 " ;
} ;
}
] ;
2024-05-26 22:32:38 +02:00
} ;
" 5 0 - w g 1 " = {
enable = true ;
matchConfig . Name = " w g 1 " ;
address = [
" 1 0 . 0 . 0 . 3 / 3 1 "
2024-05-25 21:23:43 +02:00
] ;
2024-06-01 10:55:40 +02:00
routes = [
{
routeConfig = {
Destination = " 1 8 5 . 1 4 3 . 1 0 1 . 4 2 / 3 2 " ;
MultiPathRoute = " 1 0 . 0 . 0 . 2 1 " ;
} ;
}
] ;
2024-05-25 21:23:43 +02:00
} ;
2024-02-08 20:53:22 +01:00
}
# configuration for the hostapd dynamic interfaces
# * netdev type vlan
# * host address for vlan
# * vlan config for wlan interface
// builtins . foldl'
2024-01-18 23:35:54 +01:00
( acc : cur : acc // cur )
2024-02-08 20:53:22 +01:00
{ }
2024-01-18 23:35:54 +01:00
( builtins . map
2024-02-08 20:53:22 +01:00
( {
vlanid ,
vlanid' ,
} : {
2024-01-18 23:35:54 +01:00
# 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.
2024-02-08 20:53:22 +01:00
" 4 1 - ${ mkInterfaceName { inherit vlanid ; } } " = {
matchConfig . Name = " ${ mkInterfaceName { inherit vlanid ; } } " ;
2024-01-18 23:35:54 +01:00
address = [
2024-02-08 20:53:22 +01:00
( mkVlanIpv4HostAddr {
inherit vlanid ;
host = 1 ;
} )
2024-01-18 23:35:54 +01:00
] ;
networkConfig = {
ConfigureWithoutCarrier = true ;
} ;
2023-12-28 10:38:38 +00:00
2024-01-18 23:35:54 +01:00
linkConfig . RequiredForOnline = " n o " ;
linkConfig . ActivationPolicy = " a l w a y s - u p " ;
2023-12-28 10:38:38 +00:00
2024-01-18 23:35:54 +01:00
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
" 4 1 - w l a n 0 . ${ vlanid' } " = {
matchConfig . Name = " w l a n 0 . ${ vlanid' } " ;
networkConfig = {
Bridge = bridgeInterfaceName ;
ConfigureWithoutCarrier = true ;
2023-12-28 10:38:38 +00:00
} ;
2024-01-18 23:35:54 +01:00
linkConfig . RequiredForOnline = " n o " ;
2023-12-28 10:38:38 +00:00
2024-01-18 23:35:54 +01:00
bridgeVLANs = [
{
bridgeVLANConfig = {
VLAN = vlanid ;
PVID = vlanid ;
EgressUntagged = vlanid ;
} ;
}
] ;
} ;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
" 5 0 - ${ mkInterfaceName { inherit vlanid ; } } " = {
matchConfig . Name = " ${ mkInterfaceName { inherit vlanid ; } } " ;
2024-01-18 23:35:54 +01:00
address = [
2024-02-08 20:53:22 +01:00
( mkVlanIpv4HostAddr {
inherit vlanid ;
host = 1 ;
} )
2024-01-18 23:35:54 +01:00
] ;
networkConfig = {
ConfigureWithoutCarrier = true ;
2023-12-28 10:38:38 +00:00
} ;
2024-01-18 23:35:54 +01:00
linkConfig . RequiredForOnline = " n o " ;
} ;
} )
2024-02-08 20:53:22 +01:00
(
builtins . map
( vlanid : {
inherit vlanid ;
vlanid' = builtins . toString vlanid ;
} )
2024-01-18 23:35:54 +01:00
vlanRange
2024-02-08 20:53:22 +01:00
) ) ;
2023-08-10 21:45:49 +02:00
} ;
# wireless access point
services . hostapd = {
enable = true ;
2024-06-02 23:27:14 +02:00
# package = nodeFlake.packages.${system}.hostapd_patched;
2024-02-08 20:53:22 +01:00
radios = let
# generated with https://miniwebtool.com/mac-address-generator/
mkBssid = i : " 3 4 : 5 6 : c e : 0 f : e d : 4 ${ toString i } " ;
in {
wlan0 = {
band = " 2 g " ;
countryCode = " C H " ;
channel = 0 ; # ACS
# use 'iw phy#1 info' to determine your VHT capabilities
wifi4 = {
enable = true ;
capabilities = [ " H T 4 0 + " " L D P C " " S H O R T - G I - 2 0 " " S H O R T - G I - 4 0 " " T X - S T B C " " R X - S T B C 1 " " M A X - A M S D U - 7 9 3 5 " ] ;
} ;
networks = {
wlan0 = let
iface = " w l a n 0 " ;
in {
ssid = " m l s i a " ;
bssid = mkBssid 0 ;
2023-08-10 21:45:49 +02:00
2024-02-08 20:53:22 +01:00
# authentication.mode = "wpa3-sae";
authentication . mode = " w p a 3 - s a e - t r a n s i t i o n " ;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
authentication . wpaPskFile = config . sops . secrets . " ${ iface } _ w p a P s k F i l e " . path ;
authentication . saePasswordsFile = config . sops . secrets . " ${ iface } _ s a e P a s s w o r d s F i l e " . path ;
2023-08-10 21:45:49 +02:00
2024-02-08 20:53:22 +01:00
# see https://w1.fi/cgit/hostap/plain/hostapd/hostapd.conf for reference
settings = {
# bridge = bridgeInterfaceName;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
# 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;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
# enables debug logging
logger_stdout_level = lib . mkForce 0 ;
logger_stdout = -1 ;
# logger_syslog_level= lib.mkForce 0;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
# 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
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
dynamic_vlan = 1 ;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
# this option currently requires a patch to hostapd
vlan_no_bridge = 1 ;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
/*
not used due to the above vlan_no_bridge setting
2023-12-28 10:38:38 +00:00
vlan_tagged_interface = bridgeInterfaceName ;
vlan_naming = 1 ;
vlan_bridge = " b r - ${ iface } . " ;
2024-02-08 20:53:22 +01:00
* /
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 " h o s t a p d . v l a n "
( builtins . concatStringsSep " \n " ( generated ++ wildcard ) ) ;
filePath = toString file ;
in
filePath ;
2024-01-18 23:35:54 +01:00
2024-02-08 20:53:22 +01:00
wpa_key_mgmt = lib . mkForce ( builtins . concatStringsSep " " [
" W P A - P S K "
# 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"
] ) ;
# wpa_psk_radius = 0;
wpa_pairwise = " C C M P " ;
wmm_enabled = 1 ;
# IEEE 802.11i (authentication) related configuration
# Encrypt management frames to protect against deauthentication and similar attacks
ieee80211w = 1 ;
sae_require_mfp = 1 ;
sae_groups = " 1 9 2 0 2 1 " ;
# [ENABLE-TLSv1.3] = enable TLSv1.3 (experimental - disabled by default)
tls_flags = " [ E N A B L E - T L S v 1 . 3 ] " ;
ieee8021x = 0 ;
eap_server = 0 ;
} ;
2023-08-10 21:45:49 +02:00
} ;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
# wlan0-1 = {
# ssid = "mlsia-testing";
# authentication = {
# mode = "wpa3-sae-transition";
# };
# bssid = mkBssid 1;
# settings = {
# bridge = bridgeInterfaceName;
# };
# };
# wlan0-1 = {
# ssid = "justtestingwifi-wpa3";
# authentication = {
# mode = "wpa3-sae";
# saePasswordsFile = config.sops.secrets.wlan0_1_saePasswordFile.path;
# };
# bssid = mkBssid 1;
# settings = {
# bridge = bridgeInterfaceName;
# };
# };
# Uncomment when needed otherwise remove
# wlan0-1 = {
# ssid = "koteczkowo3";
# authentication = {
# mode = "none"; # this is overriden by settings
# };
# managementFrameProtection = "optional";
# bssid = "e6:02:43:07:00:00";
# settings = {
# bridge = bridgeInterfaceName;
# wpa = lib.mkForce 2;
# wpa_key_mgmt = "WPA-PSK";
# wpa_pairwise = "CCMP";
# wpa_psk_file = config.sops.secrets.legacyWifiPassword.path;
# };
# };
} ;
2024-01-18 23:35:54 +01:00
} ;
2024-02-08 20:53:22 +01:00
# wlan1 = {
# band = "5g";
# # channels with 160 MHz width in Poland: 36, 52, 100 i 116
# channel = 0; # ACS
# countryCode = "PL";
# # use 'iw phy#1 info' to determine your VHT capabilities
# wifi4 = {
# enable = true;
# capabilities = ["HT40+" "LDPC" "SHORT-GI-20" "SHORT-GI-40" "TX-STBC" "RX-STBC1" "MAX-AMSDU-7935"];
# };
# wifi5 = {
# enable = true;
# operatingChannelWidth = "160";
# capabilities = ["RXLDPC" "SHORT-GI-80" "SHORT-GI-160" "TX-STBC-2BY1" "SU-BEAMFORMER" "SU-BEAMFORMEE" "MU-BEAMFORMER" "MU-BEAMFORMEE" "RX-ANTENNA-PATTERN" "TX-ANTENNA-PATTERN" "RX-STBC-1" "SOUNDING-DIMENSION-4" "BF-ANTENNA-4" "VHT160" "MAX-MPDU-11454" "MAX-A-MPDU-LEN-EXP7"];
# };
# wifi6 = {
# enable = true;
# singleUserBeamformer = true;
# singleUserBeamformee = true;
# multiUserBeamformer = true;
# operatingChannelWidth = "160";
# };
# settings = {
# # these two are mandatory for wifi 5 & 6 to work
# vht_oper_centr_freq_seg0_idx = 50;
# he_oper_centr_freq_seg0_idx = 50;
# # The "tx_queue_data2_burst" parameter in Linux refers to the burst size for
# # transmitting data packets from the second data queue of a network interface.
# # It determines the number of packets that can be sent in a burst.
# # Adjusting this parameter can impact network throughput and latency.
# tx_queue_data2_burst = 2;
# # The "he_bss_color" parameter in Wi-Fi 6 (802.11ax) refers to the BSS Color field in the HE (High Efficiency) MAC header.
# # BSS Color is a mechanism introduced in Wi-Fi 6 to mitigate interference and improve network efficiency in dense deployment scenarios.
# # It allows multiple overlapping Basic Service Sets (BSS) to differentiate and coexist in the same area without causing excessive interference.
# he_bss_color = 63; # was set to 128 by openwrt but range of possible values in 2.10 is 1-63
# # Magic values that were set by openwrt but I didn't bother inspecting every single one
# he_spr_sr_control = 3;
# he_default_pe_duration = 4;
# he_rts_threshold = 1023;
# he_mu_edca_qos_info_param_count = 0;
# he_mu_edca_qos_info_q_ack = 0;
# he_mu_edca_qos_info_queue_request = 0;
# he_mu_edca_qos_info_txop_request = 0;
# # he_mu_edca_ac_be_aci=0; missing in 2.10
# he_mu_edca_ac_be_aifsn = 8;
# he_mu_edca_ac_be_ecwmin = 9;
# he_mu_edca_ac_be_ecwmax = 10;
# he_mu_edca_ac_be_timer = 255;
# he_mu_edca_ac_bk_aifsn = 15;
# he_mu_edca_ac_bk_aci = 1;
# he_mu_edca_ac_bk_ecwmin = 9;
# he_mu_edca_ac_bk_ecwmax = 10;
# he_mu_edca_ac_bk_timer = 255;
# he_mu_edca_ac_vi_ecwmin = 5;
# he_mu_edca_ac_vi_ecwmax = 7;
# he_mu_edca_ac_vi_aifsn = 5;
# he_mu_edca_ac_vi_aci = 2;
# he_mu_edca_ac_vi_timer = 255;
# he_mu_edca_ac_vo_aifsn = 5;
# he_mu_edca_ac_vo_aci = 3;
# he_mu_edca_ac_vo_ecwmin = 5;
# he_mu_edca_ac_vo_ecwmax = 7;
# he_mu_edca_ac_vo_timer = 255;
# };
# networks = {
# wlan1 = {
# ssid = "koteczkowo5";
# authentication = {
# mode = "wpa3-sae";
# saePasswordsFile = config.sops.secrets.wifiPassword.path; # Use saePasswordsFile if possible.
# };
# bssid = "36:b9:02:21:08:a2";
# settings = {
# bridge = bridgeInterfaceName;
# };
# };
# };
# };
} ;
2023-08-10 21:45:49 +02:00
} ;
services . resolved . enable = false ;
services . dnsmasq = {
enable = true ;
settings = {
domain-needed = true ;
bogus-priv = true ;
no-resolv = true ;
2023-12-28 10:38:38 +00:00
localise-queries = true ;
2023-08-10 21:45:49 +02:00
2023-12-28 10:38:38 +00:00
proxy-dnssec = true ;
conntrack = true ;
2023-12-28 13:56:57 +01:00
# enable for debugging
# log-debug = true;
# log-queries = true;
2023-12-28 10:38:38 +00:00
# disable negative caching
no-negcache = true ;
local-ttl = 0 ;
dhcp-ttl = 0 ;
2024-02-08 20:53:22 +01:00
dhcp-range = let
mkDhcpRange = {
tag ,
vlanid ,
} :
builtins . concatStringsSep " , " [
2024-01-18 23:35:54 +01:00
tag
2024-02-08 20:53:22 +01:00
( mkVlanIpv4HostAddr {
inherit vlanid ;
host = 100 ;
cidr = false ;
} )
( mkVlanIpv4HostAddr {
inherit vlanid ;
host = 199 ;
cidr = false ;
} )
2024-01-18 23:35:54 +01:00
" 1 2 h "
] ;
2024-02-08 20:53:22 +01:00
in
2023-12-28 10:38:38 +00:00
builtins . map
2024-02-08 20:53:22 +01:00
(
vlanid :
mkDhcpRange {
tag = mkInterfaceName { inherit vlanid ; } ;
inherit vlanid ;
}
)
vlanRangeWith0 ;
2023-12-28 10:38:38 +00:00
2024-06-02 23:27:14 +02:00
# TODO: double-check that this works
dhcp-host = " 1 c : 6 9 : 7 a : 0 7 : 0 8 : 5 f , ${ dmzExposedHostIpv4 } , ${ dmzExposedHost } " ;
2023-08-10 21:45:49 +02:00
expand-hosts = true ;
2023-08-22 10:20:16 +02:00
# don't use /etc/hosts as this would advertise ${nodeName} as localhost
2023-08-10 21:45:49 +02:00
no-hosts = true ;
2023-12-28 10:38:38 +00:00
server = [
# upstream DNS servers
# https://dnsforge.de/
" 1 7 6 . 9 . 9 3 . 1 9 8 "
" 1 7 6 . 9 . 1 . 1 1 7 "
" 2 a 0 1 : 4 f 8 : 1 5 1 : 3 4 a a : : 1 9 8 "
" 2 a 0 1 : 4 f 8 : 1 4 1 : 3 1 6 d : : 1 1 7 "
# cloudflare and google
# "9.9.9.9" "8.8.8.8" "1.1.1.1"
] ;
2024-02-08 20:53:22 +01:00
domain =
[
" / ${ getVlanDomain { vlanid = 0 ; } } / , l o c a l "
]
++ builtins . map
(
vlanid : " ${ getVlanDomain { inherit vlanid ; } } , ${ mkVlanIpv4HostAddr {
inherit vlanid ;
host = 0 ;
cidr = true ;
} } , local "
2023-12-28 10:38:38 +00:00
)
2024-02-08 20:53:22 +01:00
vlanRangeWith0 ;
2023-12-28 10:38:38 +00:00
# TODO: compare this to using `interface-name`
2024-02-08 20:53:22 +01:00
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 ; } )
]
2023-12-28 10:38:38 +00:00
)
2024-02-08 20:53:22 +01:00
vlanRangeWith0 ;
2023-12-28 10:38:38 +00:00
2024-02-08 20:53:22 +01:00
dhcp-option-force =
builtins . map
( vlanid : " ${ mkInterfaceName { inherit vlanid ; } } , o p t i o n : d o m a i n - s e a r c h , ${ getVlanDomain { inherit vlanid ; } } " )
vlanRangeWith0 ;
2024-01-18 23:35:54 +01:00
2024-01-19 13:56:20 +01:00
# auth-server = [
# (builtins.concatStringsSep "," [
# "www.stefanjunker.de"
# # (mkInterfaceName { vlanid = vlansByName.dmz.id; })
# # (mkInterfaceName { vlanid = vlansByName.office.id; })
# ])
# ];
2024-04-18 17:24:49 +02:00
cname = [
2024-06-02 23:27:14 +02:00
" m a i l s e r v e r . s v c . s t e f a n j u n k e r . d e , ${ dmzExposedHost } "
" w w w . s t e f a n j u n k e r . d e , ${ dmzExposedHost } "
" h e d g e d o c . w w w . s t e f a n j u n k e r . d e , ${ dmzExposedHost } "
" j i t s i . w w w . s t e f a n j u n k e r . d e , ${ dmzExposedHost } "
" l l d a p . w w w . s t e f a n j u n k e r . d e , ${ dmzExposedHost } "
" f o r g e j o . w w w . s t e f a n j u n k e r . d e , ${ dmzExposedHost } "
2024-04-18 17:24:49 +02:00
] ;
2023-08-10 21:45:49 +02:00
} ;
} ;
2024-06-02 23:27:14 +02:00
system . stateVersion = " 2 4 . 0 5 " ;
2023-08-10 21:45:49 +02:00
2024-06-02 23:27:14 +02:00
# boot.kernelPackages = pkgs.linuxPackages_bpir3_6_6;
2023-08-10 21:45:49 +02:00
environment . systemPackages = [
pkgs . ethtool
2023-12-28 10:38:38 +00:00
pkgs . neovim
2024-05-26 22:32:38 +02:00
pkgs . wireguard-tools
pkgs . tshark
pkgs . tmux
2023-12-28 10:38:38 +00:00
( pkgs . writeShellScriptBin " d b g - i p " ''
echo links :
ip - br - c l
echo
echo addresses :
ip - br - c a
echo
echo vlans :
bridge - c vlan
'' )
( pkgs . writeShellScriptBin " d b g - d n s m a s q " ''
# get the rendered in-use config
pgrep - a dnsmasq | grep - Eo ' [ ^ ] * conf' | xargs cat | grep - Eo ' [ ^ = ] * conf' | xargs cat
'' )
2023-08-10 21:45:49 +02:00
] ;
}