vuls: init at 0.27.0
[NixPkgs.git] / nixos / modules / services / networking / i2pd.nix
blob72069e609ac28a1d2dc799152c899bb19ed15f9c
1 { config, lib, pkgs, ... }:
3 let
4   inherit (lib) mkIf mkOption mkDefault mkEnableOption types optional optionals;
5   inherit (lib.types) nullOr bool listOf str attrsOf submodule;
7   cfg = config.services.i2pd;
9   homeDir = "/var/lib/i2pd";
11   strOpt = k: v: k + " = " + v;
12   boolOpt = k: v: k + " = " + lib.boolToString v;
13   intOpt = k: v: k + " = " + toString v;
14   lstOpt = k: xs: k + " = " + lib.concatStringsSep "," xs;
15   optionalNullString = o: s: optional (s != null) (strOpt o s);
16   optionalNullBool = o: b: optional (b != null) (boolOpt o b);
17   optionalNullInt = o: i: optional (i != null) (intOpt o i);
18   optionalEmptyList = o: l: optional ([] != l) (lstOpt o l);
20   mkEnableTrueOption = name: mkEnableOption name // { default = true; };
22   mkEndpointOpt = name: addr: port: {
23     enable = mkEnableOption name;
24     name = mkOption {
25       type = types.str;
26       default = name;
27       description = "The endpoint name.";
28     };
29     address = mkOption {
30       type = types.str;
31       default = addr;
32       description = "Bind address for ${name} endpoint.";
33     };
34     port = mkOption {
35       type = types.port;
36       default = port;
37       description = "Bind port for ${name} endpoint.";
38     };
39   };
41   i2cpOpts = name: {
42     length = mkOption {
43       type = types.int;
44       description = "Guaranteed minimum hops for ${name} tunnels.";
45       default = 3;
46     };
47     quantity = mkOption {
48       type = types.int;
49       description = "Number of simultaneous ${name} tunnels.";
50       default = 5;
51     };
52   };
54   mkKeyedEndpointOpt = name: addr: port: keyloc:
55     (mkEndpointOpt name addr port) // {
56       keys = mkOption {
57         type = nullOr str;
58         default = keyloc;
59         description = ''
60           File to persist ${lib.toUpper name} keys.
61         '';
62       };
63       inbound = i2cpOpts name;
64       outbound = i2cpOpts name;
65       latency.min = mkOption {
66         type = with types; nullOr int;
67         description = "Min latency for tunnels.";
68         default = null;
69       };
70       latency.max = mkOption {
71         type = with types; nullOr int;
72         description = "Max latency for tunnels.";
73         default = null;
74       };
75     };
77   commonTunOpts = name: {
78     outbound = i2cpOpts name;
79     inbound = i2cpOpts name;
80     crypto.tagsToSend = mkOption {
81       type = types.int;
82       description = "Number of ElGamal/AES tags to send.";
83       default = 40;
84     };
85     destination = mkOption {
86       type = types.str;
87       description = "Remote endpoint, I2P hostname or b32.i2p address.";
88     };
89     keys = mkOption {
90       type = types.str;
91       default = name + "-keys.dat";
92       description = "Keyset used for tunnel identity.";
93     };
94   } // mkEndpointOpt name "127.0.0.1" 0;
96   sec = name: "\n[" + name + "]";
97   notice = "# DO NOT EDIT -- this file has been generated automatically.";
98   i2pdConf = let
99     opts = [
100       notice
101       (strOpt "loglevel" cfg.logLevel)
102       (boolOpt "logclftime" cfg.logCLFTime)
103       (boolOpt "ipv4" cfg.enableIPv4)
104       (boolOpt "ipv6" cfg.enableIPv6)
105       (boolOpt "notransit" cfg.notransit)
106       (boolOpt "floodfill" cfg.floodfill)
107       (intOpt "netid" cfg.netid)
108     ] ++ (optionalNullInt "bandwidth" cfg.bandwidth)
109       ++ (optionalNullInt "port" cfg.port)
110       ++ (optionalNullString "family" cfg.family)
111       ++ (optionalNullString "datadir" cfg.dataDir)
112       ++ (optionalNullInt "share" cfg.share)
113       ++ (optionalNullBool "ssu" cfg.ssu)
114       ++ (optionalNullBool "ntcp" cfg.ntcp)
115       ++ (optionalNullString "ntcpproxy" cfg.ntcpProxy)
116       ++ (optionalNullString "ifname" cfg.ifname)
117       ++ (optionalNullString "ifname4" cfg.ifname4)
118       ++ (optionalNullString "ifname6" cfg.ifname6)
119       ++ [
120       (sec "limits")
121       (intOpt "transittunnels" cfg.limits.transittunnels)
122       (intOpt "coresize" cfg.limits.coreSize)
123       (intOpt "openfiles" cfg.limits.openFiles)
124       (intOpt "ntcphard" cfg.limits.ntcpHard)
125       (intOpt "ntcpsoft" cfg.limits.ntcpSoft)
126       (intOpt "ntcpthreads" cfg.limits.ntcpThreads)
127       (sec "upnp")
128       (boolOpt "enabled" cfg.upnp.enable)
129       (sec "precomputation")
130       (boolOpt "elgamal" cfg.precomputation.elgamal)
131       (sec "reseed")
132       (boolOpt "verify" cfg.reseed.verify)
133     ] ++ (optionalNullString "file" cfg.reseed.file)
134       ++ (optionalEmptyList "urls" cfg.reseed.urls)
135       ++ (optionalNullString "floodfill" cfg.reseed.floodfill)
136       ++ (optionalNullString "zipfile" cfg.reseed.zipfile)
137       ++ (optionalNullString "proxy" cfg.reseed.proxy)
138       ++ [
139       (sec "trust")
140       (boolOpt "enabled" cfg.trust.enable)
141       (boolOpt "hidden" cfg.trust.hidden)
142     ] ++ (optionalEmptyList "routers" cfg.trust.routers)
143       ++ (optionalNullString "family" cfg.trust.family)
144       ++ [
145       (sec "websockets")
146       (boolOpt "enabled" cfg.websocket.enable)
147       (strOpt "address" cfg.websocket.address)
148       (intOpt "port" cfg.websocket.port)
149       (sec "exploratory")
150       (intOpt "inbound.length" cfg.exploratory.inbound.length)
151       (intOpt "inbound.quantity" cfg.exploratory.inbound.quantity)
152       (intOpt "outbound.length" cfg.exploratory.outbound.length)
153       (intOpt "outbound.quantity" cfg.exploratory.outbound.quantity)
154       (sec "ntcp2")
155       (boolOpt "enabled" cfg.ntcp2.enable)
156       (boolOpt "published" cfg.ntcp2.published)
157       (intOpt "port" cfg.ntcp2.port)
158       (sec "addressbook")
159       (strOpt "defaulturl" cfg.addressbook.defaulturl)
160     ] ++ (optionalEmptyList "subscriptions" cfg.addressbook.subscriptions)
161       ++ [
162       (sec "meshnets")
163       (boolOpt "yggdrasil" cfg.yggdrasil.enable)
164     ] ++ (optionalNullString "yggaddress" cfg.yggdrasil.address)
165       ++ (lib.flip map
166       (lib.collect (proto: proto ? port && proto ? address) cfg.proto)
167       (proto: let protoOpts = [
168         (sec proto.name)
169         (boolOpt "enabled" proto.enable)
170         (strOpt "address" proto.address)
171         (intOpt "port" proto.port)
172         ] ++ (optionals (proto ? keys) (optionalNullString "keys" proto.keys))
173         ++ (optionals (proto ? auth) (optionalNullBool "auth" proto.auth))
174         ++ (optionals (proto ? user) (optionalNullString "user" proto.user))
175         ++ (optionals (proto ? pass) (optionalNullString "pass" proto.pass))
176         ++ (optionals (proto ? strictHeaders) (optionalNullBool "strictheaders" proto.strictHeaders))
177         ++ (optionals (proto ? hostname) (optionalNullString "hostname" proto.hostname))
178         ++ (optionals (proto ? outproxy) (optionalNullString "outproxy" proto.outproxy))
179         ++ (optionals (proto ? outproxyPort) (optionalNullInt "outproxyport" proto.outproxyPort))
180         ++ (optionals (proto ? outproxyEnable) (optionalNullBool "outproxy.enabled" proto.outproxyEnable));
181         in (lib.concatStringsSep "\n" protoOpts)
182       ));
183   in
184     pkgs.writeText "i2pd.conf" (lib.concatStringsSep "\n" opts);
186   tunnelConf = let
187     mkOutTunnel = tun:
188       let
189         outTunOpts = [
190           (sec tun.name)
191           "type = client"
192           (intOpt "port" tun.port)
193           (strOpt "destination" tun.destination)
194         ] ++ (optionals (tun ? destinationPort) (optionalNullInt "destinationport" tun.destinationPort))
195           ++ (optionals (tun ? keys) (optionalNullString "keys" tun.keys))
196           ++ (optionals (tun ? address) (optionalNullString "address" tun.address))
197           ++ (optionals (tun ? inbound.length) (optionalNullInt "inbound.length" tun.inbound.length))
198           ++ (optionals (tun ? inbound.quantity) (optionalNullInt "inbound.quantity" tun.inbound.quantity))
199           ++ (optionals (tun ? outbound.length) (optionalNullInt "outbound.length" tun.outbound.length))
200           ++ (optionals (tun ? outbound.quantity) (optionalNullInt "outbound.quantity" tun.outbound.quantity))
201           ++ (optionals (tun ? crypto.tagsToSend) (optionalNullInt "crypto.tagstosend" tun.crypto.tagsToSend));
202       in
203         lib.concatStringsSep "\n" outTunOpts;
205     mkInTunnel = tun:
206       let
207         inTunOpts = [
208           (sec tun.name)
209           "type = server"
210           (intOpt "port" tun.port)
211           (strOpt "host" tun.address)
212         ] ++ (optionals (tun ? destination) (optionalNullString "destination" tun.destination))
213           ++ (optionals (tun ? keys) (optionalNullString "keys" tun.keys))
214           ++ (optionals (tun ? inPort) (optionalNullInt "inport" tun.inPort))
215           ++ (optionals (tun ? accessList) (optionalEmptyList "accesslist" tun.accessList));
216       in
217         lib.concatStringsSep "\n" inTunOpts;
219     allOutTunnels = lib.collect (tun: tun ? port && tun ? destination) cfg.outTunnels;
220     allInTunnels = lib.collect (tun: tun ? port && tun ? address) cfg.inTunnels;
222     opts = [ notice ] ++ (map mkOutTunnel allOutTunnels) ++ (map mkInTunnel allInTunnels);
223   in
224     pkgs.writeText "i2pd-tunnels.conf" (lib.concatStringsSep "\n" opts);
226   i2pdFlags = lib.concatStringsSep " " (
227     optional (cfg.address != null) ("--host=" + cfg.address) ++ [
228     "--service"
229     ("--conf=" + i2pdConf)
230     ("--tunconf=" + tunnelConf)
231   ]);
237   imports = [
238     (lib.mkRenamedOptionModule [ "services" "i2pd" "extIp" ] [ "services" "i2pd" "address" ])
239   ];
241   ###### interface
243   options = {
245     services.i2pd = {
247       enable = mkEnableOption "I2Pd daemon" // {
248         description = ''
249           Enables I2Pd as a running service upon activation.
250           Please read <https://i2pd.readthedocs.io/en/latest/> for further
251           configuration help.
252         '';
253       };
255       package = lib.mkPackageOption pkgs "i2pd" { };
257       logLevel = mkOption {
258         type = types.enum ["debug" "info" "warn" "error"];
259         default = "error";
260         description = ''
261           The log level. {command}`i2pd` defaults to "info"
262           but that generates copious amounts of log messages.
264           We default to "error" which is similar to the default log
265           level of {command}`tor`.
266         '';
267       };
269       logCLFTime = mkEnableOption "full CLF-formatted date and time to log";
271       address = mkOption {
272         type = nullOr str;
273         default = null;
274         description = ''
275           Your external IP or hostname.
276         '';
277       };
279       family = mkOption {
280         type = nullOr str;
281         default = null;
282         description = ''
283           Specify a family the router belongs to.
284         '';
285       };
287       dataDir = mkOption {
288         type = nullOr str;
289         default = null;
290         description = ''
291           Alternative path to storage of i2pd data (RI, keys, peer profiles, ...)
292         '';
293       };
295       share = mkOption {
296         type = types.int;
297         default = 100;
298         description = ''
299           Limit of transit traffic from max bandwidth in percents.
300         '';
301       };
303       ifname = mkOption {
304         type = nullOr str;
305         default = null;
306         description = ''
307           Network interface to bind to.
308         '';
309       };
311       ifname4 = mkOption {
312         type = nullOr str;
313         default = null;
314         description = ''
315           IPv4 interface to bind to.
316         '';
317       };
319       ifname6 = mkOption {
320         type = nullOr str;
321         default = null;
322         description = ''
323           IPv6 interface to bind to.
324         '';
325       };
327       ntcpProxy = mkOption {
328         type = nullOr str;
329         default = null;
330         description = ''
331           Proxy URL for NTCP transport.
332         '';
333       };
335       ntcp = mkEnableTrueOption "ntcp";
336       ssu = mkEnableTrueOption "ssu";
338       notransit = mkEnableOption "notransit" // {
339         description = ''
340           Tells the router to not accept transit tunnels during startup.
341         '';
342       };
344       floodfill = mkEnableOption "floodfill" // {
345         description = ''
346           If the router is declared to be unreachable and needs introduction nodes.
347         '';
348       };
350       netid = mkOption {
351         type = types.int;
352         default = 2;
353         description = ''
354           I2P overlay netid.
355         '';
356       };
358       bandwidth = mkOption {
359         type = with types; nullOr int;
360         default = null;
361         description = ''
362            Set a router bandwidth limit integer in KBps.
363            If not set, {command}`i2pd` defaults to 32KBps.
364         '';
365       };
367       port = mkOption {
368         type = with types; nullOr int;
369         default = null;
370         description = ''
371           I2P listen port. If no one is given the router will pick between 9111 and 30777.
372         '';
373       };
375       enableIPv4 = mkEnableTrueOption "IPv4 connectivity";
376       enableIPv6 = mkEnableOption "IPv6 connectivity";
377       nat = mkEnableTrueOption "NAT bypass";
379       upnp.enable = mkEnableOption "UPnP service discovery";
380       upnp.name = mkOption {
381         type = types.str;
382         default = "I2Pd";
383         description = ''
384           Name i2pd appears in UPnP forwardings list.
385         '';
386       };
388       precomputation.elgamal = mkEnableTrueOption "Precomputed ElGamal tables" // {
389         description = ''
390           Whenever to use precomputated tables for ElGamal.
391           {command}`i2pd` defaults to `false`
392           to save 64M of memory (and looses some performance).
394           We default to `true` as that is what most
395           users want anyway.
396         '';
397       };
399       reseed.verify = mkEnableOption "SU3 signature verification";
401       reseed.file = mkOption {
402         type = nullOr str;
403         default = null;
404         description = ''
405           Full path to SU3 file to reseed from.
406         '';
407       };
409       reseed.urls = mkOption {
410         type = listOf str;
411         default = [];
412         description = ''
413           Reseed URLs.
414         '';
415       };
417       reseed.floodfill = mkOption {
418         type = nullOr str;
419         default = null;
420         description = ''
421           Path to router info of floodfill to reseed from.
422         '';
423       };
425       reseed.zipfile = mkOption {
426         type = nullOr str;
427         default = null;
428         description = ''
429           Path to local .zip file to reseed from.
430         '';
431       };
433       reseed.proxy = mkOption {
434         type = nullOr str;
435         default = null;
436         description = ''
437           URL for reseed proxy, supports http/socks.
438         '';
439       };
441      addressbook.defaulturl = mkOption {
442         type = types.str;
443         default = "http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt";
444         description = ''
445           AddressBook subscription URL for initial setup
446         '';
447       };
448      addressbook.subscriptions = mkOption {
449         type = listOf str;
450         default = [
451           "http://inr.i2p/export/alive-hosts.txt"
452           "http://i2p-projekt.i2p/hosts.txt"
453           "http://stats.i2p/cgi-bin/newhosts.txt"
454         ];
455         description = ''
456           AddressBook subscription URLs
457         '';
458       };
460       trust.enable = mkEnableOption "explicit trust options";
462       trust.family = mkOption {
463         type = nullOr str;
464         default = null;
465         description = ''
466           Router Family to trust for first hops.
467         '';
468       };
470       trust.routers = mkOption {
471         type = listOf str;
472         default = [];
473         description = ''
474           Only connect to the listed routers.
475         '';
476       };
478       trust.hidden = mkEnableOption "router concealment";
480       websocket = mkEndpointOpt "websockets" "127.0.0.1" 7666;
482       exploratory.inbound = i2cpOpts "exploratory";
483       exploratory.outbound = i2cpOpts "exploratory";
485       ntcp2.enable = mkEnableTrueOption "NTCP2";
486       ntcp2.published = mkEnableOption "NTCP2 publication";
487       ntcp2.port = mkOption {
488         type = types.port;
489         default = 0;
490         description = ''
491           Port to listen for incoming NTCP2 connections (0=auto).
492         '';
493       };
495       limits.transittunnels = mkOption {
496         type = types.int;
497         default = 2500;
498         description = ''
499           Maximum number of active transit sessions.
500         '';
501       };
503       limits.coreSize = mkOption {
504         type = types.int;
505         default = 0;
506         description = ''
507           Maximum size of corefile in Kb (0 - use system limit).
508         '';
509       };
511       limits.openFiles = mkOption {
512         type = types.int;
513         default = 0;
514         description = ''
515           Maximum number of open files (0 - use system default).
516         '';
517       };
519       limits.ntcpHard = mkOption {
520         type = types.int;
521         default = 0;
522         description = ''
523           Maximum number of active transit sessions.
524         '';
525       };
527       limits.ntcpSoft = mkOption {
528         type = types.int;
529         default = 0;
530         description = ''
531           Threshold to start probabalistic backoff with ntcp sessions (default: use system limit).
532         '';
533       };
535       limits.ntcpThreads = mkOption {
536         type = types.int;
537         default = 1;
538         description = ''
539           Maximum number of threads used by NTCP DH worker.
540         '';
541       };
543       yggdrasil.enable = mkEnableOption "Yggdrasil";
545       yggdrasil.address = mkOption {
546         type = nullOr str;
547         default = null;
548         description = ''
549           Your local yggdrasil address. Specify it if you want to bind your router to a
550           particular address.
551         '';
552       };
554       proto.http = (mkEndpointOpt "http" "127.0.0.1" 7070) // {
556         auth = mkEnableOption "webconsole authentication";
558         user = mkOption {
559           type = types.str;
560           default = "i2pd";
561           description = ''
562             Username for webconsole access
563           '';
564         };
566         pass = mkOption {
567           type = types.str;
568           default = "i2pd";
569           description = ''
570             Password for webconsole access.
571           '';
572         };
574         strictHeaders = mkOption {
575           type = nullOr bool;
576           default = null;
577           description = ''
578             Enable strict host checking on WebUI.
579           '';
580         };
582         hostname = mkOption {
583           type = nullOr str;
584           default = null;
585           description = ''
586             Expected hostname for WebUI.
587           '';
588         };
589       };
591       proto.httpProxy = (mkKeyedEndpointOpt "httpproxy" "127.0.0.1" 4444 "httpproxy-keys.dat")
592       // {
593         outproxy = mkOption {
594           type = nullOr str;
595           default = null;
596           description = "Upstream outproxy bind address.";
597         };
598       };
599       proto.socksProxy = (mkKeyedEndpointOpt "socksproxy" "127.0.0.1" 4447 "socksproxy-keys.dat")
600       // {
601         outproxyEnable = mkEnableOption "SOCKS outproxy";
602         outproxy = mkOption {
603           type = types.str;
604           default = "127.0.0.1";
605           description = "Upstream outproxy bind address.";
606         };
607         outproxyPort = mkOption {
608           type = types.int;
609           default = 4444;
610           description = "Upstream outproxy bind port.";
611         };
612       };
614       proto.sam = mkEndpointOpt "sam" "127.0.0.1" 7656;
615       proto.bob = mkEndpointOpt "bob" "127.0.0.1" 2827;
616       proto.i2cp = mkEndpointOpt "i2cp" "127.0.0.1" 7654;
617       proto.i2pControl = mkEndpointOpt "i2pcontrol" "127.0.0.1" 7650;
619       outTunnels = mkOption {
620         default = {};
621         type = attrsOf (submodule (
622           { name, ... }: {
623             options = {
624               destinationPort = mkOption {
625                 type = with types; nullOr int;
626                 default = null;
627                 description = "Connect to particular port at destination.";
628               };
629             } // commonTunOpts name;
630             config = {
631               name = mkDefault name;
632             };
633           }
634         ));
635         description = ''
636           Connect to someone as a client and establish a local accept endpoint
637         '';
638       };
640       inTunnels = mkOption {
641         default = {};
642         type = attrsOf (submodule (
643           { name, ... }: {
644             options = {
645               inPort = mkOption {
646                 type = types.int;
647                 default = 0;
648                 description = "Service port. Default to the tunnel's listen port.";
649               };
650               accessList = mkOption {
651                 type = listOf str;
652                 default = [];
653                 description = "I2P nodes that are allowed to connect to this service.";
654               };
655             } // commonTunOpts name;
656             config = {
657               name = mkDefault name;
658             };
659           }
660         ));
661         description = ''
662           Serve something on I2P network at port and delegate requests to address inPort.
663         '';
664       };
665     };
666   };
669   ###### implementation
671   config = mkIf cfg.enable {
673     users.users.i2pd = {
674       group = "i2pd";
675       description = "I2Pd User";
676       home = homeDir;
677       createHome = true;
678       uid = config.ids.uids.i2pd;
679     };
681     users.groups.i2pd.gid = config.ids.gids.i2pd;
683     systemd.services.i2pd = {
684       description = "Minimal I2P router";
685       after = [ "network.target" ];
686       wantedBy = [ "multi-user.target" ];
687       serviceConfig =
688       {
689         User = "i2pd";
690         WorkingDirectory = homeDir;
691         Restart = "on-abort";
692         ExecStart = "${cfg.package}/bin/i2pd ${i2pdFlags}";
693       };
694     };
695   };