nixos: Working l2mesh with IPsec
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 17m15s
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 17m15s
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
{ lib, pkgs, config, vpns, ... }:
|
||||
{ lib, config, vpns, ... }:
|
||||
let
|
||||
inherit (lib) optionalString mapAttrsToList concatStringsSep filterAttrs mkIf mkMerge;
|
||||
inherit (lib.my) isIPv6;
|
||||
inherit (builtins) any attrValues;
|
||||
inherit (lib) optionalString mapAttrsToList concatStringsSep concatMapStringsSep filterAttrs mkIf mkMerge;
|
||||
inherit (lib.my) isIPv6 mkOpt';
|
||||
|
||||
vxlanPort = 4789;
|
||||
|
||||
@@ -24,38 +25,34 @@ let
|
||||
Local = ownAddr;
|
||||
MacLearning = true;
|
||||
DestinationPort = vxlanPort;
|
||||
PortRange = "${toString vxlanPort}-${toString (vxlanPort + 1)}";
|
||||
Independent = true;
|
||||
};
|
||||
};
|
||||
links."20-l2mesh-${name}" = {
|
||||
matchConfig.Name = mesh.interface;
|
||||
# TODO: ipv6? ipsec?
|
||||
linkConfig.MTUBytes = "1450";
|
||||
};
|
||||
networks."90-l2mesh-${name}" = {
|
||||
matchConfig.Name = mesh.interface;
|
||||
extraConfig = concatStringsSep "\n" (mapAttrsToList (n: peer: ''
|
||||
[BridgeFDB]
|
||||
MACAddress=00:00:00:00:00:00
|
||||
Destination=${peer.addr}
|
||||
'') otherPeers);
|
||||
linkConfig.MTUBytes =
|
||||
let
|
||||
espOverhead =
|
||||
if (!mesh.security.enable) then 0
|
||||
else
|
||||
# SPI + seq + IV + pad / header + ICV
|
||||
4 + 4 + (if mesh.security.encrypt then 8 else 0) + 2 + 16;
|
||||
# UDP + VXLAN + Ethernet + L3 (IPv4/IPv6)
|
||||
overhead = espOverhead + 8 + 8 + 14 + mesh.l3Overhead;
|
||||
in
|
||||
toString (mesh.baseMTU - overhead);
|
||||
|
||||
bridgeFDBs = mapAttrsToList (n: peer: {
|
||||
bridgeFDBConfig = {
|
||||
MACAddress = "00:00:00:00:00:00";
|
||||
Destination = peer.addr;
|
||||
};
|
||||
}) otherPeers;
|
||||
};
|
||||
};
|
||||
|
||||
mkLibreswanConfig = name: mesh: with info mesh; {
|
||||
enable = true;
|
||||
# TODO: finish this...
|
||||
connections."l2mesh-${name}" = ''
|
||||
keyexchange=ike
|
||||
type=transport
|
||||
left=${ownAddr}
|
||||
|
||||
auto=start
|
||||
phase2=esp
|
||||
ikev2=yes
|
||||
'';
|
||||
};
|
||||
|
||||
vxlanAllow = vni: "udp dport ${toString vxlanPort} @th,96,24 ${toString vni} accept";
|
||||
mkFirewallConfig = name: mesh: with info mesh;
|
||||
let
|
||||
netProto = if (isIPv6 ownAddr) then "ip6" else "ip";
|
||||
@@ -63,8 +60,11 @@ let
|
||||
''
|
||||
table inet filter {
|
||||
chain l2mesh-${name} {
|
||||
${optionalString mesh.security.enable "meta l4proto esp accept"}
|
||||
udp dport ${toString vxlanPort} @th,96,24 ${toString mesh.vni} accept
|
||||
${optionalString mesh.security.enable ''
|
||||
udp dport isakmp accept
|
||||
meta l4proto esp accept
|
||||
''}
|
||||
${optionalString (!mesh.security.enable) (vxlanAllow mesh.vni)}
|
||||
return
|
||||
}
|
||||
chain input {
|
||||
@@ -72,12 +72,63 @@ let
|
||||
}
|
||||
}
|
||||
'';
|
||||
|
||||
mkLibreswanConfig = name: mesh: with info mesh; {
|
||||
enable = true;
|
||||
connections = mkMerge (mapAttrsToList
|
||||
(pName: peer: {
|
||||
"l2mesh-${name}-${pName}" = ''
|
||||
keyexchange=ike
|
||||
hostaddrfamily=ipv${if mesh.ipv6 then "6" else "4"}
|
||||
type=transport
|
||||
|
||||
left=${ownAddr}
|
||||
leftprotoport=udp/${toString vxlanPort}
|
||||
right=${peer.addr}
|
||||
rightprotoport=udp/${toString vxlanPort}
|
||||
rightupdown=
|
||||
|
||||
auto=start
|
||||
authby=secret
|
||||
phase2=esp
|
||||
esp=${if mesh.security.encrypt then "aes_gcm256" else "null-sha256"}
|
||||
ikev2=yes
|
||||
modecfgpull=no
|
||||
'';
|
||||
})
|
||||
otherPeers);
|
||||
};
|
||||
genSecrets = name: mesh: with info mesh; concatMapStringsSep "\n" (p: ''
|
||||
echo "${ownAddr} ${p.addr} : PSK \"$(< "${config.my.vpns.l2.pskFiles.${name}}")\"" >> /run/l2mesh.secrets
|
||||
'') (attrValues otherPeers);
|
||||
anySecurity = any (c: c.security.enable) (attrValues memberMeshes);
|
||||
in
|
||||
{
|
||||
options = {
|
||||
my.vpns.l2 = with lib.types; {
|
||||
pskFiles = mkOpt' (attrsOf str) { } "PSK files for secured meshes.";
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
systemd.network = mkMerge (mapAttrsToList mkNetConfig memberMeshes);
|
||||
# TODO: finish this...
|
||||
#services.libreswan = mkMerge (mapAttrsToList mkLibreswanConfig (filterAttrs (_: c: c.security.enable) memberMeshes));
|
||||
|
||||
environment.etc."ipsec.d/l2mesh.secrets" = mkIf anySecurity {
|
||||
source = "/run/l2mesh.secrets";
|
||||
};
|
||||
systemd.services.ipsec = mkIf anySecurity {
|
||||
preStart = ''
|
||||
oldUmask="$(umask)"
|
||||
umask 006
|
||||
|
||||
> /run/l2mesh.secrets
|
||||
${concatStringsSep "\n" (mapAttrsToList genSecrets memberMeshes)}
|
||||
|
||||
umask "$oldUmask"
|
||||
'';
|
||||
};
|
||||
|
||||
services.libreswan = mkMerge (mapAttrsToList mkLibreswanConfig (filterAttrs (_: c: c.security.enable) memberMeshes));
|
||||
my.firewall.extraRules = concatStringsSep "\n" (mapAttrsToList mkFirewallConfig (filterAttrs (_: c: c.firewall) memberMeshes));
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user