services: wireguard: clean up logic

This module has a complicated logic, and I found the code quite ugly.
making use of `mkMerge` makes it easier to read and think through.
This commit is contained in:
Bruno BELANYI 2021-04-23 20:31:10 +00:00
parent 84b61b25b3
commit 26eac86de0

View file

@ -96,80 +96,100 @@ in
}; };
}; };
config.networking = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable (lib.mkMerge [
wg-quick.interfaces."${cfg.iface}" = { {
listenPort = cfg.port; networking.wg-quick.interfaces."${cfg.iface}" = {
address = with cfg.net; with lib; [ listenPort = cfg.port;
"${v4.subnet}.${toString thisPeer.clientNum}/${toString v4.mask}" address = with cfg.net; with lib; [
"${v6.subnet}::${toString thisPeer.clientNum}/${toHexString v6.mask}" "${v4.subnet}.${toString thisPeer.clientNum}/${toString v4.mask}"
]; "${v6.subnet}::${toString thisPeer.clientNum}/${toHexString v6.mask}"
# Insecure, I don't care ];
privateKey = thisPeer.privateKey; # Insecure, I don't care
privateKey = thisPeer.privateKey;
peers = lib.mapAttrsToList peers =
(_: peer: { let
inherit (peer) publicKey; mkPeer = _: peer: lib.mkMerge [
} // lib.optionalAttrs thisPeerIsServer { {
# Only forward from server to clients inherit (peer) publicKey;
allowedIPs = with cfg.net; [ }
"${v4.subnet}.${toString peer.clientNum}/32"
"${v6.subnet}::${toString peer.clientNum}/128" (lib.optionalAttrs thisPeerIsServer {
]; # Only forward from server to clients
} // lib.optionalAttrs (peer ? externalIp) { allowedIPs = with cfg.net; [
# Known addresses "${v4.subnet}.${toString peer.clientNum}/32"
endpoint = "${peer.externalIp}:${toString cfg.port}"; "${v6.subnet}::${toString peer.clientNum}/128"
} // lib.optionalAttrs (!thisPeerIsServer) { ];
# Forward all traffic to server })
allowedIPs = with cfg.net; [
"0.0.0.0/0" (lib.optionalAttrs (!thisPeerIsServer) {
"::/0" # Forward all traffic through wireguard to server
]; allowedIPs = with cfg.net; [
# Roaming clients need to keep NAT-ing active "0.0.0.0/0"
persistentKeepalive = 10; "::/0"
}) ];
otherPeers; # Roaming clients need to keep NAT-ing active
} // lib.optionalAttrs thisPeerIsServer { persistentKeepalive = 10;
# Setup forwarding on server # We know that `peer` is a server, set up the endpoint
postUp = with cfg.net; '' endpoint = "${peer.externalIp}:${toString cfg.port}";
${pkgs.iptables}/bin/iptables -A FORWARD -i ${cfg.iface} -j ACCEPT })
${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s ${v4.subnet}.1/${toString v4.mask} -o ${extIface} -j MASQUERADE ];
${pkgs.iptables}/bin/ip6tables -A FORWARD -i ${cfg.iface} -j ACCEPT in
${pkgs.iptables}/bin/ip6tables -t nat -A POSTROUTING -s ${v6.subnet}::1/${toString v6.mask} -o ${extIface} -j MASQUERADE lib.mapAttrsToList mkPeer otherPeers;
''; };
preDown = with cfg.net; '' }
${pkgs.iptables}/bin/iptables -D FORWARD -i ${cfg.iface} -j ACCEPT
${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s ${v4.subnet}.1/${toString v4.mask} -o ${extIface} -j MASQUERADE # Set up clients to use configured DNS servers
${pkgs.iptables}/bin/ip6tables -D FORWARD -i ${cfg.iface} -j ACCEPT (lib.mkIf (!thisPeerIsServer) {
${pkgs.iptables}/bin/ip6tables -t nat -D POSTROUTING -s ${v6.subnet}::1/${toString v6.mask} -o ${extIface} -j MASQUERADE networking.wg-quick.interfaces."${cfg.iface}".dns =
'';
} // lib.optionalAttrs (!thisPeerIsServer) {
# Use DNS servers hosted on wireguard servers
dns =
let let
isServer = _: peer: peer ? externalIp;
toInternalIps = peer: [ toInternalIps = peer: [
"${cfg.net.v4.subnet}.${toString peer.clientNum}" "${cfg.net.v4.subnet}.${toString peer.clientNum}"
"${cfg.net.v6.subnet}::${toString peer.clientNum}" "${cfg.net.v6.subnet}::${toString peer.clientNum}"
]; ];
servers = lib.filterAttrs isServer otherPeers; # We know that `otherPeers` is an attribute set of servers
internalIps = lib.flatten internalIps = lib.flatten
(lib.mapAttrsToList (_: peer: toInternalIps peer) servers); (lib.mapAttrsToList (_: peer: toInternalIps peer) otherPeers);
internalServers = lib.optionals cfg.dns.useInternal internalIps; internalServers = lib.optionals cfg.dns.useInternal internalIps;
in in
internalServers ++ cfg.dns.additionalServers; internalServers ++ cfg.dns.additionalServers;
}; })
nat = lib.optionalAttrs thisPeerIsServer { # Expose port
enable = true; {
externalInterface = extIface; networking.firewall.allowedUDPPorts = [ cfg.port ];
internalInterfaces = [ cfg.iface ]; }
};
firewall.allowedUDPPorts = [ cfg.port ]; # Allow NATing wireguard traffic on server
}; (lib.mkIf thisPeerIsServer {
networking.nat = {
enable = true;
externalInterface = extIface;
internalInterfaces = [ cfg.iface ];
};
})
# Do not start the service by making it not wanted by any unit # Set up forwarding to WAN
config.systemd.services.wg-quick-wg = lib.mkIf (!cfg.startAtBoot) { (lib.mkIf thisPeerIsServer {
wantedBy = lib.mkForce [ ]; networking.wg-quick.interfaces."${cfg.iface}" = {
}; postUp = with cfg.net; ''
${pkgs.iptables}/bin/iptables -A FORWARD -i ${cfg.iface} -j ACCEPT
${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s ${v4.subnet}.1/${toString v4.mask} -o ${extIface} -j MASQUERADE
${pkgs.iptables}/bin/ip6tables -A FORWARD -i ${cfg.iface} -j ACCEPT
${pkgs.iptables}/bin/ip6tables -t nat -A POSTROUTING -s ${v6.subnet}::1/${toString v6.mask} -o ${extIface} -j MASQUERADE
'';
preDown = with cfg.net; ''
${pkgs.iptables}/bin/iptables -D FORWARD -i ${cfg.iface} -j ACCEPT
${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s ${v4.subnet}.1/${toString v4.mask} -o ${extIface} -j MASQUERADE
${pkgs.iptables}/bin/ip6tables -D FORWARD -i ${cfg.iface} -j ACCEPT
${pkgs.iptables}/bin/ip6tables -t nat -D POSTROUTING -s ${v6.subnet}::1/${toString v6.mask} -o ${extIface} -j MASQUERADE
'';
};
})
# When not needed at boot, ensure that there are no reverse dependencies
(lib.mkIf (!cfg.startAtBoot) {
systemd.services."wg-quick-${cfg.iface}".wantedBy = lib.mkForce [ ];
})
]);
} }