2024-06-19 23:13:24 +02:00
# TODO: don't pull in bluez (or any bluetooth components)
2024-02-08 20:53:22 +01:00
{
repoFlake ,
pkgs ,
lib ,
config ,
nodeFlake ,
nodeName ,
localDomainName ,
system ,
. . .
2024-11-15 10:17:56 +01:00
} :
let
inherit ( nodeFlake . inputs ) nixos-nftables-firewall 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-11-15 10:17:56 +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
builtins . concatStringsSep " . " [
" 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-11-15 10:17:56 +01:00
vlansByName = lib . attrsets . mapAttrs' (
vlanid' : attrs :
lib . attrsets . nameValuePair attrs . name (
attrs
// {
id = lib . strings . toInt vlanid' ;
id' = vlanid' ;
}
2024-01-18 23:35:54 +01:00
)
2024-11-15 10:17:56 +01:00
) vlans ;
2023-12-28 10:38:38 +00:00
2024-11-15 10:17:56 +01:00
getVlanDomain =
{ vlanid }:
if vlanid = = 0 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-11-15 10:17:56 +01:00
mkInterfaceName =
{ vlanid }:
if vlanid = = 0 then bridgeInterfaceName else " ${ bridgeInterfaceName } . ${ toString vlanid } " ;
2024-01-18 23:35:54 +01:00
2024-08-24 00:18:17 +02:00
dmzExposedHost = " s j - s r v 1 " ;
dmzExposedHostDomain = " d m z . i n t e r n a l " ;
dmzExposedHostFQDN = " ${ dmzExposedHost } . ${ dmzExposedHostDomain } " ;
2024-06-02 23:27:14 +02:00
dmzExposedHostIpv4 = mkVlanIpv4HostAddr {
vlanid = vlansByName . dmz . id ;
host = 99 ;
cidr = false ;
} ;
2024-08-24 00:18:17 +02:00
2024-11-15 10:17:56 +01:00
dmzExposedHostMACaddr =
repoFlake . nixosConfigurations . ${ dmzExposedHost } . config . systemd . network . netdevs . " 1 0 - d m z 0 " . netdevConfig . MACAddress ;
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-06-12 22:18:52 +02:00
# sops.secrets.wlan0_saePasswordsFile = {};
2024-11-15 10:17:56 +01:00
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 ;
2024-10-13 20:17:35 +02:00
stopRuleset = " " ;
2024-02-08 20:53:22 +01:00
chains = {
prerouting = {
" e x p o s e H o s t " = {
2024-11-15 10:17:56 +01:00
after = [ " h o o k " ] ;
rules =
let
wanInterfaces = builtins . concatStringsSep " , " config . networking . nftables . firewall . zones . wan . interfaces ;
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 ;
2024-10-13 20:17:35 +02:00
snippets . nnf-common . enable = true ;
# included in the above
# snippets.nnf-conntrack.enable = true;
2024-02-08 20:53:22 +01:00
zones =
{
2024-11-15 10:17:56 +01:00
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-11-15 10:17:56 +01:00
wan . interfaces = [
" w a n "
" l a n 0 "
] ;
vpn . interfaces = [
" w g 0 "
" w g 1 "
" w g 2 "
] ;
2024-02-08 20:53:22 +01:00
}
//
2023-12-28 10:38:38 +00:00
# generate a zone for each vlan
2024-11-15 10:17:56 +01:00
lib . attrsets . mapAttrs ( _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-11-15 10:17:56 +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-11-15 10:17:56 +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-11-15 10:17:56 +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-11-15 10:17:56 +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-11-15 10:17:56 +01:00
vlan-to-fw = {
allowedUDPPortRanges = [
{
from = 53 ;
to = 53 ;
}
{
from = 67 ;
to = 68 ;
}
{
from = 5201 ;
to = 5201 ;
}
2024-02-08 20:53:22 +01:00
] ;
2024-11-15 10:17:56 +01:00
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-11-15 10:17:56 +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-11-15 10:17:56 +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-11-15 10:17:56 +01:00
wan-to-fw = {
from = [ " w a n " ] ;
to = [ " f w " ] ;
allowedTCPPortRanges = [
{
from = 22 ;
to = 22 ;
}
2024-02-08 20:53:22 +01:00
] ;
2024-11-15 10:17:56 +01:00
extraLines = allowIcmpLines ++ [ " d r o p " ] ;
} ;
2024-06-01 10:55:40 +02:00
2024-11-15 10:17:56 +01: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 " ;
} ;
2024-06-01 10:55:40 +02:00
} ;
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-11-15 10:17:56 +01:00
netdevs =
let
router0-ifog_wg0Endpoint = " ${ repoFlake . colmena . router0-ifog . deployment . targetHost } : ${ builtins . toString repoFlake . nixosConfigurations . router0-ifog . config . systemd . network . netdevs . wg0 . wireguardConfig . ListenPort } " ;
router0-ifog_wg1Endpoint = " ${ repoFlake . colmena . router0-ifog . deployment . targetHost } : ${ builtins . toString repoFlake . nixosConfigurations . router0-ifog . config . systemd . network . netdevs . wg1 . wireguardConfig . ListenPort } " ;
router0-hosthatch_wg0Endpoint = " ${ repoFlake . colmena . router0-hosthatch . deployment . targetHost } : ${ builtins . toString repoFlake . nixosConfigurations . router0-hosthatch . config . systemd . network . netdevs . wg0 . wireguardConfig . ListenPort } " ;
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-06-08 21:04:38 +02:00
Endpoint = router0-ifog_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 = " ;
2024-06-08 21:04:38 +02:00
Endpoint = router0-ifog_wg1Endpoint ;
} ;
}
] ;
} ;
wg2 = {
enable = true ;
netdevConfig = {
Name = " w g 2 " ;
Kind = " w i r e g u a r d " ;
} ;
wireguardConfig = {
PrivateKeyFile = builtins . toString config . sops . secrets . wg0-privatekey . path ;
FirewallMark = 102 ;
} ;
wireguardPeers = [
{
wireguardPeerConfig = {
AllowedIPs = [
# 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"
] ;
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 = " ;
Endpoint = router0-hosthatch_wg0Endpoint ;
2024-05-26 22:32:38 +02:00
} ;
}
] ;
} ;
2024-02-08 20:53:22 +01:00
}
# generate the vlan devices. these will be tagged on the main bridge
2024-11-15 10:17:56 +01:00
// builtins . foldl' ( acc : cur : acc // cur ) { } (
2024-02-08 20:53:22 +01:00
builtins . map
2024-11-15 10:17:56 +01:00
(
{ vlanid , vlanid' }:
{
" 2 0 - ${ mkInterfaceName { inherit vlanid ; } } " = {
netdevConfig = {
Kind = " v l a n " ;
Name = " ${ mkInterfaceName { inherit vlanid ; } } " ;
} ;
vlanConfig . Id = vlanid ;
} ;
}
)
(
builtins . map ( vlanid : {
inherit vlanid ;
vlanid' = builtins . toString vlanid ;
} ) vlanRange
)
2024-02-08 20:53:22 +01:00
) ;
2024-11-15 10:17:56 +01:00
networks =
let
commonWanOptions = {
networkConfig = {
# start a DHCP Client for IPv4/6 Addressing/Routing
DHCP = true ;
DNSOverTLS = true ;
DNSSEC = true ;
IPForward = true ;
# accept Router Advertisements for Stateless IPv6 Autoconfiguraton (SLAAC)
IPv6AcceptRA = true ;
IPv6PrivacyExtensions = false ;
DHCPPrefixDelegation = true ;
} ;
dhcpV4Config = {
UseDNS = false ;
UseDomains = false ;
UseHostname = false ;
} ;
dhcpV6Config = {
UseDNS = false ;
UseDomains = false ;
UseHostname = false ;
PrefixDelegationHint = " : : / 5 6 " ;
UseDelegatedPrefix = true ;
WithoutRA = " s o l i c i t " ;
} ;
ipv6AcceptRAConfig = {
UseDNS = false ;
UseDomains = false ;
} ;
2024-10-13 20:17:35 +02:00
2024-11-15 10:17:56 +01:00
# TODO: enable these somehow
# extraConfig = ''
# [IPv6AcceptRA]
# # FIXME: supported in nixos-24.11
# DHCPv6Client=solicit
2024-10-13 20:17:35 +02:00
2024-11-15 10:17:56 +01:00
# # FIXME: not supported at all yet
# UsePREF64=true
# '';
} ;
in
2024-02-08 20:53:22 +01:00
{
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 = [
2024-06-08 21:04:38 +02:00
{
routingPolicyRuleConfig = {
FirewallMark = 100 ;
Priority = 30000 ;
Table = 100 ;
} ;
}
{
routingPolicyRuleConfig = {
FirewallMark = 100 ;
Priority = 30001 ;
Table = 100 ;
Type = " p r o h i b i t " ;
} ;
}
2024-05-26 22:32:38 +02:00
{
routingPolicyRuleConfig = {
FirewallMark = 101 ;
Priority = 30000 ;
Table = 101 ;
} ;
}
{
routingPolicyRuleConfig = {
FirewallMark = 101 ;
Priority = 30001 ;
Table = 101 ;
Type = " p r o h i b i t " ;
} ;
}
{
routingPolicyRuleConfig = {
2024-06-08 21:04:38 +02:00
FirewallMark = 102 ;
2024-05-26 22:32:38 +02:00
Priority = 30000 ;
2024-06-08 21:04:38 +02:00
Table = 102 ;
2024-05-26 22:32:38 +02:00
} ;
}
{
routingPolicyRuleConfig = {
2024-06-08 21:04:38 +02:00
FirewallMark = 102 ;
2024-05-26 22:32:38 +02:00
Priority = 30001 ;
2024-06-08 21:04:38 +02:00
Table = 102 ;
2024-05-26 22:32:38 +02:00
Type = " p r o h i b i t " ;
} ;
}
] ;
} ;
2024-02-08 20:53:22 +01:00
# use lan0 as secondary WAN interface
2024-10-13 20:17:35 +02:00
" 1 0 - l a n 0 - w a n " = lib . attrsets . recursiveUpdate commonWanOptions {
2024-02-08 20:53:22 +01:00
matchConfig . Name = " l a n 0 " ;
2024-10-13 20:17:35 +02:00
# make routing on this interface a dependency for network-online.target
# linkConfig.RequiredForOnline = "routable";
2024-02-08 20:53:22 +01:00
linkConfig . RequiredForOnline = " n o " ;
2024-05-26 22:32:38 +02:00
2024-10-13 20:17:35 +02:00
dhcpV4Config = {
RouteMetric = 2000 ;
} ;
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-10-13 20:17:35 +02:00
" 1 0 - w a n " = lib . attrsets . recursiveUpdate commonWanOptions {
2024-02-08 20:53:22 +01:00
matchConfig . Name = " w a n " ;
# 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 " ;
2024-10-13 20:17:35 +02:00
dhcpV4Config = {
RouteMetric = 1000 ;
} ;
2024-05-26 22:32:38 +02:00
# similar to
# ip route add default via 192.168.0.1 table 100
routes = [
{
routeConfig = {
Gateway = " _ d h c p 4 " ;
Table = 100 ;
} ;
}
2024-06-08 21:04:38 +02:00
{
routeConfig = {
Gateway = " _ d h c p 4 " ;
Table = 102 ;
} ;
}
2024-05-26 22:32:38 +02:00
] ;
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 ;
2024-11-15 10:17:56 +01:00
bridgeConfig = { } ;
2024-02-08 20:53:22 +01:00
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-11-15 10:17:56 +01:00
vlan = builtins . map ( vlanid : ( mkInterfaceName { inherit vlanid ; } ) ) vlanRange ;
2024-02-08 20:53:22 +01:00
} ;
2024-05-25 21:23:43 +02:00
" 5 0 - w g 0 " = {
enable = true ;
matchConfig . Name = " w g 0 " ;
2024-11-15 10:17:56 +01:00
address = [ " 1 0 . 0 . 0 . 1 / 3 1 " ] ;
2024-06-01 10:55:40 +02:00
routes = [
2024-07-26 14:01:59 +02:00
# {
# routeConfig = {
# # test the set uprouting to a specific IP
# Destination = "${repoFlake.colmena.sj-bm-hostkey0.deployment.targetHost}/32";
# MultiPathRoute = "10.0.0.0 1";
# };
# }
2024-06-01 10:55:40 +02:00
] ;
2024-05-26 22:32:38 +02:00
} ;
" 5 0 - w g 1 " = {
enable = true ;
matchConfig . Name = " w g 1 " ;
2024-11-15 10:17:56 +01:00
address = [ " 1 0 . 0 . 0 . 3 / 3 1 " ] ;
2024-06-01 10:55:40 +02:00
routes = [
2024-07-26 14:01:59 +02:00
# {
# routeConfig = {
# Destination = "${repoFlake.colmena.sj-bm-hostkey0.deployment.targetHost}/32";
# MultiPathRoute = "10.0.0.2 1";
# };
# }
2024-06-01 10:55:40 +02:00
] ;
2024-05-25 21:23:43 +02:00
} ;
2024-06-08 21:04:38 +02:00
" 5 0 - w g 2 " = {
enable = true ;
matchConfig . Name = " w g 2 " ;
2024-11-15 10:17:56 +01:00
address = [ " 1 0 . 0 . 1 . 1 / 3 1 " ] ;
2024-06-08 21:04:38 +02:00
routes = [
# TODO: add a testing route here
] ;
} ;
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
2024-11-15 10:17:56 +01:00
// 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.
" 4 1 - ${ mkInterfaceName { inherit vlanid ; } } " = {
matchConfig . Name = " ${ mkInterfaceName { inherit vlanid ; } } " ;
address = [
( mkVlanIpv4HostAddr {
inherit vlanid ;
host = 1 ;
} )
] ;
networkConfig = {
ConfigureWithoutCarrier = true ;
2024-10-13 20:17:35 +02:00
2024-11-15 10:17:56 +01:00
# the client shouldn't be allowed to send us RAs, that would be weird.
IPv6AcceptRA = false ;
2024-10-13 20:17:35 +02:00
2024-11-15 10:17:56 +01:00
DHCPPrefixDelegation = true ;
IPv6SendRA = true ;
} ;
2023-12-28 10:38:38 +00:00
2024-11-15 10:17:56 +01:00
dhcpPrefixDelegationConfig = {
UplinkInterface = " w a n " ;
Assign = true ;
SubnetId = vlanid ;
Announce = true ;
2024-01-18 23:35:54 +01:00
} ;
2024-11-15 10:17:56 +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-11-15 10:17:56 +01:00
bridgeVLANs = [
{
bridgeVLANConfig = {
VLAN = vlanid ;
} ;
}
] ;
} ;
2023-12-28 10:38:38 +00:00
2024-11-15 10:17:56 +01:00
# 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 ;
2024-01-18 23:35:54 +01:00
} ;
2023-12-28 10:38:38 +00:00
2024-11-15 10:17:56 +01:00
linkConfig . RequiredForOnline = " n o " ;
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
)
) ;
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-11-15 10:17:56 +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 " ;
# FIXME: apparently setting this could cause bugs, testing disabling it for a while.
# countryCode = "CH";
channel = 0 ; # 0 would mean Automatic Channel Selection
settings = {
# TODO: this would be faster but x13s on windows can't connect when it's enabled.
# ieee80211n = 1;
# Exclude DFS channels from ACS
# This option can be used to exclude all DFS channels from the ACS channel list
# in cases where the driver supports DFS channels.
acs_exclude_dfs = 0 ;
} ;
2024-06-19 23:13:24 +02:00
2024-11-15 10:17:56 +01:00
# use 'iw phy#1 info' to determine your VHT capabilities
wifi4 = {
enable = true ;
require = false ;
capabilities = [
" H T 2 0 "
" 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 "
" 4 0 - I N T O L E R A N T "
# not supported by BPI-R3 module
# "DELAYED-BA"
# "DSSS_CCK-40"
] ;
} ;
2024-06-19 23:13:24 +02:00
2024-11-15 10:17:56 +01:00
wifi5 = {
enable = false ;
require = false ;
} ;
2024-06-19 23:13:24 +02:00
2024-11-15 10:17:56 +01:00
wifi6 = {
enable = false ;
require = false ;
} ;
2024-02-08 20:53:22 +01:00
2024-11-15 10:17:56 +01:00
networks = {
wlan0 =
let
iface = " w l a n 0 " ;
2024-02-08 20:53:22 +01:00
in
2024-11-15 10:17:56 +01:00
{
ssid = " m l s i a " ;
bssid = mkBssid 0 ;
# enables debug logging
logLevel = 0 ;
authentication . mode = " w p a 2 - s h a 2 5 6 "
# "wpa3-sae-transition"
# "wpa3-sae"
;
authentication . wpaPskFile = config . sops . secrets . " ${ iface } _ w p a P s k F i l e " . path ;
# TODO: unfortunately SAE passwords don't work per VLAN like PSKs do
# authentication.saePasswordsFile = config.sops.secrets."${iface}_saePasswordsFile".path;
# see https://w1.fi/cgit/hostap/plain/hostapd/hostapd.conf for reference
settings = {
# disable syslog because it duplicates stdout
logger_syslog = lib . mkForce 0 ;
# 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;
# 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 ;
# this option currently requires a patch to hostapd
vlan_no_bridge = 1 ;
/*
not used due to the above vlan_no_bridge setting
vlan_tagged_interface = bridgeInterfaceName ;
vlan_naming = 1 ;
vlan_bridge = " b r - ${ 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 " h o s t a p d . v l a n " ( builtins . concatStringsSep " \n " ( generated ++ wildcard ) ) ;
filePath = toString file ;
in
filePath ;
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.
# 0 := disabled; 1 := optional; 2 := required
ieee80211w = 1 ;
# sae_require_mfp = 1;
# sae_groups = "19 20 21";
# [ENABLE-TLSv1.3] = enable TLSv1.3 (experimental - disabled by default)
tls_flags = " [ E N A B L E - T L S v 1 . 3 ] " ;
# TODO: debugging for wifi drops happens below here
# Require IEEE 802.1X authorization
ieee8021x = 0 ;
# Optionally, hostapd can be configured to use an integrated EAP server
# to process EAP authentication locally without need for an external RADIUS
# server. This functionality can be used both as a local authentication server
# for IEEE 802.1X/EAPOL and as a RADIUS server for other devices.
# Use integrated EAP server instead of external RADIUS authentication
# server. This is also needed if hostapd is configured to act as a RADIUS
# authentication server.
eap_server = 0 ;
# Disassociate stations based on excessive transmission failures or other
# indications of connection loss. This depends on the driver capabilities and
# may not be available with all drivers.
disassoc_low_ack = 0 ;
skip_inactivity_poll = 1 ;
# TODO: check if this is required. multicast can be more efficient so it'd be nice to disable this.
multicast_to_unicast = 0 ;
} ;
} ;
2023-08-10 21:45:49 +02:00
} ;
2024-02-08 20:53:22 +01:00
} ;
2024-01-18 23:35:54 +01:00
} ;
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-10-13 20:17:35 +02:00
# v6 config
enable-ra = true ;
2024-11-15 10:17:56 +01:00
dhcp-range =
let
mkDhcpRange =
{ tag , vlanid }:
builtins . concatStringsSep " , " [
tag
( mkVlanIpv4HostAddr {
inherit vlanid ;
host = 100 ;
cidr = false ;
} )
( mkVlanIpv4HostAddr {
inherit vlanid ;
host = 199 ;
cidr = false ;
} )
" 1 2 h "
# "slaac"
# "ra-stateless"
# "ra-names"
] ;
in
builtins . map (
2024-02-08 20:53:22 +01:00
vlanid :
2024-11-15 10:17:56 +01:00
mkDhcpRange {
tag = mkInterfaceName { inherit vlanid ; } ;
inherit vlanid ;
}
) vlanRangeWith0 ;
2023-12-28 10:38:38 +00:00
2024-08-24 00:18:17 +02:00
dhcp-host = builtins . concatStringsSep " , " [
dmzExposedHostMACaddr
dmzExposedHostIpv4
dmzExposedHostFQDN
] ;
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 "
2024-08-22 14:31:32 +02:00
# https://dismail.de/info.html#dns
" 1 1 6 . 2 0 3 . 3 2 . 2 1 7 "
" 2 a 0 1 : 4 f 8 : 1 c 1 b : 4 4 a a : : 1 "
" 1 5 9 . 6 9 . 1 1 4 . 1 5 7 "
" 2 a 0 1 : 4 f 8 : c 1 7 : 7 3 9 a : : 2 "
2023-12-28 10:38:38 +00:00
] ;
2024-02-08 20:53:22 +01:00
domain =
2024-11-15 10:17:56 +01:00
[ " / ${ getVlanDomain { vlanid = 0 ; } } / , l o c a l " ]
++ builtins . map (
vlanid :
" ${ getVlanDomain { inherit vlanid ; } } , ${
mkVlanIpv4HostAddr {
inherit vlanid ;
host = 0 ;
cidr = true ;
}
} , local "
) vlanRangeWith0 ;
2023-12-28 10:38:38 +00:00
# TODO: compare this to using `interface-name`
2024-11-15 10:17:56 +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 ; } )
2024-02-08 20:53:22 +01:00
]
2024-11-15 10:17:56 +01:00
) vlanRangeWith0 ;
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-10-16 18:27:42 +02:00
" k a n i d m . 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
2024-06-19 23:13:24 +02:00
pkgs . vim
2023-12-28 10:38:38 +00:00
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
] ;
}