python3Packages.orjson: Disable failing tests on 32 bit
[NixPkgs.git] / nixos / modules / services / networking / i2pd.nix
blobb60cbe664b6f6277cad82299c0a00c0f422ada26
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
7   cfg = config.services.i2pd;
9   homeDir = "/var/lib/i2pd";
11   strOpt = k: v: k + " = " + v;
12   boolOpt = k: v: k + " = " + boolToString v;
13   intOpt = k: v: k + " = " + toString v;
14   lstOpt = k: xs: k + " = " + 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 (lib.mdDoc name) // { default = true; };
22   mkEndpointOpt = name: addr: port: {
23     enable = mkEnableOption (lib.mdDoc name);
24     name = mkOption {
25       type = types.str;
26       default = name;
27       description = lib.mdDoc "The endpoint name.";
28     };
29     address = mkOption {
30       type = types.str;
31       default = addr;
32       description = lib.mdDoc "Bind address for ${name} endpoint.";
33     };
34     port = mkOption {
35       type = types.port;
36       default = port;
37       description = lib.mdDoc "Bind port for ${name} endpoint.";
38     };
39   };
41   i2cpOpts = name: {
42     length = mkOption {
43       type = types.int;
44       description = lib.mdDoc "Guaranteed minimum hops for ${name} tunnels.";
45       default = 3;
46     };
47     quantity = mkOption {
48       type = types.int;
49       description = lib.mdDoc "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 = with types; nullOr str;
58         default = keyloc;
59         description = lib.mdDoc ''
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 = lib.mdDoc "Min latency for tunnels.";
68         default = null;
69       };
70       latency.max = mkOption {
71         type = with types; nullOr int;
72         description = lib.mdDoc "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 = lib.mdDoc "Number of ElGamal/AES tags to send.";
83       default = 40;
84     };
85     destination = mkOption {
86       type = types.str;
87       description = lib.mdDoc "Remote endpoint, I2P hostname or b32.i2p address.";
88     };
89     keys = mkOption {
90       type = types.str;
91       default = name + "-keys.dat";
92       description = lib.mdDoc "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       ++ (flip map
166       (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         ] ++ (if proto ? keys then optionalNullString "keys" proto.keys else [])
173         ++ (if proto ? auth then optionalNullBool "auth" proto.auth else [])
174         ++ (if proto ? user then optionalNullString "user" proto.user else [])
175         ++ (if proto ? pass then optionalNullString "pass" proto.pass else [])
176         ++ (if proto ? strictHeaders then optionalNullBool "strictheaders" proto.strictHeaders else [])
177         ++ (if proto ? hostname then optionalNullString "hostname" proto.hostname else [])
178         ++ (if proto ? outproxy then optionalNullString "outproxy" proto.outproxy else [])
179         ++ (if proto ? outproxyPort then optionalNullInt "outproxyport" proto.outproxyPort else [])
180         ++ (if proto ? outproxyEnable then optionalNullBool "outproxy.enabled" proto.outproxyEnable else []);
181         in (concatStringsSep "\n" protoOpts)
182       ));
183   in
184     pkgs.writeText "i2pd.conf" (concatStringsSep "\n" opts);
186   tunnelConf = let opts = [
187     notice
188     (flip map
189       (collect (tun: tun ? port && tun ? destination) cfg.outTunnels)
190       (tun: let outTunOpts = [
191         (sec tun.name)
192         "type = client"
193         (intOpt "port" tun.port)
194         (strOpt "destination" tun.destination)
195         ] ++ (if tun ? destinationPort then optionalNullInt "destinationport" tun.destinationPort else [])
196         ++ (if tun ? keys then
197             optionalNullString "keys" tun.keys else [])
198         ++ (if tun ? address then
199             optionalNullString "address" tun.address else [])
200         ++ (if tun ? inbound.length then
201             optionalNullInt "inbound.length" tun.inbound.length else [])
202         ++ (if tun ? inbound.quantity then
203             optionalNullInt "inbound.quantity" tun.inbound.quantity else [])
204         ++ (if tun ? outbound.length then
205             optionalNullInt "outbound.length" tun.outbound.length else [])
206         ++ (if tun ? outbound.quantity then
207             optionalNullInt "outbound.quantity" tun.outbound.quantity else [])
208         ++ (if tun ? crypto.tagsToSend then
209             optionalNullInt "crypto.tagstosend" tun.crypto.tagsToSend else []);
210         in concatStringsSep "\n" outTunOpts))
211     (flip map
212       (collect (tun: tun ? port && tun ? address) cfg.inTunnels)
213       (tun: let inTunOpts = [
214         (sec tun.name)
215         "type = server"
216         (intOpt "port" tun.port)
217         (strOpt "host" tun.address)
218       ] ++ (if tun ? destination then
219             optionalNullString "destination" tun.destination else [])
220         ++ (if tun ? keys then
221             optionalNullString "keys" tun.keys else [])
222         ++ (if tun ? inPort then
223             optionalNullInt "inport" tun.inPort else [])
224         ++ (if tun ? accessList then
225             optionalEmptyList "accesslist" tun.accessList else []);
226         in concatStringsSep "\n" inTunOpts))];
227     in pkgs.writeText "i2pd-tunnels.conf" opts;
229   i2pdFlags = concatStringsSep " " (
230     optional (cfg.address != null) ("--host=" + cfg.address) ++ [
231     "--service"
232     ("--conf=" + i2pdConf)
233     ("--tunconf=" + tunnelConf)
234   ]);
240   imports = [
241     (mkRenamedOptionModule [ "services" "i2pd" "extIp" ] [ "services" "i2pd" "address" ])
242   ];
244   ###### interface
246   options = {
248     services.i2pd = {
250       enable = mkEnableOption (lib.mdDoc "I2Pd daemon") // {
251         description = lib.mdDoc ''
252           Enables I2Pd as a running service upon activation.
253           Please read http://i2pd.readthedocs.io/en/latest/ for further
254           configuration help.
255         '';
256       };
258       package = mkOption {
259         type = types.package;
260         default = pkgs.i2pd;
261         defaultText = literalExpression "pkgs.i2pd";
262         description = lib.mdDoc ''
263           i2pd package to use.
264         '';
265       };
267       logLevel = mkOption {
268         type = types.enum ["debug" "info" "warn" "error"];
269         default = "error";
270         description = lib.mdDoc ''
271           The log level. {command}`i2pd` defaults to "info"
272           but that generates copious amounts of log messages.
274           We default to "error" which is similar to the default log
275           level of {command}`tor`.
276         '';
277       };
279       logCLFTime = mkEnableOption (lib.mdDoc "Full CLF-formatted date and time to log");
281       address = mkOption {
282         type = with types; nullOr str;
283         default = null;
284         description = lib.mdDoc ''
285           Your external IP or hostname.
286         '';
287       };
289       family = mkOption {
290         type = with types; nullOr str;
291         default = null;
292         description = lib.mdDoc ''
293           Specify a family the router belongs to.
294         '';
295       };
297       dataDir = mkOption {
298         type = with types; nullOr str;
299         default = null;
300         description = lib.mdDoc ''
301           Alternative path to storage of i2pd data (RI, keys, peer profiles, ...)
302         '';
303       };
305       share = mkOption {
306         type = types.int;
307         default = 100;
308         description = lib.mdDoc ''
309           Limit of transit traffic from max bandwidth in percents.
310         '';
311       };
313       ifname = mkOption {
314         type = with types; nullOr str;
315         default = null;
316         description = lib.mdDoc ''
317           Network interface to bind to.
318         '';
319       };
321       ifname4 = mkOption {
322         type = with types; nullOr str;
323         default = null;
324         description = lib.mdDoc ''
325           IPv4 interface to bind to.
326         '';
327       };
329       ifname6 = mkOption {
330         type = with types; nullOr str;
331         default = null;
332         description = lib.mdDoc ''
333           IPv6 interface to bind to.
334         '';
335       };
337       ntcpProxy = mkOption {
338         type = with types; nullOr str;
339         default = null;
340         description = lib.mdDoc ''
341           Proxy URL for NTCP transport.
342         '';
343       };
345       ntcp = mkEnableTrueOption "ntcp";
346       ssu = mkEnableTrueOption "ssu";
348       notransit = mkEnableOption (lib.mdDoc "notransit") // {
349         description = lib.mdDoc ''
350           Tells the router to not accept transit tunnels during startup.
351         '';
352       };
354       floodfill = mkEnableOption (lib.mdDoc "floodfill") // {
355         description = lib.mdDoc ''
356           If the router is declared to be unreachable and needs introduction nodes.
357         '';
358       };
360       netid = mkOption {
361         type = types.int;
362         default = 2;
363         description = lib.mdDoc ''
364           I2P overlay netid.
365         '';
366       };
368       bandwidth = mkOption {
369         type = with types; nullOr int;
370         default = null;
371         description = lib.mdDoc ''
372            Set a router bandwidth limit integer in KBps.
373            If not set, {command}`i2pd` defaults to 32KBps.
374         '';
375       };
377       port = mkOption {
378         type = with types; nullOr int;
379         default = null;
380         description = lib.mdDoc ''
381           I2P listen port. If no one is given the router will pick between 9111 and 30777.
382         '';
383       };
385       enableIPv4 = mkEnableTrueOption "IPv4 connectivity";
386       enableIPv6 = mkEnableOption (lib.mdDoc "IPv6 connectivity");
387       nat = mkEnableTrueOption "NAT bypass";
389       upnp.enable = mkEnableOption (lib.mdDoc "UPnP service discovery");
390       upnp.name = mkOption {
391         type = types.str;
392         default = "I2Pd";
393         description = lib.mdDoc ''
394           Name i2pd appears in UPnP forwardings list.
395         '';
396       };
398       precomputation.elgamal = mkEnableTrueOption "Precomputed ElGamal tables" // {
399         description = lib.mdDoc ''
400           Whenever to use precomputated tables for ElGamal.
401           {command}`i2pd` defaults to `false`
402           to save 64M of memory (and looses some performance).
404           We default to `true` as that is what most
405           users want anyway.
406         '';
407       };
409       reseed.verify = mkEnableOption (lib.mdDoc "SU3 signature verification");
411       reseed.file = mkOption {
412         type = with types; nullOr str;
413         default = null;
414         description = lib.mdDoc ''
415           Full path to SU3 file to reseed from.
416         '';
417       };
419       reseed.urls = mkOption {
420         type = with types; listOf str;
421         default = [];
422         description = lib.mdDoc ''
423           Reseed URLs.
424         '';
425       };
427       reseed.floodfill = mkOption {
428         type = with types; nullOr str;
429         default = null;
430         description = lib.mdDoc ''
431           Path to router info of floodfill to reseed from.
432         '';
433       };
435       reseed.zipfile = mkOption {
436         type = with types; nullOr str;
437         default = null;
438         description = lib.mdDoc ''
439           Path to local .zip file to reseed from.
440         '';
441       };
443       reseed.proxy = mkOption {
444         type = with types; nullOr str;
445         default = null;
446         description = lib.mdDoc ''
447           URL for reseed proxy, supports http/socks.
448         '';
449       };
451      addressbook.defaulturl = mkOption {
452         type = types.str;
453         default = "http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt";
454         description = lib.mdDoc ''
455           AddressBook subscription URL for initial setup
456         '';
457       };
458      addressbook.subscriptions = mkOption {
459         type = with types; listOf str;
460         default = [
461           "http://inr.i2p/export/alive-hosts.txt"
462           "http://i2p-projekt.i2p/hosts.txt"
463           "http://stats.i2p/cgi-bin/newhosts.txt"
464         ];
465         description = lib.mdDoc ''
466           AddressBook subscription URLs
467         '';
468       };
470       trust.enable = mkEnableOption (lib.mdDoc "Explicit trust options");
472       trust.family = mkOption {
473         type = with types; nullOr str;
474         default = null;
475         description = lib.mdDoc ''
476           Router Familiy to trust for first hops.
477         '';
478       };
480       trust.routers = mkOption {
481         type = with types; listOf str;
482         default = [];
483         description = lib.mdDoc ''
484           Only connect to the listed routers.
485         '';
486       };
488       trust.hidden = mkEnableOption (lib.mdDoc "Router concealment");
490       websocket = mkEndpointOpt "websockets" "127.0.0.1" 7666;
492       exploratory.inbound = i2cpOpts "exploratory";
493       exploratory.outbound = i2cpOpts "exploratory";
495       ntcp2.enable = mkEnableTrueOption "NTCP2";
496       ntcp2.published = mkEnableOption (lib.mdDoc "NTCP2 publication");
497       ntcp2.port = mkOption {
498         type = types.int;
499         default = 0;
500         description = lib.mdDoc ''
501           Port to listen for incoming NTCP2 connections (0=auto).
502         '';
503       };
505       limits.transittunnels = mkOption {
506         type = types.int;
507         default = 2500;
508         description = lib.mdDoc ''
509           Maximum number of active transit sessions.
510         '';
511       };
513       limits.coreSize = mkOption {
514         type = types.int;
515         default = 0;
516         description = lib.mdDoc ''
517           Maximum size of corefile in Kb (0 - use system limit).
518         '';
519       };
521       limits.openFiles = mkOption {
522         type = types.int;
523         default = 0;
524         description = lib.mdDoc ''
525           Maximum number of open files (0 - use system default).
526         '';
527       };
529       limits.ntcpHard = mkOption {
530         type = types.int;
531         default = 0;
532         description = lib.mdDoc ''
533           Maximum number of active transit sessions.
534         '';
535       };
537       limits.ntcpSoft = mkOption {
538         type = types.int;
539         default = 0;
540         description = lib.mdDoc ''
541           Threshold to start probabalistic backoff with ntcp sessions (default: use system limit).
542         '';
543       };
545       limits.ntcpThreads = mkOption {
546         type = types.int;
547         default = 1;
548         description = lib.mdDoc ''
549           Maximum number of threads used by NTCP DH worker.
550         '';
551       };
553       yggdrasil.enable = mkEnableOption (lib.mdDoc "Yggdrasil");
555       yggdrasil.address = mkOption {
556         type = with types; nullOr str;
557         default = null;
558         description = lib.mdDoc ''
559           Your local yggdrasil address. Specify it if you want to bind your router to a
560           particular address.
561         '';
562       };
564       proto.http = (mkEndpointOpt "http" "127.0.0.1" 7070) // {
566         auth = mkEnableOption (lib.mdDoc "Webconsole authentication");
568         user = mkOption {
569           type = types.str;
570           default = "i2pd";
571           description = lib.mdDoc ''
572             Username for webconsole access
573           '';
574         };
576         pass = mkOption {
577           type = types.str;
578           default = "i2pd";
579           description = lib.mdDoc ''
580             Password for webconsole access.
581           '';
582         };
584         strictHeaders = mkOption {
585           type = with types; nullOr bool;
586           default = null;
587           description = lib.mdDoc ''
588             Enable strict host checking on WebUI.
589           '';
590         };
592         hostname = mkOption {
593           type = with types; nullOr str;
594           default = null;
595           description = lib.mdDoc ''
596             Expected hostname for WebUI.
597           '';
598         };
599       };
601       proto.httpProxy = (mkKeyedEndpointOpt "httpproxy" "127.0.0.1" 4444 "httpproxy-keys.dat")
602       // {
603         outproxy = mkOption {
604           type = with types; nullOr str;
605           default = null;
606           description = lib.mdDoc "Upstream outproxy bind address.";
607         };
608       };
609       proto.socksProxy = (mkKeyedEndpointOpt "socksproxy" "127.0.0.1" 4447 "socksproxy-keys.dat")
610       // {
611         outproxyEnable = mkEnableOption (lib.mdDoc "SOCKS outproxy");
612         outproxy = mkOption {
613           type = types.str;
614           default = "127.0.0.1";
615           description = lib.mdDoc "Upstream outproxy bind address.";
616         };
617         outproxyPort = mkOption {
618           type = types.int;
619           default = 4444;
620           description = lib.mdDoc "Upstream outproxy bind port.";
621         };
622       };
624       proto.sam = mkEndpointOpt "sam" "127.0.0.1" 7656;
625       proto.bob = mkEndpointOpt "bob" "127.0.0.1" 2827;
626       proto.i2cp = mkEndpointOpt "i2cp" "127.0.0.1" 7654;
627       proto.i2pControl = mkEndpointOpt "i2pcontrol" "127.0.0.1" 7650;
629       outTunnels = mkOption {
630         default = {};
631         type = with types; attrsOf (submodule (
632           { name, ... }: {
633             options = {
634               destinationPort = mkOption {
635                 type = with types; nullOr int;
636                 default = null;
637                 description = lib.mdDoc "Connect to particular port at destination.";
638               };
639             } // commonTunOpts name;
640             config = {
641               name = mkDefault name;
642             };
643           }
644         ));
645         description = lib.mdDoc ''
646           Connect to someone as a client and establish a local accept endpoint
647         '';
648       };
650       inTunnels = mkOption {
651         default = {};
652         type = with types; attrsOf (submodule (
653           { name, ... }: {
654             options = {
655               inPort = mkOption {
656                 type = types.int;
657                 default = 0;
658                 description = lib.mdDoc "Service port. Default to the tunnel's listen port.";
659               };
660               accessList = mkOption {
661                 type = with types; listOf str;
662                 default = [];
663                 description = lib.mdDoc "I2P nodes that are allowed to connect to this service.";
664               };
665             } // commonTunOpts name;
666             config = {
667               name = mkDefault name;
668             };
669           }
670         ));
671         description = lib.mdDoc ''
672           Serve something on I2P network at port and delegate requests to address inPort.
673         '';
674       };
675     };
676   };
679   ###### implementation
681   config = mkIf cfg.enable {
683     users.users.i2pd = {
684       group = "i2pd";
685       description = "I2Pd User";
686       home = homeDir;
687       createHome = true;
688       uid = config.ids.uids.i2pd;
689     };
691     users.groups.i2pd.gid = config.ids.gids.i2pd;
693     systemd.services.i2pd = {
694       description = "Minimal I2P router";
695       after = [ "network.target" ];
696       wantedBy = [ "multi-user.target" ];
697       serviceConfig =
698       {
699         User = "i2pd";
700         WorkingDirectory = homeDir;
701         Restart = "on-abort";
702         ExecStart = "${cfg.package}/bin/i2pd ${i2pdFlags}";
703       };
704     };
705   };