118 lines
3.1 KiB
Nix
118 lines
3.1 KiB
Nix
# wireguard upstreams (like njalla and flpk, not like vpn dialup. see vpn-gw)
|
|
{ hostName, config, lib, pkgs, ... }:
|
|
|
|
let
|
|
|
|
tunnels = lib.filterAttrs (_: { wireguard, ... }:
|
|
wireguard != null
|
|
) config.site.hosts.${hostName}.interfaces;
|
|
firstTunnel =
|
|
if builtins.length (builtins.attrNames tunnels) > 0
|
|
then builtins.head (builtins.attrNames tunnels)
|
|
else null;
|
|
enabled = firstTunnel != null;
|
|
|
|
privateKeyFile = ifName:
|
|
"/run/wireguard-keys/${ifName}.key";
|
|
|
|
wireguardMark = 3;
|
|
vpnTable = 100;
|
|
in
|
|
{
|
|
systemd.services = builtins.foldl' (services: ifName: services // {
|
|
"wireguard-key-${ifName}" = {
|
|
description = "Create key file for wireguard interface '${ifName}'";
|
|
requiredBy = [ "systemd-networkd.service" ];
|
|
before = [ "systemd-networkd.service" ];
|
|
serviceConfig.Type = "oneshot";
|
|
script = ''
|
|
#! ${pkgs.runtimeShell} -e
|
|
|
|
F=${privateKeyFile ifName}
|
|
mkdir -p -m 0700 $(dirname $F)
|
|
chown systemd-network:systemd-network $(dirname $F)
|
|
rm -f $F
|
|
cat >$F <<EOF
|
|
${tunnels.${ifName}.wireguard.privateKey}
|
|
EOF
|
|
chmod 0400 $F
|
|
chown systemd-network:systemd-network $F
|
|
'';
|
|
};
|
|
}) {} (builtins.attrNames tunnels);
|
|
|
|
environment.systemPackages = lib.optionals enabled [
|
|
pkgs.wireguard-tools
|
|
];
|
|
|
|
systemd.network.netdevs = builtins.mapAttrs (ifName: { wireguard, ... }: {
|
|
netdevConfig = {
|
|
Name = ifName;
|
|
Kind = "wireguard";
|
|
};
|
|
wireguardConfig = {
|
|
PrivateKeyFile = privateKeyFile ifName;
|
|
FirewallMark = wireguardMark;
|
|
};
|
|
wireguardPeers = [ {
|
|
wireguardPeerConfig = {
|
|
PublicKey = wireguard.publicKey;
|
|
Endpoint = wireguard.endpoint;
|
|
AllowedIPs = "0.0.0.0/0, ::/0";
|
|
};
|
|
} ];
|
|
}) tunnels;
|
|
|
|
systemd.network.networks = lib.mkIf enabled ({
|
|
# Wireguard transported through another routing table
|
|
# (containing upstream by bird ospf)
|
|
core.routingPolicyRules = [ {
|
|
# Marked wireguard packets take the vpn routing table
|
|
routingPolicyRuleConfig = {
|
|
FirewallMark = wireguardMark;
|
|
Table = vpnTable;
|
|
};
|
|
} ];
|
|
} // builtins.mapAttrs (ifName: { wireguard, upstream, ... }: {
|
|
# Wireguard interfaces
|
|
matchConfig.Name = ifName;
|
|
|
|
addresses = map (addr: {
|
|
addressConfig.Address = addr;
|
|
}) wireguard.addresses;
|
|
|
|
# IPv4 default route
|
|
networkConfig.DefaultRouteOnDevice = true;
|
|
routes = [ {
|
|
# IPv6 default route
|
|
routeConfig.Destination = "::/0";
|
|
} ];
|
|
|
|
extraConfig = lib.mkIf (upstream.upBandwidth != null) ''
|
|
[CAKE]
|
|
Parent = root
|
|
# DOCSIS overhead
|
|
OverheadBytes = 18
|
|
Bandwidth = ${toString upstream.upBandwidth}K
|
|
'';
|
|
}) tunnels);
|
|
|
|
networking.nat = lib.mkIf enabled {
|
|
enable = true;
|
|
enableIPv6 = true;
|
|
internalInterfaces = [ "core" ];
|
|
externalInterface = firstTunnel;
|
|
inherit (config.site.hosts.${hostName}) forwardPorts;
|
|
};
|
|
|
|
# Configure rt_table name
|
|
networking.iproute2 = lib.mkIf enabled {
|
|
enable = true;
|
|
rttablesExtraConfig = ''
|
|
${toString vpnTable} vpn
|
|
'';
|
|
};
|
|
|
|
# TODO: firewall
|
|
}
|