nixos/tinc: add settings and hostSettings for RFC42-style options
This commit is contained in:
parent
00617447b2
commit
499e366d7b
1 changed files with 224 additions and 13 deletions
|
@ -1,13 +1,156 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.services.tinc;
|
||||
|
||||
in
|
||||
mkValueString = value:
|
||||
if value == true then "yes"
|
||||
else if value == false then "no"
|
||||
else generators.mkValueStringDefault { } value;
|
||||
|
||||
toTincConf = generators.toKeyValue {
|
||||
listsAsDuplicateKeys = true;
|
||||
mkKeyValue = generators.mkKeyValueDefault { inherit mkValueString; } "=";
|
||||
};
|
||||
|
||||
tincConfType = with types;
|
||||
let
|
||||
valueType = oneOf [ bool str int ];
|
||||
in
|
||||
attrsOf (either valueType (listOf valueType));
|
||||
|
||||
addressSubmodule = {
|
||||
options = {
|
||||
address = mkOption {
|
||||
type = types.str;
|
||||
description = "The external IP address or hostname where the host can be reached.";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.nullOr types.port;
|
||||
default = null;
|
||||
description = ''
|
||||
The port where the host can be reached.
|
||||
|
||||
If no port is specified, the default Port is used.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
subnetSubmodule = {
|
||||
options = {
|
||||
address = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
The subnet of this host.
|
||||
|
||||
Subnets can either be single MAC, IPv4 or IPv6 addresses, in which case
|
||||
a subnet consisting of only that single address is assumed, or they can
|
||||
be a IPv4 or IPv6 network address with a prefix length.
|
||||
|
||||
IPv4 subnets are notated like 192.168.1.0/24, IPv6 subnets are notated
|
||||
like fec0:0:0:1::/64. MAC addresses are notated like 0:1a:2b:3c:4d:5e.
|
||||
|
||||
Note that subnets like 192.168.1.1/24 are invalid.
|
||||
'';
|
||||
};
|
||||
|
||||
prefixLength = mkOption {
|
||||
type = with types; nullOr (addCheck int (n: n >= 0 && n <= 128));
|
||||
default = null;
|
||||
description = ''
|
||||
The prefix length of the subnet.
|
||||
|
||||
If null, a subnet consisting of only that single address is assumed.
|
||||
|
||||
This conforms to standard CIDR notation as described in RFC1519.
|
||||
'';
|
||||
};
|
||||
|
||||
weight = mkOption {
|
||||
type = types.ints.unsigned;
|
||||
default = 10;
|
||||
description = ''
|
||||
Indicates the priority over identical Subnets owned by different nodes.
|
||||
|
||||
Lower values indicate higher priority. Packets will be sent to the
|
||||
node with the highest priority, unless that node is not reachable, in
|
||||
which case the node with the next highest priority will be tried, and
|
||||
so on.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hostSubmodule = { config, ... }: {
|
||||
options = {
|
||||
addresses = mkOption {
|
||||
type = types.listOf (types.submodule addressSubmodule);
|
||||
default = [ ];
|
||||
description = ''
|
||||
The external address where the host can be reached. This will set this
|
||||
host's <option>settings.Address</option> option.
|
||||
|
||||
This variable is only required if you want to connect to this host.
|
||||
'';
|
||||
};
|
||||
|
||||
subnets = mkOption {
|
||||
type = types.listOf (types.submodule subnetSubmodule);
|
||||
default = [ ];
|
||||
description = ''
|
||||
The subnets which this tinc daemon will serve. This will set this
|
||||
host's <option>settings.Subnet</option> option.
|
||||
|
||||
Tinc tries to look up which other daemon it should send a packet to by
|
||||
searching the appropriate subnet. If the packet matches a subnet, it
|
||||
will be sent to the daemon who has this subnet in his host
|
||||
configuration file.
|
||||
'';
|
||||
};
|
||||
|
||||
rsaPublicKey = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = ''
|
||||
Legacy RSA public key of the host in PEM format, including start and
|
||||
end markers.
|
||||
|
||||
This will be appended as-is in the host's configuration file.
|
||||
|
||||
The ed25519 public key can be specified using the
|
||||
<option>settings.Ed25519PublicKey</option> option instead.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
default = { };
|
||||
type = types.submodule { freeformType = tincConfType; };
|
||||
description = ''
|
||||
Configuration for this host.
|
||||
|
||||
See <link xlink:href="https://tinc-vpn.org/documentation-1.1/Host-configuration-variables.html"/>
|
||||
for supported values.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config.settings = {
|
||||
Address = mkDefault (map
|
||||
(address: "${address.address} ${toString address.port}")
|
||||
config.addresses);
|
||||
|
||||
Subnet = mkDefault (map
|
||||
(subnet:
|
||||
if subnet.prefixLength == null then "${subnet.address}#${toString subnet.weight}"
|
||||
else "${subnet.address}/${toString subnet.prefixLength}#${toString subnet.weight}")
|
||||
config.subnets);
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
@ -18,7 +161,7 @@ in
|
|||
|
||||
networks = mkOption {
|
||||
default = { };
|
||||
type = with types; attrsOf (submodule {
|
||||
type = with types; attrsOf (submodule ({ config, ... }: {
|
||||
options = {
|
||||
|
||||
extraConfig = mkOption {
|
||||
|
@ -26,6 +169,9 @@ in
|
|||
type = types.lines;
|
||||
description = ''
|
||||
Extra lines to add to the tinc service configuration file.
|
||||
|
||||
Note that using the declarative <option>service.tinc.networks.<name>.settings</option>
|
||||
option is preferred.
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -69,6 +215,40 @@ in
|
|||
hosts = mkOption {
|
||||
default = { };
|
||||
type = types.attrsOf types.lines;
|
||||
description = ''
|
||||
The name of the host in the network as well as the configuration for that host.
|
||||
This name should only contain alphanumerics and underscores.
|
||||
|
||||
Note that using the declarative <option>service.tinc.networks.<name>.hostSettings</option>
|
||||
option is preferred.
|
||||
'';
|
||||
};
|
||||
|
||||
hostSettings = mkOption {
|
||||
default = { };
|
||||
example = literalExample ''
|
||||
{
|
||||
host1 = {
|
||||
addresses = [
|
||||
{ address = "192.168.1.42"; }
|
||||
{ address = "192.168.1.42"; port = 1655; }
|
||||
];
|
||||
subnets = [ { address = "10.0.0.42"; } ];
|
||||
rsaPublicKey = "...";
|
||||
settings = {
|
||||
Ed25519PublicKey = "...";
|
||||
};
|
||||
};
|
||||
host2 = {
|
||||
subnets = [ { address = "10.0.1.0"; prefixLength = 24; weight = 2; } ];
|
||||
rsaPublicKey = "...";
|
||||
settings = {
|
||||
Compression = 10;
|
||||
};
|
||||
};
|
||||
}
|
||||
'';
|
||||
type = types.attrsOf (types.submodule hostSubmodule);
|
||||
description = ''
|
||||
The name of the host in the network as well as the configuration for that host.
|
||||
This name should only contain alphanumerics and underscores.
|
||||
|
@ -79,7 +259,7 @@ in
|
|||
default = "tun";
|
||||
type = types.enum [ "tun" "tap" ];
|
||||
description = ''
|
||||
The type of virtual interface used for the network connection
|
||||
The type of virtual interface used for the network connection.
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -118,8 +298,44 @@ in
|
|||
Note that tinc can't run scripts anymore (such as tinc-down or host-up), unless it is setup to be runnable inside chroot environment.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
default = { };
|
||||
type = types.submodule { freeformType = tincConfType; };
|
||||
example = literalExample ''
|
||||
{
|
||||
Interface = "custom.interface";
|
||||
DirectOnly = true;
|
||||
Mode = "switch";
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Configuration of the Tinc daemon for this network.
|
||||
|
||||
See <link xlink:href="https://tinc-vpn.org/documentation-1.1/Main-configuration-variables.html"/>
|
||||
for supported values.
|
||||
'';
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
config = {
|
||||
hosts = mapAttrs
|
||||
(hostname: host: ''
|
||||
${toTincConf host.settings}
|
||||
${host.rsaPublicKey}
|
||||
'')
|
||||
config.hostSettings;
|
||||
|
||||
settings = {
|
||||
DeviceType = mkDefault config.interfaceType;
|
||||
Name = mkDefault (if config.name == null then "$HOST" else config.name);
|
||||
Ed25519PrivateKeyFile = mkIf (config.ed25519PrivateKeyFile != null) (mkDefault config.ed25519PrivateKeyFile);
|
||||
PrivateKeyFile = mkIf (config.rsaPrivateKeyFile != null) (mkDefault config.rsaPrivateKeyFile);
|
||||
ListenAddress = mkIf (config.listenAddress != null) (mkDefault config.listenAddress);
|
||||
BindToAddress = mkIf (config.bindToAddress != null) (mkDefault config.bindToAddress);
|
||||
};
|
||||
};
|
||||
}));
|
||||
|
||||
description = ''
|
||||
Defines the tinc networks which will be started.
|
||||
|
@ -144,13 +360,7 @@ in
|
|||
"tinc/${network}/tinc.conf" = {
|
||||
mode = "0444";
|
||||
text = ''
|
||||
Name = ${if data.name == null then "$HOST" else data.name}
|
||||
DeviceType = ${data.interfaceType}
|
||||
${optionalString (data.ed25519PrivateKeyFile != null) "Ed25519PrivateKeyFile = ${data.ed25519PrivateKeyFile}"}
|
||||
${optionalString (data.rsaPrivateKeyFile != null) "PrivateKeyFile = ${data.rsaPrivateKeyFile}"}
|
||||
${optionalString (data.listenAddress != null) "ListenAddress = ${data.listenAddress}"}
|
||||
${optionalString (data.bindToAddress != null) "BindToAddress = ${data.bindToAddress}"}
|
||||
Interface = tinc.${network}
|
||||
${toTincConf ({ Interface = "tinc.${network}"; } // data.settings)}
|
||||
${data.extraConfig}
|
||||
'';
|
||||
};
|
||||
|
@ -221,4 +431,5 @@ in
|
|||
|
||||
};
|
||||
|
||||
meta.maintainers = with maintainers; [ minijackson ];
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue