|
|
|
@ -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 ]; |
|
|
|
|
} |
|
|
|
|