···1{ config, lib, pkgs, ... }:
23with lib;
0045-let
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000067- cfg = config.services.tinc;
000089-in
0000100000000000000011{
1213 ###### interface
···1819 networks = mkOption {
20 default = { };
21- type = with types; attrsOf (submodule {
22 options = {
2324 extraConfig = mkOption {
···26 type = types.lines;
27 description = ''
28 Extra lines to add to the tinc service configuration file.
00029 '';
30 };
31···72 description = ''
73 The name of the host in the network as well as the configuration for that host.
74 This name should only contain alphanumerics and underscores.
000000000000000000000000000000000075 '';
76 };
77···79 default = "tun";
80 type = types.enum [ "tun" "tap" ];
81 description = ''
82- The type of virtual interface used for the network connection
83 '';
84 };
85···116 The chroot is performed after all the initialization is done, after writing pid files and opening network sockets.
117118 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.
000000000000000000119 '';
120 };
121 };
122- });
000000000000000000123124 description = ''
125 Defines the tinc networks which will be started.
···144 "tinc/${network}/tinc.conf" = {
145 mode = "0444";
146 text = ''
147- Name = ${if data.name == null then "$HOST" else data.name}
148- DeviceType = ${data.interfaceType}
149- ${optionalString (data.ed25519PrivateKeyFile != null) "Ed25519PrivateKeyFile = ${data.ed25519PrivateKeyFile}"}
150- ${optionalString (data.rsaPrivateKeyFile != null) "PrivateKeyFile = ${data.rsaPrivateKeyFile}"}
151- ${optionalString (data.listenAddress != null) "ListenAddress = ${data.listenAddress}"}
152- ${optionalString (data.bindToAddress != null) "BindToAddress = ${data.bindToAddress}"}
153- Interface = tinc.${network}
154 ${data.extraConfig}
155 '';
156 };
···222223 };
2240225}
···1{ config, lib, pkgs, ... }:
23with lib;
4+let
5+ cfg = config.services.tinc;
67+ mkValueString = value:
8+ if value == true then "yes"
9+ else if value == false then "no"
10+ else generators.mkValueStringDefault { } value;
11+12+ toTincConf = generators.toKeyValue {
13+ listsAsDuplicateKeys = true;
14+ mkKeyValue = generators.mkKeyValueDefault { inherit mkValueString; } "=";
15+ };
16+17+ tincConfType = with types;
18+ let
19+ valueType = oneOf [ bool str int ];
20+ in
21+ attrsOf (either valueType (listOf valueType));
22+23+ addressSubmodule = {
24+ options = {
25+ address = mkOption {
26+ type = types.str;
27+ description = "The external IP address or hostname where the host can be reached.";
28+ };
29+30+ port = mkOption {
31+ type = types.nullOr types.port;
32+ default = null;
33+ description = ''
34+ The port where the host can be reached.
35+36+ If no port is specified, the default Port is used.
37+ '';
38+ };
39+ };
40+ };
41+42+ subnetSubmodule = {
43+ options = {
44+ address = mkOption {
45+ type = types.str;
46+ description = ''
47+ The subnet of this host.
48+49+ Subnets can either be single MAC, IPv4 or IPv6 addresses, in which case
50+ a subnet consisting of only that single address is assumed, or they can
51+ be a IPv4 or IPv6 network address with a prefix length.
52+53+ IPv4 subnets are notated like 192.168.1.0/24, IPv6 subnets are notated
54+ like fec0:0:0:1::/64. MAC addresses are notated like 0:1a:2b:3c:4d:5e.
55+56+ Note that subnets like 192.168.1.1/24 are invalid.
57+ '';
58+ };
59+60+ prefixLength = mkOption {
61+ type = with types; nullOr (addCheck int (n: n >= 0 && n <= 128));
62+ default = null;
63+ description = ''
64+ The prefix length of the subnet.
65+66+ If null, a subnet consisting of only that single address is assumed.
67+68+ This conforms to standard CIDR notation as described in RFC1519.
69+ '';
70+ };
71+72+ weight = mkOption {
73+ type = types.ints.unsigned;
74+ default = 10;
75+ description = ''
76+ Indicates the priority over identical Subnets owned by different nodes.
77+78+ Lower values indicate higher priority. Packets will be sent to the
79+ node with the highest priority, unless that node is not reachable, in
80+ which case the node with the next highest priority will be tried, and
81+ so on.
82+ '';
83+ };
84+ };
85+ };
86+87+ hostSubmodule = { config, ... }: {
88+ options = {
89+ addresses = mkOption {
90+ type = types.listOf (types.submodule addressSubmodule);
91+ default = [ ];
92+ description = ''
93+ The external address where the host can be reached. This will set this
94+ host's <option>settings.Address</option> option.
95+96+ This variable is only required if you want to connect to this host.
97+ '';
98+ };
99+100+ subnets = mkOption {
101+ type = types.listOf (types.submodule subnetSubmodule);
102+ default = [ ];
103+ description = ''
104+ The subnets which this tinc daemon will serve. This will set this
105+ host's <option>settings.Subnet</option> option.
106+107+ Tinc tries to look up which other daemon it should send a packet to by
108+ searching the appropriate subnet. If the packet matches a subnet, it
109+ will be sent to the daemon who has this subnet in his host
110+ configuration file.
111+ '';
112+ };
113+114+ rsaPublicKey = mkOption {
115+ type = types.str;
116+ default = "";
117+ description = ''
118+ Legacy RSA public key of the host in PEM format, including start and
119+ end markers.
120+121+ This will be appended as-is in the host's configuration file.
122+123+ The ed25519 public key can be specified using the
124+ <option>settings.Ed25519PublicKey</option> option instead.
125+ '';
126+ };
127128+ settings = mkOption {
129+ default = { };
130+ type = types.submodule { freeformType = tincConfType; };
131+ description = ''
132+ Configuration for this host.
133134+ See <link xlink:href="https://tinc-vpn.org/documentation-1.1/Host-configuration-variables.html"/>
135+ for supported values.
136+ '';
137+ };
138+ };
139140+ config.settings = {
141+ Address = mkDefault (map
142+ (address: "${address.address} ${toString address.port}")
143+ config.addresses);
144+145+ Subnet = mkDefault (map
146+ (subnet:
147+ if subnet.prefixLength == null then "${subnet.address}#${toString subnet.weight}"
148+ else "${subnet.address}/${toString subnet.prefixLength}#${toString subnet.weight}")
149+ config.subnets);
150+ };
151+ };
152+153+in
154{
155156 ###### interface
···161162 networks = mkOption {
163 default = { };
164+ type = with types; attrsOf (submodule ({ config, ... }: {
165 options = {
166167 extraConfig = mkOption {
···169 type = types.lines;
170 description = ''
171 Extra lines to add to the tinc service configuration file.
172+173+ Note that using the declarative <option>service.tinc.networks.<name>.settings</option>
174+ option is preferred.
175 '';
176 };
177···218 description = ''
219 The name of the host in the network as well as the configuration for that host.
220 This name should only contain alphanumerics and underscores.
221+222+ Note that using the declarative <option>service.tinc.networks.<name>.hostSettings</option>
223+ option is preferred.
224+ '';
225+ };
226+227+ hostSettings = mkOption {
228+ default = { };
229+ example = literalExample ''
230+ {
231+ host1 = {
232+ addresses = [
233+ { address = "192.168.1.42"; }
234+ { address = "192.168.1.42"; port = 1655; }
235+ ];
236+ subnets = [ { address = "10.0.0.42"; } ];
237+ rsaPublicKey = "...";
238+ settings = {
239+ Ed25519PublicKey = "...";
240+ };
241+ };
242+ host2 = {
243+ subnets = [ { address = "10.0.1.0"; prefixLength = 24; weight = 2; } ];
244+ rsaPublicKey = "...";
245+ settings = {
246+ Compression = 10;
247+ };
248+ };
249+ }
250+ '';
251+ type = types.attrsOf (types.submodule hostSubmodule);
252+ description = ''
253+ The name of the host in the network as well as the configuration for that host.
254+ This name should only contain alphanumerics and underscores.
255 '';
256 };
257···259 default = "tun";
260 type = types.enum [ "tun" "tap" ];
261 description = ''
262+ The type of virtual interface used for the network connection.
263 '';
264 };
265···296 The chroot is performed after all the initialization is done, after writing pid files and opening network sockets.
297298 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.
299+ '';
300+ };
301+302+ settings = mkOption {
303+ default = { };
304+ type = types.submodule { freeformType = tincConfType; };
305+ example = literalExample ''
306+ {
307+ Interface = "custom.interface";
308+ DirectOnly = true;
309+ Mode = "switch";
310+ }
311+ '';
312+ description = ''
313+ Configuration of the Tinc daemon for this network.
314+315+ See <link xlink:href="https://tinc-vpn.org/documentation-1.1/Main-configuration-variables.html"/>
316+ for supported values.
317 '';
318 };
319 };
320+321+ config = {
322+ hosts = mapAttrs
323+ (hostname: host: ''
324+ ${toTincConf host.settings}
325+ ${host.rsaPublicKey}
326+ '')
327+ config.hostSettings;
328+329+ settings = {
330+ DeviceType = mkDefault config.interfaceType;
331+ Name = mkDefault (if config.name == null then "$HOST" else config.name);
332+ Ed25519PrivateKeyFile = mkIf (config.ed25519PrivateKeyFile != null) (mkDefault config.ed25519PrivateKeyFile);
333+ PrivateKeyFile = mkIf (config.rsaPrivateKeyFile != null) (mkDefault config.rsaPrivateKeyFile);
334+ ListenAddress = mkIf (config.listenAddress != null) (mkDefault config.listenAddress);
335+ BindToAddress = mkIf (config.bindToAddress != null) (mkDefault config.bindToAddress);
336+ };
337+ };
338+ }));
339340 description = ''
341 Defines the tinc networks which will be started.
···360 "tinc/${network}/tinc.conf" = {
361 mode = "0444";
362 text = ''
363+ ${toTincConf ({ Interface = "tinc.${network}"; } // data.settings)}
000000364 ${data.extraConfig}
365 '';
366 };
···432433 };
434435+ meta.maintainers = with maintainers; [ minijackson ];
436}