services: wireguard: set up DNS server on clients

This makes use of my newly written adblocking DNS service, it does
assume that the server would have both wireguard and DNS enabled.

I would also like to move to using my ip-related library functions,
however it does not support IPv6 and is unlikely to be easily added...
But I am not sure that I *need* IPv6 support for my use-case.

Finally, I find this module a bit too heavy, it could be improved by
having specific 'server' and 'client' roles, instead of implicit roles
depending on whether an external IP exists.
This commit is contained in:
Bruno BELANYI 2021-04-21 19:35:16 +00:00
parent 3696471201
commit f79fcd020b

View file

@ -9,7 +9,14 @@ let
peers = config.my.secrets.wireguard.peers; peers = config.my.secrets.wireguard.peers;
thisPeer = peers."${hostName}"; thisPeer = peers."${hostName}";
otherPeers = lib.filterAttrs (name: _: name != hostName) peers; thisPeerIsServer = thisPeer ? externalIp;
# Only connect to clients from server, and only connect to server from clients
otherPeers =
let
allOthers = lib.filterAttrs (name: _: name != hostName) peers;
shouldConnectToPeer = _: peer: thisPeerIsServer != (peer ? externalIp);
in
lib.filterAttrs shouldConnectToPeer allOthers;
extIface = config.my.networking.externalInterface; extIface = config.my.networking.externalInterface;
in in
@ -31,7 +38,27 @@ in
description = "Port to configure for Wireguard"; description = "Port to configure for Wireguard";
}; };
dns = {
useInternal = my.mkDisableOption ''
Use internal DNS servers from wireguard 'server'
'';
additionalServers = mkOption {
type = with types; listOf str;
default = [
"1.0.0.1"
"1.1.1.1"
];
example = [
"8.8.4.4"
"8.8.8.8"
];
description = "Which DNS servers to use in addition to adblock ones";
};
};
net = { net = {
# FIXME: use new ip library to handle this more cleanly
v4 = { v4 = {
subnet = mkOption { subnet = mkOption {
type = types.str; type = types.str;
@ -46,6 +73,7 @@ in
description = "The CIDR mask to use on internal IPs"; description = "The CIDR mask to use on internal IPs";
}; };
}; };
# FIXME: extend library for IPv6
v6 = { v6 = {
subnet = mkOption { subnet = mkOption {
type = types.str; type = types.str;
@ -76,7 +104,7 @@ in
peers = lib.mapAttrsToList peers = lib.mapAttrsToList
(_: peer: { (_: peer: {
inherit (peer) publicKey; inherit (peer) publicKey;
} // lib.optionalAttrs (thisPeer ? externalIp) { } // lib.optionalAttrs thisPeerIsServer {
# Only forward from server to clients # Only forward from server to clients
allowedIPs = with cfg.net; [ allowedIPs = with cfg.net; [
"${v4.subnet}.${toString peer.clientNum}/32" "${v4.subnet}.${toString peer.clientNum}/32"
@ -85,7 +113,7 @@ in
} // lib.optionalAttrs (peer ? externalIp) { } // lib.optionalAttrs (peer ? externalIp) {
# Known addresses # Known addresses
endpoint = "${peer.externalIp}:${toString cfg.port}"; endpoint = "${peer.externalIp}:${toString cfg.port}";
} // lib.optionalAttrs (!(thisPeer ? externalIp)) { } // lib.optionalAttrs (!thisPeerIsServer) {
# Forward all traffic to server # Forward all traffic to server
allowedIPs = with cfg.net; [ allowedIPs = with cfg.net; [
"0.0.0.0/0" "0.0.0.0/0"
@ -93,10 +121,9 @@ in
]; ];
# Roaming clients need to keep NAT-ing active # Roaming clients need to keep NAT-ing active
persistentKeepalive = 10; persistentKeepalive = 10;
# Use server DNS
}) })
otherPeers; otherPeers;
} // lib.optionalAttrs (thisPeer ? externalIp) { } // lib.optionalAttrs thisPeerIsServer {
# Setup forwarding on server # Setup forwarding on server
postUp = with cfg.net; '' postUp = with cfg.net; ''
${pkgs.iptables}/bin/iptables -A FORWARD -i ${cfg.iface} -j ACCEPT ${pkgs.iptables}/bin/iptables -A FORWARD -i ${cfg.iface} -j ACCEPT
@ -110,10 +137,24 @@ in
${pkgs.iptables}/bin/ip6tables -D FORWARD -i ${cfg.iface} -j ACCEPT ${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 ${pkgs.iptables}/bin/ip6tables -t nat -D POSTROUTING -s ${v6.subnet}::1/${toString v6.mask} -o ${extIface} -j MASQUERADE
''; '';
} // lib.optionalAttrs (!thisPeerIsServer) {
# Use DNS servers hosted on wireguard servers
dns =
let
isServer = _: peer: peer ? externalIp;
toInternalIps = peer: [
"${cfg.net.v4.subnet}.${toString peer.clientNum}"
"${cfg.net.v6.subnet}::${toString peer.clientNum}"
];
servers = lib.filterAttrs isServer otherPeers;
internalIps = lib.flatten
(lib.mapAttrsToList (_: peer: toInternalIps peer) servers);
internalServers = lib.optionals cfg.dns.useInternal internalIps;
in
internalServers ++ cfg.dns.additionalServers;
}; };
nat = lib.optionalAttrs (thisPeer ? externalIp) { nat = lib.optionalAttrs thisPeerIsServer {
enable = true; enable = true;
externalInterface = extIface; externalInterface = extIface;
internalInterfaces = [ cfg.iface ]; internalInterfaces = [ cfg.iface ];