···11{ config, lib, pkgs, ... }:
2233with lib;
44+let
55+ cfg = config.services.tinc;
4655-let
77+ mkValueString = value:
88+ if value == true then "yes"
99+ else if value == false then "no"
1010+ else generators.mkValueStringDefault { } value;
1111+1212+ toTincConf = generators.toKeyValue {
1313+ listsAsDuplicateKeys = true;
1414+ mkKeyValue = generators.mkKeyValueDefault { inherit mkValueString; } "=";
1515+ };
1616+1717+ tincConfType = with types;
1818+ let
1919+ valueType = oneOf [ bool str int ];
2020+ in
2121+ attrsOf (either valueType (listOf valueType));
2222+2323+ addressSubmodule = {
2424+ options = {
2525+ address = mkOption {
2626+ type = types.str;
2727+ description = "The external IP address or hostname where the host can be reached.";
2828+ };
2929+3030+ port = mkOption {
3131+ type = types.nullOr types.port;
3232+ default = null;
3333+ description = ''
3434+ The port where the host can be reached.
3535+3636+ If no port is specified, the default Port is used.
3737+ '';
3838+ };
3939+ };
4040+ };
4141+4242+ subnetSubmodule = {
4343+ options = {
4444+ address = mkOption {
4545+ type = types.str;
4646+ description = ''
4747+ The subnet of this host.
4848+4949+ Subnets can either be single MAC, IPv4 or IPv6 addresses, in which case
5050+ a subnet consisting of only that single address is assumed, or they can
5151+ be a IPv4 or IPv6 network address with a prefix length.
5252+5353+ IPv4 subnets are notated like 192.168.1.0/24, IPv6 subnets are notated
5454+ like fec0:0:0:1::/64. MAC addresses are notated like 0:1a:2b:3c:4d:5e.
5555+5656+ Note that subnets like 192.168.1.1/24 are invalid.
5757+ '';
5858+ };
5959+6060+ prefixLength = mkOption {
6161+ type = with types; nullOr (addCheck int (n: n >= 0 && n <= 128));
6262+ default = null;
6363+ description = ''
6464+ The prefix length of the subnet.
6565+6666+ If null, a subnet consisting of only that single address is assumed.
6767+6868+ This conforms to standard CIDR notation as described in RFC1519.
6969+ '';
7070+ };
7171+7272+ weight = mkOption {
7373+ type = types.ints.unsigned;
7474+ default = 10;
7575+ description = ''
7676+ Indicates the priority over identical Subnets owned by different nodes.
7777+7878+ Lower values indicate higher priority. Packets will be sent to the
7979+ node with the highest priority, unless that node is not reachable, in
8080+ which case the node with the next highest priority will be tried, and
8181+ so on.
8282+ '';
8383+ };
8484+ };
8585+ };
8686+8787+ hostSubmodule = { config, ... }: {
8888+ options = {
8989+ addresses = mkOption {
9090+ type = types.listOf (types.submodule addressSubmodule);
9191+ default = [ ];
9292+ description = ''
9393+ The external address where the host can be reached. This will set this
9494+ host's <option>settings.Address</option> option.
9595+9696+ This variable is only required if you want to connect to this host.
9797+ '';
9898+ };
9999+100100+ subnets = mkOption {
101101+ type = types.listOf (types.submodule subnetSubmodule);
102102+ default = [ ];
103103+ description = ''
104104+ The subnets which this tinc daemon will serve. This will set this
105105+ host's <option>settings.Subnet</option> option.
106106+107107+ Tinc tries to look up which other daemon it should send a packet to by
108108+ searching the appropriate subnet. If the packet matches a subnet, it
109109+ will be sent to the daemon who has this subnet in his host
110110+ configuration file.
111111+ '';
112112+ };
113113+114114+ rsaPublicKey = mkOption {
115115+ type = types.str;
116116+ default = "";
117117+ description = ''
118118+ Legacy RSA public key of the host in PEM format, including start and
119119+ end markers.
120120+121121+ This will be appended as-is in the host's configuration file.
122122+123123+ The ed25519 public key can be specified using the
124124+ <option>settings.Ed25519PublicKey</option> option instead.
125125+ '';
126126+ };
612777- cfg = config.services.tinc;
128128+ settings = mkOption {
129129+ default = { };
130130+ type = types.submodule { freeformType = tincConfType; };
131131+ description = ''
132132+ Configuration for this host.
813399-in
134134+ See <link xlink:href="https://tinc-vpn.org/documentation-1.1/Host-configuration-variables.html"/>
135135+ for supported values.
136136+ '';
137137+ };
138138+ };
10139140140+ config.settings = {
141141+ Address = mkDefault (map
142142+ (address: "${address.address} ${toString address.port}")
143143+ config.addresses);
144144+145145+ Subnet = mkDefault (map
146146+ (subnet:
147147+ if subnet.prefixLength == null then "${subnet.address}#${toString subnet.weight}"
148148+ else "${subnet.address}/${toString subnet.prefixLength}#${toString subnet.weight}")
149149+ config.subnets);
150150+ };
151151+ };
152152+153153+in
11154{
1215513156 ###### interface
···1816119162 networks = mkOption {
20163 default = { };
2121- type = with types; attrsOf (submodule {
164164+ type = with types; attrsOf (submodule ({ config, ... }: {
22165 options = {
2316624167 extraConfig = mkOption {
···26169 type = types.lines;
27170 description = ''
28171 Extra lines to add to the tinc service configuration file.
172172+173173+ Note that using the declarative <option>service.tinc.networks.<name>.settings</option>
174174+ option is preferred.
29175 '';
30176 };
31177···72218 description = ''
73219 The name of the host in the network as well as the configuration for that host.
74220 This name should only contain alphanumerics and underscores.
221221+222222+ Note that using the declarative <option>service.tinc.networks.<name>.hostSettings</option>
223223+ option is preferred.
224224+ '';
225225+ };
226226+227227+ hostSettings = mkOption {
228228+ default = { };
229229+ example = literalExample ''
230230+ {
231231+ host1 = {
232232+ addresses = [
233233+ { address = "192.168.1.42"; }
234234+ { address = "192.168.1.42"; port = 1655; }
235235+ ];
236236+ subnets = [ { address = "10.0.0.42"; } ];
237237+ rsaPublicKey = "...";
238238+ settings = {
239239+ Ed25519PublicKey = "...";
240240+ };
241241+ };
242242+ host2 = {
243243+ subnets = [ { address = "10.0.1.0"; prefixLength = 24; weight = 2; } ];
244244+ rsaPublicKey = "...";
245245+ settings = {
246246+ Compression = 10;
247247+ };
248248+ };
249249+ }
250250+ '';
251251+ type = types.attrsOf (types.submodule hostSubmodule);
252252+ description = ''
253253+ The name of the host in the network as well as the configuration for that host.
254254+ This name should only contain alphanumerics and underscores.
75255 '';
76256 };
77257···79259 default = "tun";
80260 type = types.enum [ "tun" "tap" ];
81261 description = ''
8282- The type of virtual interface used for the network connection
262262+ The type of virtual interface used for the network connection.
83263 '';
84264 };
85265···116296 The chroot is performed after all the initialization is done, after writing pid files and opening network sockets.
117297118298 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.
299299+ '';
300300+ };
301301+302302+ settings = mkOption {
303303+ default = { };
304304+ type = types.submodule { freeformType = tincConfType; };
305305+ example = literalExample ''
306306+ {
307307+ Interface = "custom.interface";
308308+ DirectOnly = true;
309309+ Mode = "switch";
310310+ }
311311+ '';
312312+ description = ''
313313+ Configuration of the Tinc daemon for this network.
314314+315315+ See <link xlink:href="https://tinc-vpn.org/documentation-1.1/Main-configuration-variables.html"/>
316316+ for supported values.
119317 '';
120318 };
121319 };
122122- });
320320+321321+ config = {
322322+ hosts = mapAttrs
323323+ (hostname: host: ''
324324+ ${toTincConf host.settings}
325325+ ${host.rsaPublicKey}
326326+ '')
327327+ config.hostSettings;
328328+329329+ settings = {
330330+ DeviceType = mkDefault config.interfaceType;
331331+ Name = mkDefault (if config.name == null then "$HOST" else config.name);
332332+ Ed25519PrivateKeyFile = mkIf (config.ed25519PrivateKeyFile != null) (mkDefault config.ed25519PrivateKeyFile);
333333+ PrivateKeyFile = mkIf (config.rsaPrivateKeyFile != null) (mkDefault config.rsaPrivateKeyFile);
334334+ ListenAddress = mkIf (config.listenAddress != null) (mkDefault config.listenAddress);
335335+ BindToAddress = mkIf (config.bindToAddress != null) (mkDefault config.bindToAddress);
336336+ };
337337+ };
338338+ }));
123339124340 description = ''
125341 Defines the tinc networks which will be started.
···144360 "tinc/${network}/tinc.conf" = {
145361 mode = "0444";
146362 text = ''
147147- Name = ${if data.name == null then "$HOST" else data.name}
148148- DeviceType = ${data.interfaceType}
149149- ${optionalString (data.ed25519PrivateKeyFile != null) "Ed25519PrivateKeyFile = ${data.ed25519PrivateKeyFile}"}
150150- ${optionalString (data.rsaPrivateKeyFile != null) "PrivateKeyFile = ${data.rsaPrivateKeyFile}"}
151151- ${optionalString (data.listenAddress != null) "ListenAddress = ${data.listenAddress}"}
152152- ${optionalString (data.bindToAddress != null) "BindToAddress = ${data.bindToAddress}"}
153153- Interface = tinc.${network}
363363+ ${toTincConf ({ Interface = "tinc.${network}"; } // data.settings)}
154364 ${data.extraConfig}
155365 '';
156366 };
···222432223433 };
224434435435+ meta.maintainers = with maintainers; [ minijackson ];
225436}