router0-dmz0: dnssec, local names, code cleanup

This commit is contained in:
steveej 2023-12-28 11:22:39 +01:00
parent 5299051f86
commit ecfe589b60
3 changed files with 114 additions and 43 deletions

View file

@ -5,6 +5,7 @@
config, config,
nodeFlake, nodeFlake,
nodeName, nodeName,
localDomainName,
system, system,
... ...
}: let }: let
@ -32,7 +33,7 @@
[ "192" "168" (toString (vlanid + offset)) "${toString host}${lib.strings.optionalString cidr "/24"}" ]; [ "192" "168" (toString (vlanid + offset)) "${toString host}${lib.strings.optionalString cidr "/24"}" ];
defaultVlan = { defaultVlan = {
name = "internal"; name = "${localDomainName}";
packet_priority = 0; packet_priority = 0;
}; };
@ -55,6 +56,13 @@
"15".name = "iot2"; "15".name = "iot2";
"15".packet_priority = -10; "15".packet_priority = -10;
}; };
vlansByName = lib.attrsets.mapAttrs' (vlanid': attrs:
lib.attrsets.nameValuePair
attrs.name
(attrs // { id = lib.strings.toInt vlanid'; id' = vlanid';})
) vlans;
getVlanDomain = { vlanid }: getVlanDomain = { vlanid }:
if vlanid == 0 if vlanid == 0
then then
@ -62,6 +70,13 @@
else else
vlans."${toString vlanid}".name + "." + defaultVlan.name vlans."${toString vlanid}".name + "." + defaultVlan.name
; ;
bridgeInterfaceName = "br-lan";
mkInterfaceName = { vlanid }:
if vlanid == 0
then bridgeInterfaceName
else "${bridgeInterfaceName}.${toString vlanid}"
;
in { in {
imports = [ imports = [
repoFlake.inputs.sops-nix.nixosModules.sops repoFlake.inputs.sops-nix.nixosModules.sops
@ -164,13 +179,16 @@ in {
firewall = { firewall = {
enable = true; enable = true;
zones = { zones = {
lan.interfaces = [ "br-lan" ]; lan.interfaces = [ (mkInterfaceName {vlanid = 0;}) ];
vlan.interfaces = builtins.map (vlanid: "br-lan.${toString vlanid}") vlanRange; vlan.interfaces = builtins.map (vlanid: (mkInterfaceName {inherit vlanid;})) vlanRange;
# lan.ipv4Addresses = ["192.168.0.0/16"]; # lan.ipv4Addresses = ["192.168.0.0/16"];
wan.interfaces = ["wan" "lan0"]; wan.interfaces = ["wan" "lan0"];
} // } //
# TODO: generate a zone for each vlan # generate a zone for each vlan
{} lib.attrsets.mapAttrs (key: value: {
interfaces = [ (mkInterfaceName { vlanid = value.id; }) ];
})
vlansByName
; ;
rules = let rules = let
ipv6IcmpTypes = [ ipv6IcmpTypes = [
@ -194,6 +212,12 @@ in {
verdict = "accept"; verdict = "accept";
}; };
office-to-dmz = {
from = ["office"];
to = ["dmz"];
verdict = "accept";
};
lan-to-fw = { lan-to-fw = {
from = ["lan"]; from = ["lan"];
to = ["fw" "lan"]; to = ["fw" "lan"];
@ -258,10 +282,10 @@ in {
wait-online.anyInterface = true; wait-online.anyInterface = true;
netdevs = { netdevs = {
# Create the bridge interface # Create the bridge interface
"20-br-lan" = { "20-${bridgeInterfaceName}" = {
netdevConfig = { netdevConfig = {
Kind = "bridge"; Kind = "bridge";
Name = "br-lan"; Name = bridgeInterfaceName;
}; };
extraConfig = '' extraConfig = ''
@ -280,10 +304,10 @@ in {
{} {}
(builtins.map (builtins.map
({ vlanid, vlanid' }: { ({ vlanid, vlanid' }: {
"20-br-lan.${vlanid'}" = { "20-${mkInterfaceName { inherit vlanid; }}" = {
netdevConfig = { netdevConfig = {
Kind = "vlan"; Kind = "vlan";
Name = "br-lan.${vlanid'}"; Name = "${mkInterfaceName { inherit vlanid; }}";
}; };
vlanConfig.Id = vlanid; vlanConfig.Id = vlanid;
}; };
@ -331,24 +355,45 @@ in {
"30-lan1" = { "30-lan1" = {
matchConfig.Name = "lan1"; matchConfig.Name = "lan1";
networkConfig = { networkConfig = {
Bridge = "br-lan"; Bridge = bridgeInterfaceName;
ConfigureWithoutCarrier = true; ConfigureWithoutCarrier = true;
}; };
linkConfig.RequiredForOnline = "enslaved"; linkConfig.RequiredForOnline = "enslaved";
bridgeVLANs = [
{
bridgeVLANConfig = {
VLAN = vlansByName.dmz.id;
PVID = vlansByName.dmz.id;
EgressUntagged = vlansByName.dmz.id;
}; };
}
];
};
"30-lan2" = { "30-lan2" = {
matchConfig.Name = "lan2"; matchConfig.Name = "lan2";
networkConfig = { networkConfig = {
Bridge = "br-lan"; Bridge = bridgeInterfaceName;
ConfigureWithoutCarrier = true; ConfigureWithoutCarrier = true;
}; };
linkConfig.RequiredForOnline = "enslaved"; linkConfig.RequiredForOnline = "enslaved";
bridgeVLANs = [
{
bridgeVLANConfig = {
VLAN = vlansByName.office.id;
PVID = vlansByName.office.id;
EgressUntagged = vlansByName.office.id;
};
}
];
}; };
"30-lan3" = { "30-lan3" = {
matchConfig.Name = "lan3"; matchConfig.Name = "lan3";
networkConfig = { networkConfig = {
Bridge = "br-lan"; Bridge = bridgeInterfaceName;
ConfigureWithoutCarrier = true; ConfigureWithoutCarrier = true;
}; };
linkConfig.RequiredForOnline = "enslaved"; linkConfig.RequiredForOnline = "enslaved";
@ -360,11 +405,10 @@ in {
}; };
} }
]; ];
}; };
# Configure the bridge for its desired function # Configure the bridge for its desired function
"40-br-lan" = { "40-${bridgeInterfaceName}" = {
matchConfig.Name = "br-lan"; matchConfig.Name = bridgeInterfaceName;
bridgeConfig = {}; bridgeConfig = {};
address = [ address = [
(mkVlanIpv4HostAddr { vlanid = 0; host = 1;}) (mkVlanIpv4HostAddr { vlanid = 0; host = 1;})
@ -385,7 +429,7 @@ in {
]; ];
vlan = (builtins.map vlan = (builtins.map
(vlanid: "br-lan.${builtins.toString vlanid}") (vlanid: (mkInterfaceName { inherit vlanid; }))
vlanRange vlanRange
); );
}; };
@ -404,8 +448,8 @@ in {
# configure the tagged vlan device with an address and vlan filtering. # configure the tagged vlan device with an address and vlan filtering.
# dnsmasq is configured to serve the respective /24 range on each tagged device. # 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. # this device only receives traffic for the given vlanid and sends tagged traffic to the bridge.
"41-br-lan.${vlanid'}" = { "41-${mkInterfaceName { inherit vlanid; }}" = {
matchConfig.Name = "br-lan.${vlanid'}"; matchConfig.Name = "${mkInterfaceName { inherit vlanid; }}";
address = [ address = [
(mkVlanIpv4HostAddr { inherit vlanid; host = 1; }) (mkVlanIpv4HostAddr { inherit vlanid; host = 1; })
]; ];
@ -432,7 +476,7 @@ in {
"41-wlan0.${vlanid'}" = { "41-wlan0.${vlanid'}" = {
matchConfig.Name = "wlan0.${vlanid'}"; matchConfig.Name = "wlan0.${vlanid'}";
networkConfig = { networkConfig = {
Bridge = "br-lan"; Bridge = bridgeInterfaceName;
ConfigureWithoutCarrier = true; ConfigureWithoutCarrier = true;
}; };
@ -449,8 +493,8 @@ in {
]; ];
}; };
"50-br-lan.${vlanid'}" = { "50-${mkInterfaceName { inherit vlanid; }}" = {
matchConfig.Name = "br-lan.${vlanid'}"; matchConfig.Name = "${mkInterfaceName { inherit vlanid; }}";
address = [ address = [
(mkVlanIpv4HostAddr { inherit vlanid; host = 1; }) (mkVlanIpv4HostAddr { inherit vlanid; host = 1; })
]; ];
@ -498,15 +542,17 @@ in {
authentication.wpaPskFile = config.sops.secrets."${iface}_wpaPskFile".path; authentication.wpaPskFile = config.sops.secrets."${iface}_wpaPskFile".path;
authentication.saePasswordsFile = config.sops.secrets."${iface}_saePasswordsFile".path; authentication.saePasswordsFile = config.sops.secrets."${iface}_saePasswordsFile".path;
# see https://w1.fi/cgit/hostap/plain/hostapd/hostapd.conf for reference
settings = { settings = {
# bridge = "br-lan"; # bridge = bridgeInterfaceName;
# wpa_psk_file = config.sops.secrets.wlan0_wpaPskFile.path; # wpa_psk_file = config.sops.secrets.wlan0_wpaPskFile.path;
# not yet supported on hostapd 2.10 # not yet supported on hostapd 2.10
# sae_password_file = config.sops.secrets.wlan0_saePasswordsFile.path; # sae_password_file = config.sops.secrets.wlan0_saePasswordsFile.path;
logger_stdout_level= lib.mkForce 0; # enables debug logging
logger_syslog_level= lib.mkForce 0; # logger_stdout_level= lib.mkForce 0;
# logger_syslog_level= lib.mkForce 0;
# resources on vlan tagging # resources on vlan tagging
# https://wireless.wiki.kernel.org/en/users/Documentation/hostapd#dynamic_vlan_tagging # https://wireless.wiki.kernel.org/en/users/Documentation/hostapd#dynamic_vlan_tagging
@ -517,7 +563,7 @@ in {
vlan_no_bridge = 1; vlan_no_bridge = 1;
/* not used due to the above vlan_no_bridge setting /* not used due to the above vlan_no_bridge setting
vlan_tagged_interface = "br-lan"; vlan_tagged_interface = bridgeInterfaceName;
vlan_naming = 1; vlan_naming = 1;
vlan_bridge = "br-${iface}."; vlan_bridge = "br-${iface}.";
*/ */
@ -568,7 +614,7 @@ in {
# bssid = mkBssid 1; # bssid = mkBssid 1;
# settings = { # settings = {
# bridge = "br-lan"; # bridge = bridgeInterfaceName;
# }; # };
# }; # };
@ -581,7 +627,7 @@ in {
# managementFrameProtection = "optional"; # managementFrameProtection = "optional";
# bssid = "e6:02:43:07:00:00"; # bssid = "e6:02:43:07:00:00";
# settings = { # settings = {
# bridge = "br-lan"; # bridge = bridgeInterfaceName;
# wpa = lib.mkForce 2; # wpa = lib.mkForce 2;
# wpa_key_mgmt = "WPA-PSK"; # wpa_key_mgmt = "WPA-PSK";
# wpa_pairwise = "CCMP"; # wpa_pairwise = "CCMP";
@ -673,7 +719,7 @@ in {
# }; # };
# bssid = "36:b9:02:21:08:a2"; # bssid = "36:b9:02:21:08:a2";
# settings = { # settings = {
# bridge = "br-lan"; # bridge = bridgeInterfaceName;
# }; # };
# }; # };
# }; # };
@ -683,15 +729,24 @@ in {
services.resolved.enable = false; services.resolved.enable = false;
services.dnsmasq = let services.dnsmasq = {
mkIfName = { vlanid }: if vlanid == 0 then "br-lan" else "br-lan.${toString vlanid}";
in {
enable = true; enable = true;
settings = { settings = {
# sensible behaviours
domain-needed = true; domain-needed = true;
bogus-priv = true; bogus-priv = true;
no-resolv = true; no-resolv = true;
localise-queries = true;
proxy-dnssec = true;
conntrack = true;
log-debug = true;
log-queries = true;
# disable negative caching
no-negcache = true;
local-ttl = 0;
dhcp-ttl = 0;
dhcp-range = let dhcp-range = let
mkDhcpRange = { tag, vlanid }: builtins.concatStringsSep "," [ mkDhcpRange = { tag, vlanid }: builtins.concatStringsSep "," [
@ -703,12 +758,12 @@ in {
in in
builtins.map builtins.map
(vlanid: (vlanid:
mkDhcpRange { tag = mkIfName {inherit vlanid;}; inherit vlanid; } mkDhcpRange { tag = mkInterfaceName {inherit vlanid;}; inherit vlanid; }
) )
vlanRangeWith0 vlanRangeWith0
; ;
# interface = "br-lan"; # interface = bridgeInterfaceName;
# bind-interfaces = true; # bind-interfaces = true;
# dhcp-host = "192.168.10.1"; # dhcp-host = "192.168.10.1";
@ -720,12 +775,27 @@ in {
# don't use /etc/hosts as this would advertise ${nodeName} as localhost # don't use /etc/hosts as this would advertise ${nodeName} as localhost
no-hosts = true; no-hosts = true;
# address = "/${nodeName}.lan/${fwLanHostAddr}"; # address = "/${nodeName}.lan/${fwLanHostAddr}";
server = [ server = [
# upstream DNS servers # upstream DNS servers
"9.9.9.9" "8.8.8.8" "1.1.1.1"
# https://dnsforge.de/
"176.9.93.198"
"176.9.1.117"
"2a01:4f8:151:34aa::198"
"2a01:4f8:141:316d::117"
# cloudflare and google
# "9.9.9.9" "8.8.8.8" "1.1.1.1"
];
domain = [
"/${getVlanDomain {vlanid = 0;}}/,local"
] ++ builtins.map ] ++ builtins.map
(vlanid: "/${getVlanDomain {inherit vlanid;}}/") (vlanid:
"${getVlanDomain {inherit vlanid;}},${mkVlanIpv4HostAddr { inherit vlanid; host = 0; cidr = true; }},local"
)
vlanRangeWith0 vlanRangeWith0
; ;
@ -734,18 +804,17 @@ in {
] ++ builtins.map ] ++ builtins.map
(vlanid: (vlanid:
builtins.concatStringsSep "," [ builtins.concatStringsSep "," [
"${nodeName}.${getVlanDomain{inherit vlanid;}}" "0.0.0.1" (mkIfName {inherit vlanid;}) # "${getVlanDomain{inherit vlanid;}}" "0.0.0.1" (mkInterfaceName {inherit vlanid;})
"${nodeName}.${getVlanDomain{inherit vlanid;}}" "0.0.0.1" (mkInterfaceName {inherit vlanid;})
] ]
) )
vlanRangeWith0 vlanRangeWith0
; ;
dhcp-option-force = builtins.map dhcp-option-force = builtins.map
(vlanid: "${mkIfName {inherit vlanid;}},option:domain-search,${getVlanDomain{inherit vlanid;}}") (vlanid: "${mkInterfaceName {inherit vlanid;}},option:domain-search,${getVlanDomain{inherit vlanid;}}")
vlanRangeWith0 vlanRangeWith0
; ;
localise-queries = true;
}; };
}; };

View file

@ -3,6 +3,7 @@
nodeName, nodeName,
repoFlake, repoFlake,
nodeFlake, nodeFlake,
localDomainName ? "internal",
... ...
}: { }: {
meta.nodeSpecialArgs.${nodeName} = { meta.nodeSpecialArgs.${nodeName} = {
@ -14,6 +15,8 @@
(nodeFlake.inputs.bpir3.packages.${system}) (nodeFlake.inputs.bpir3.packages.${system})
armTrustedFirmwareMT7986 armTrustedFirmwareMT7986
; ;
inherit localDomainName;
}; };
meta.nodeNixpkgs.${nodeName} = meta.nodeNixpkgs.${nodeName} =
@ -23,7 +26,7 @@
}; };
${nodeName} = { ${nodeName} = {
deployment.targetHost = "router0.dmz0.noosphere.life"; deployment.targetHost = "${nodeName}.${localDomainName}";
deployment.replaceUnknownProfiles = true; deployment.replaceUnknownProfiles = true;
# nixpkgs.pkgs = nodeFlake.inputs.nixpkgs.legacyPackages.${system}; # nixpkgs.pkgs = nodeFlake.inputs.nixpkgs.legacyPackages.${system};

View file

@ -60,7 +60,6 @@
nixpkgs.lib.attrsets.recursiveUpdate nixpkgs.lib.attrsets.recursiveUpdate
attrs attrs
{ {
# TODO: it would be nice if this were the same as meta.nodeSpecialArgs.${nodeName} as in the default.nix
specialArgs = (import ./default.nix { specialArgs = (import ./default.nix {
system = nativeSystem; system = nativeSystem;
inherit nodeName; inherit nodeName;