234 lines
7.4 KiB
Nix
234 lines
7.4 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
options,
|
|
...
|
|
}:
|
|
|
|
with lib;
|
|
with types;
|
|
|
|
let
|
|
cfg = config.qois.meta.network;
|
|
mkStr =
|
|
description:
|
|
(mkOption {
|
|
type = str;
|
|
inherit description;
|
|
});
|
|
mkOptStr =
|
|
description:
|
|
(mkOption {
|
|
type = nullOr str;
|
|
default = null;
|
|
inherit description;
|
|
});
|
|
|
|
mkNetworkIdOpts =
|
|
v:
|
|
assert v == 4 || v == 6;
|
|
submodule {
|
|
options = {
|
|
id = mkOption {
|
|
type = types.str;
|
|
description = ''
|
|
IPv${toString v} ID
|
|
'';
|
|
};
|
|
|
|
prefixLength = mkOption {
|
|
type = types.addCheck types.int (n: n >= 0 && n <= (if v == 4 then 32 else 128));
|
|
description = ''
|
|
Subnet mask of the ip, specified as the number of
|
|
bits in the prefix (<literal>${if v == 4 then "24" else "64"}</literal>).
|
|
'';
|
|
};
|
|
|
|
gateway = mkOption {
|
|
default = null;
|
|
type = nullOr str;
|
|
description = ''
|
|
Upstream Gateway IP
|
|
'';
|
|
};
|
|
|
|
nameservers = mkOption {
|
|
default = null;
|
|
type = nullOr (listOf str);
|
|
description = "Nameserver IP";
|
|
};
|
|
};
|
|
};
|
|
mkFqdn =
|
|
host: domain:
|
|
mkOption {
|
|
type = str;
|
|
default = "${config.qois.meta.hosts.${host}.hostName}.${domain}";
|
|
description = ''
|
|
The fully qualified domain name (FYDN) of this host inside of this specific
|
|
network. Defaults to the host attribute key and net domain.
|
|
'';
|
|
};
|
|
in
|
|
{
|
|
options.qois.meta.network.physical = mkOption {
|
|
description = "Physical network configuration";
|
|
type = attrsOf (
|
|
submodule (
|
|
{ name, ... }:
|
|
let
|
|
networkName = name;
|
|
in
|
|
{
|
|
options = {
|
|
v4 = mkOption { type = (mkNetworkIdOpts 4); };
|
|
v6 = mkOption { type = nullOr (mkNetworkIdOpts 6); };
|
|
domain = mkStr "Network DNS Domain suffix";
|
|
hosts = mkOption {
|
|
type = attrsOf (
|
|
submodule (
|
|
{ name, ... }:
|
|
let
|
|
host = name;
|
|
in
|
|
{
|
|
options = {
|
|
v4 = mkOption { type = submodule { options.ip = mkStr "The V4 host IP address"; }; };
|
|
v6 = mkOption {
|
|
default = null;
|
|
type = nullOr (submodule {
|
|
options.ip = mkStr "The V6 host IP address";
|
|
});
|
|
};
|
|
fqdn = mkFqdn host cfg.physical.${networkName}.domain;
|
|
};
|
|
}
|
|
)
|
|
);
|
|
};
|
|
};
|
|
}
|
|
)
|
|
);
|
|
default = { };
|
|
};
|
|
options.qois.meta.network.virtual = mkOption {
|
|
description = "Virtual network configuration";
|
|
type = types.attrsOf (
|
|
types.submodule (
|
|
{ name, ... }:
|
|
let
|
|
networkName = name;
|
|
in
|
|
{
|
|
options = {
|
|
v4 = mkOption { type = (mkNetworkIdOpts 4); };
|
|
v6 = mkOption {
|
|
default = null;
|
|
type = nullOr (mkNetworkIdOpts 6);
|
|
};
|
|
domain = mkStr "Network DNS Domain suffix";
|
|
hosts = mkOption {
|
|
type = attrsOf (
|
|
submodule (
|
|
{ name, ... }:
|
|
let
|
|
host = name;
|
|
in
|
|
{
|
|
options = {
|
|
v4 = mkOption { type = submodule { options.ip = mkStr "The V4 host IP address"; }; };
|
|
v6 = mkOption {
|
|
default = null;
|
|
type = nullOr (submodule {
|
|
options.ip = mkStr "The V6 host IP address";
|
|
});
|
|
};
|
|
|
|
# Taken from https://github.com/NixOS/nixpkgs/blob/nixos-21.11/nixos/modules/services/networking/wireguard.nix:
|
|
publicKey = mkOption {
|
|
example = "xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=";
|
|
type = str;
|
|
description = "The base64 public key of the peer.";
|
|
};
|
|
persistentKeepalive = mkOption {
|
|
default = null;
|
|
type = nullOr int;
|
|
example = 25;
|
|
description = ''
|
|
This is optional and is by default off, because most
|
|
users will not need it. It represents, in seconds, between 1 and 65535
|
|
inclusive, how often to send an authenticated empty packet to the peer,
|
|
for the purpose of keeping a stateful firewall or NAT mapping valid
|
|
persistently. For example, if the interface very rarely sends traffic,
|
|
but it might at anytime receive traffic from a peer, and it is behind
|
|
NAT, the interface might benefit from having a persistent keepalive
|
|
interval of 25 seconds; however, most users will not need this.'';
|
|
};
|
|
|
|
# Endpoint Configuration:
|
|
endpoint = mkOption {
|
|
description = ''
|
|
FQDN and port of this vpn-endpoint. This option indicates this host is a VPN
|
|
server.
|
|
'';
|
|
default = null;
|
|
type = nullOr (submodule {
|
|
options = {
|
|
fqdn = mkFqdn host cfg.virtual.${networkName}.domain;
|
|
port = mkOption {
|
|
type = types.addCheck types.int (n: n > 0 && n < 65536);
|
|
description = ''
|
|
The port on which the wireguard endpoint receives packages.
|
|
'';
|
|
};
|
|
};
|
|
});
|
|
};
|
|
};
|
|
}
|
|
)
|
|
);
|
|
};
|
|
};
|
|
}
|
|
)
|
|
);
|
|
default = { };
|
|
};
|
|
config = {
|
|
programs.ssh.knownHosts =
|
|
let
|
|
# hostname -> single network cfg attr -> ["known host's names"]
|
|
getHostNamesFromNetwork =
|
|
hostname: network:
|
|
if network.hosts ? ${hostname} && network.hosts.${hostname} != null then
|
|
let
|
|
hostCfg = network.hosts.${hostname};
|
|
in
|
|
[
|
|
"${hostname}.${network.domain}"
|
|
hostCfg.v4.ip
|
|
]
|
|
++ (if hostCfg.v6 != null then [ hostCfg.v6.ip ] else [ ])
|
|
else
|
|
[ ];
|
|
|
|
# hostname -> attr of network defs -> ["known host's names"]
|
|
getHostNamesForNetworks =
|
|
hostname: networks: lib.flatten (map (getHostNamesFromNetwork hostname) (lib.attrValues networks));
|
|
|
|
# hostname -> ["known host's names"]
|
|
getHostNames =
|
|
hostname:
|
|
(getHostNamesForNetworks hostname cfg.virtual) ++ (getHostNamesForNetworks hostname cfg.physical);
|
|
|
|
hostsWithPublicKey = lib.filterAttrs (
|
|
hostName: hostConfig: hostConfig.sshKey != null
|
|
) config.qois.meta.hosts;
|
|
in
|
|
mapAttrs (name: hostCfg: { extraHostNames = getHostNames name; }) hostsWithPublicKey;
|
|
|
|
};
|
|
}
|