summaryrefslogtreecommitdiffstats
path: root/nixos/modules
diff options
context:
space:
mode:
authorLinus Heckemann <git@sphalerite.org>2020-12-14 21:52:57 +0100
committerGitHub <noreply@github.com>2020-12-14 21:52:57 +0100
commitc40f06022a83d6f286dd2a906e1d5fefcc05dfa1 (patch)
tree0e889334622e07e20dcddb064af47f458e02c0da /nixos/modules
parent7a6203fffc16227e5a0f4477fff050c32ddd27b0 (diff)
parent6cd975094d9ea1bd39a9bd47307008e31fadfebe (diff)
Merge pull request #106073 from minijackson/tinc-rfc42-and-tests
nixos/tinc: rfc42 and tests
Diffstat (limited to 'nixos/modules')
-rw-r--r--nixos/modules/services/networking/tinc.nix237
1 files changed, 224 insertions, 13 deletions
diff --git a/nixos/modules/services/networking/tinc.nix b/nixos/modules/services/networking/tinc.nix
index b4b544a2413d..b6afd83a9abd 100644
--- a/nixos/modules/services/networking/tinc.nix
+++ b/nixos/modules/services/networking/tinc.nix
@@ -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.&lt;name&gt;.settings</option>
+ option is preferred.
'';
};
@@ -72,6 +218,40 @@ in
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.&lt;name&gt;.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}
'';
};
@@ -222,4 +432,5 @@ in
};
+ meta.maintainers = with maintainers; [ minijackson ];
}