nixos/i2pd: Update options to encompass recent additions to the daemon

Also:
  * switch to flat sysdir
  * remove nixos default reseeds, rely on program defaults
  * refactor config expressions
This commit is contained in:
Edward Tjörnhammar 2018-09-09 18:47:26 +02:00
parent 201ee19758
commit 9dc661aa72
No known key found for this signature in database
GPG key ID: 577898458385603E

View file

@ -8,6 +8,17 @@ let
homeDir = "/var/lib/i2pd";
strOpt = k: v: k + " = " + v;
boolOpt = k: v: k + " = " + boolToString v;
intOpt = k: v: k + " = " + toString v;
lstOpt = k: xs: k + " = " + concatStringsSep "," xs;
optionalNullString = o: s: optional (! isNull s) (strOpt o s);
optionalNullBool = o: b: optional (! isNull b) (boolOpt o b);
optionalNullInt = o: i: optional (! isNull i) (intOpt o i);
optionalEmptyList = o: l: optional ([] != l) (lstOpt o l);
mkEnableTrueOption = name: mkEnableOption name // { default = true; };
mkEndpointOpt = name: addr: port: {
enable = mkEnableOption name;
name = mkOption {
@ -18,42 +29,54 @@ let
address = mkOption {
type = types.str;
default = addr;
description = "Bind address for ${name} endpoint. Default: " + addr;
description = "Bind address for ${name} endpoint.";
};
port = mkOption {
type = types.int;
default = port;
description = "Bind port for ${name} endoint. Default: " + toString port;
description = "Bind port for ${name} endoint.";
};
};
mkKeyedEndpointOpt = name: addr: port: keyFile:
i2cpOpts = name: {
length = mkOption {
type = types.int;
description = "Guaranteed minimum hops for ${name} tunnels.";
default = 3;
};
quantity = mkOption {
type = types.int;
description = "Number of simultaneous ${name} tunnels.";
default = 5;
};
};
mkKeyedEndpointOpt = name: addr: port: keyloc:
(mkEndpointOpt name addr port) // {
keys = mkOption {
type = types.str;
default = "";
type = with types; nullOr str;
default = keyloc;
description = ''
File to persist ${lib.toUpper name} keys.
'';
};
inbound = i2cpOpts name;
outbound = i2cpOpts name;
latency.min = mkOption {
type = with types; nullOr int;
description = "Min latency for tunnels.";
default = null;
};
latency.max = mkOption {
type = with types; nullOr int;
description = "Max latency for tunnels.";
default = null;
};
};
commonTunOpts = let
i2cpOpts = {
length = mkOption {
type = types.int;
description = "Guaranteed minimum hops.";
default = 3;
};
quantity = mkOption {
type = types.int;
description = "Number of simultaneous tunnels.";
default = 5;
};
};
in name: {
outbound = i2cpOpts;
inbound = i2cpOpts;
commonTunOpts = name: {
outbound = i2cpOpts name;
inbound = i2cpOpts name;
crypto.tagsToSend = mkOption {
type = types.int;
description = "Number of ElGamal/AES tags to send.";
@ -70,94 +93,142 @@ let
};
} // mkEndpointOpt name "127.0.0.1" 0;
i2pdConf = pkgs.writeText "i2pd.conf" ''
# DO NOT EDIT -- this file has been generated automatically.
loglevel = ${cfg.logLevel}
ipv4 = ${boolToString cfg.enableIPv4}
ipv6 = ${boolToString cfg.enableIPv6}
notransit = ${boolToString cfg.notransit}
floodfill = ${boolToString cfg.floodfill}
netid = ${toString cfg.netid}
${if isNull cfg.bandwidth then "" else "bandwidth = ${toString cfg.bandwidth}" }
${if isNull cfg.port then "" else "port = ${toString cfg.port}"}
[limits]
transittunnels = ${toString cfg.limits.transittunnels}
[upnp]
enabled = ${boolToString cfg.upnp.enable}
name = ${cfg.upnp.name}
[precomputation]
elgamal = ${boolToString cfg.precomputation.elgamal}
[reseed]
verify = ${boolToString cfg.reseed.verify}
file = ${cfg.reseed.file}
urls = ${builtins.concatStringsSep "," cfg.reseed.urls}
[addressbook]
defaulturl = ${cfg.addressbook.defaulturl}
subscriptions = ${builtins.concatStringsSep "," cfg.addressbook.subscriptions}
${flip concatMapStrings
sec = name: "\n[" + name + "]";
notice = "# DO NOT EDIT -- this file has been generated automatically.";
i2pdConf = let
opts = [
notice
(strOpt "loglevel" cfg.logLevel)
(boolOpt "logclftime" cfg.logCLFTime)
(boolOpt "ipv4" cfg.enableIPv4)
(boolOpt "ipv6" cfg.enableIPv6)
(boolOpt "notransit" cfg.notransit)
(boolOpt "floodfill" cfg.floodfill)
(intOpt "netid" cfg.netid)
] ++ (optionalNullInt "bandwidth" cfg.bandwidth)
++ (optionalNullInt "port" cfg.port)
++ (optionalNullString "family" cfg.family)
++ (optionalNullString "datadir" cfg.dataDir)
++ (optionalNullInt "share" cfg.share)
++ (optionalNullBool "ssu" cfg.ssu)
++ (optionalNullBool "ntcp" cfg.ntcp)
++ (optionalNullString "ntcpproxy" cfg.ntcpProxy)
++ (optionalNullString "ifname" cfg.ifname)
++ (optionalNullString "ifname4" cfg.ifname4)
++ (optionalNullString "ifname6" cfg.ifname6)
++ [
(sec "limits")
(intOpt "transittunnels" cfg.limits.transittunnels)
(intOpt "coresize" cfg.limits.coreSize)
(intOpt "openfiles" cfg.limits.openFiles)
(intOpt "ntcphard" cfg.limits.ntcpHard)
(intOpt "ntcpsoft" cfg.limits.ntcpSoft)
(intOpt "ntcpthreads" cfg.limits.ntcpThreads)
(sec "upnp")
(boolOpt "enabled" cfg.upnp.enable)
(sec "precomputation")
(boolOpt "elgamal" cfg.precomputation.elgamal)
(sec "reseed")
(boolOpt "verify" cfg.reseed.verify)
] ++ (optionalNullString "file" cfg.reseed.file)
++ (optionalEmptyList "urls" cfg.reseed.urls)
++ (optionalNullString "floodfill" cfg.reseed.floodfill)
++ (optionalNullString "zipfile" cfg.reseed.zipfile)
++ (optionalNullString "proxy" cfg.reseed.proxy)
++ [
(sec "trust")
(boolOpt "enabled" cfg.trust.enable)
(boolOpt "hidden" cfg.trust.hidden)
] ++ (optionalEmptyList "routers" cfg.trust.routers)
++ (optionalNullString "family" cfg.trust.family)
++ [
(sec "websockets")
(boolOpt "enabled" cfg.websocket.enable)
(strOpt "address" cfg.websocket.address)
(intOpt "port" cfg.websocket.port)
(sec "exploratory")
(intOpt "inbound.length" cfg.exploratory.inbound.length)
(intOpt "inbound.quantity" cfg.exploratory.inbound.quantity)
(intOpt "outbound.length" cfg.exploratory.outbound.length)
(intOpt "outbound.quantity" cfg.exploratory.outbound.quantity)
(sec "ntcp2")
(boolOpt "enabled" cfg.ntcp2.enable)
(boolOpt "published" cfg.ntcp2.published)
(intOpt "port" cfg.ntcp2.port)
(sec "addressbook")
(strOpt "defaulturl" cfg.addressbook.defaulturl)
] ++ (optionalEmptyList "subscriptions" cfg.addressbook.subscriptions)
++ (flip map
(collect (proto: proto ? port && proto ? address && proto ? name) cfg.proto)
(proto: ''
[${proto.name}]
enabled = ${boolToString proto.enable}
address = ${proto.address}
port = ${toString proto.port}
${if proto ? keys then "keys = ${proto.keys}" else ""}
${if proto ? auth then "auth = ${boolToString proto.auth}" else ""}
${if proto ? user then "user = ${proto.user}" else ""}
${if proto ? pass then "pass = ${proto.pass}" else ""}
${if proto ? outproxy then "outproxy = ${proto.outproxy}" else ""}
${if proto ? outproxyPort then "outproxyport = ${toString proto.outproxyPort}" else ""}
'')
}
'';
(proto: let protoOpts = [
(sec proto.name)
(boolOpt "enabled" proto.enable)
(strOpt "address" proto.address)
(intOpt "port" proto.port)
] ++ (if proto ? keys then optionalNullString "keys" proto.keys else [])
++ (if proto ? auth then optionalNullBool "auth" proto.auth else [])
++ (if proto ? user then optionalNullString "user" proto.user else [])
++ (if proto ? pass then optionalNullString "pass" proto.pass else [])
++ (if proto ? strictHeaders then optionalNullBool "strictheaders" proto.strictHeaders else [])
++ (if proto ? hostname then optionalNullString "hostname" proto.hostname else [])
++ (if proto ? outproxy then optionalNullString "outproxy" proto.outproxy else [])
++ (if proto ? outproxyPort then optionalNullInt "outproxyport" proto.outproxyPort else [])
++ (if proto ? outproxyEnable then optionalNullBool "outproxy.enabled" proto.outproxyEnable else []);
in (concatStringsSep "\n" protoOpts)
));
in
pkgs.writeText "i2pd.conf" (concatStringsSep "\n" opts);
i2pdTunnelConf = pkgs.writeText "i2pd-tunnels.conf" ''
# DO NOT EDIT -- this file has been generated automatically.
${flip concatMapStrings
tunnelConf = let opts = [
notice
(flip map
(collect (tun: tun ? port && tun ? destination) cfg.outTunnels)
(tun: ''
[${tun.name}]
type = client
destination = ${tun.destination}
destinationport = ${toString tun.destinationPort}
keys = ${tun.keys}
address = ${tun.address}
port = ${toString tun.port}
inbound.length = ${toString tun.inbound.length}
outbound.length = ${toString tun.outbound.length}
inbound.quantity = ${toString tun.inbound.quantity}
outbound.quantity = ${toString tun.outbound.quantity}
crypto.tagsToSend = ${toString tun.crypto.tagsToSend}
'')
}
${flip concatMapStrings
(tun: let outTunOpts = [
(sec tun.name)
"type = client"
(intOpt "port" tun.port)
(strOpt "destination" tun.destination)
] ++ (if tun ? destinationPort then optionalNullInt "destinationport" tun.destinationPort else [])
++ (if tun ? keys then
optionalNullString "keys" tun.keys else [])
++ (if tun ? address then
optionalNullString "address" tun.address else [])
++ (if tun ? inbound.length then
optionalNullInt "inbound.length" tun.inbound.length else [])
++ (if tun ? inbound.quantity then
optionalNullInt "inbound.quantity" tun.inbound.quantity else [])
++ (if tun ? outbound.length then
optionalNullInt "outbound.length" tun.outbound.length else [])
++ (if tun ? outbound.quantity then
optionalNullInt "outbound.quantity" tun.outbound.quantity else [])
++ (if tun ? crypto.tagsToSend then
optionalNullInt "crypto.tagstosend" tun.crypto.tagsToSend else []);
in concatStringsSep "\n" outTunOpts))
(flip map
(collect (tun: tun ? port && tun ? address) cfg.inTunnels)
(tun: ''
[${tun.name}]
type = server
destination = ${tun.destination}
keys = ${tun.keys}
host = ${tun.address}
port = ${toString tun.port}
inport = ${toString tun.inPort}
accesslist = ${builtins.concatStringsSep "," tun.accessList}
'')
}
'';
(tun: let inTunOpts = [
(sec tun.name)
"type = server"
(intOpt "port" tun.port)
(strOpt "host" tun.address)
] ++ (if tun ? destination then
optionalNullString "destination" tun.destination else [])
++ (if tun ? keys then
optionalNullString "keys" tun.keys else [])
++ (if tun ? inPort then
optionalNullInt "inport" tun.inPort else [])
++ (if tun ? accessList then
optionalEmptyList "accesslist" tun.accessList else []);
in concatStringsSep "\n" inTunOpts))];
in pkgs.writeText "i2pd-tunnels.conf" opts;
i2pdSh = pkgs.writeScriptBin "i2pd" ''
#!/bin/sh
exec ${pkgs.i2pd}/bin/i2pd \
${if isNull cfg.address then "" else "--host="+cfg.address} \
--service \
--conf=${i2pdConf} \
--tunconf=${i2pdTunnelConf}
--tunconf=${tunnelConf}
'';
in
@ -170,9 +241,7 @@ in
services.i2pd = {
enable = mkOption {
type = types.bool;
default = false;
enable = mkEnableOption "I2Pd daemon" // {
description = ''
Enables I2Pd as a running service upon activation.
Please read http://i2pd.readthedocs.io/en/latest/ for further
@ -192,6 +261,8 @@ in
'';
};
logCLFTime = mkEnableOption "Full CLF-formatted date and time to log";
address = mkOption {
type = with types; nullOr str;
default = null;
@ -200,17 +271,72 @@ in
'';
};
notransit = mkOption {
type = types.bool;
default = false;
family = mkOption {
type = with types; nullOr str;
default = null;
description = ''
Specify a family the router belongs to.
'';
};
dataDir = mkOption {
type = with types; nullOr str;
default = null;
description = ''
Alternative path to storage of i2pd data (RI, keys, peer profiles, ...)
'';
};
share = mkOption {
type = types.int;
default = 100;
description = ''
Limit of transit traffic from max bandwidth in percents.
'';
};
ifname = mkOption {
type = with types; nullOr str;
default = null;
description = ''
Network interface to bind to.
'';
};
ifname4 = mkOption {
type = with types; nullOr str;
default = null;
description = ''
IPv4 interface to bind to.
'';
};
ifname6 = mkOption {
type = with types; nullOr str;
default = null;
description = ''
IPv6 interface to bind to.
'';
};
ntcpProxy = mkOption {
type = with types; nullOr str;
default = null;
description = ''
Proxy URL for NTCP transport.
'';
};
ntcp = mkEnableTrueOption "ntcp";
ssu = mkEnableTrueOption "ssu";
notransit = mkEnableOption "notransit" // {
description = ''
Tells the router to not accept transit tunnels during startup.
'';
};
floodfill = mkOption {
type = types.bool;
default = false;
floodfill = mkEnableOption "floodfill" // {
description = ''
If the router is declared to be unreachable and needs introduction nodes.
'';
@ -241,51 +367,20 @@ in
'';
};
enableIPv4 = mkOption {
type = types.bool;
default = true;
enableIPv4 = mkEnableTrueOption "IPv4 connectivity";
enableIPv6 = mkEnableOption "IPv6 connectivity";
nat = mkEnableTrueOption "NAT bypass";
upnp.enable = mkEnableOption "UPnP service discovery";
upnp.name = mkOption {
type = types.str;
default = "I2Pd";
description = ''
Enables IPv4 connectivity. Enabled by default.
Name i2pd appears in UPnP forwardings list.
'';
};
enableIPv6 = mkOption {
type = types.bool;
default = false;
description = ''
Enables IPv6 connectivity. Disabled by default.
'';
};
nat = mkOption {
type = types.bool;
default = true;
description = ''
Assume router is NATed. Enabled by default.
'';
};
upnp = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Enables UPnP.
'';
};
name = mkOption {
type = types.str;
default = "I2Pd";
description = ''
Name i2pd appears in UPnP forwardings list.
'';
};
};
precomputation.elgamal = mkOption {
type = types.bool;
default = true;
precomputation.elgamal = mkEnableTrueOption "Precomputed ElGamal tables" // {
description = ''
Whenever to use precomputated tables for ElGamal.
<command>i2pd</command> defaults to <literal>false</literal>
@ -296,76 +391,154 @@ in
'';
};
reseed = {
verify = mkOption {
type = types.bool;
default = false;
description = ''
Request SU3 signature verification
'';
};
reseed.verify = mkEnableOption "SU3 signature verification";
file = mkOption {
type = types.str;
default = "";
description = ''
Full path to SU3 file to reseed from
'';
};
urls = mkOption {
type = with types; listOf str;
default = [
"https://reseed.i2p-project.de/"
"https://i2p.mooo.com/netDb/"
"https://netdb.i2p2.no/"
"https://us.reseed.i2p2.no:444/"
"https://uk.reseed.i2p2.no:444/"
"https://i2p.manas.ca:8443/"
];
description = ''
Reseed URLs
'';
};
reseed.file = mkOption {
type = with types; nullOr str;
default = null;
description = ''
Full path to SU3 file to reseed from.
'';
};
addressbook = {
defaulturl = mkOption {
type = types.str;
default = "http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt";
description = ''
AddressBook subscription URL for initial setup
'';
};
subscriptions = mkOption {
type = with types; listOf str;
default = [
"http://inr.i2p/export/alive-hosts.txt"
"http://i2p-projekt.i2p/hosts.txt"
"http://stats.i2p/cgi-bin/newhosts.txt"
];
description = ''
AddressBook subscription URLs
'';
};
reseed.urls = mkOption {
type = with types; listOf str;
default = [];
description = ''
Reseed URLs.
'';
};
reseed.floodfill = mkOption {
type = with types; nullOr str;
default = null;
description = ''
Path to router info of floodfill to reseed from.
'';
};
reseed.zipfile = mkOption {
type = with types; nullOr str;
default = null;
description = ''
Path to local .zip file to reseed from.
'';
};
reseed.proxy = mkOption {
type = with types; nullOr str;
default = null;
description = ''
URL for reseed proxy, supports http/socks.
'';
};
addressbook.defaulturl = mkOption {
type = types.str;
default = "http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt";
description = ''
AddressBook subscription URL for initial setup
'';
};
addressbook.subscriptions = mkOption {
type = with types; listOf str;
default = [
"http://inr.i2p/export/alive-hosts.txt"
"http://i2p-projekt.i2p/hosts.txt"
"http://stats.i2p/cgi-bin/newhosts.txt"
];
description = ''
AddressBook subscription URLs
'';
};
trust.enable = mkEnableOption "Explicit trust options";
trust.family = mkOption {
type = with types; nullOr str;
default = null;
description = ''
Router Familiy to trust for first hops.
'';
};
trust.routers = mkOption {
type = with types; listOf str;
default = [];
description = ''
Only connect to the listed routers.
'';
};
trust.hidden = mkEnableOption "Router concealment.";
websocket = mkEndpointOpt "websockets" "127.0.0.1" 7666;
exploratory.inbound = i2cpOpts "exploratory";
exploratory.outbound = i2cpOpts "exploratory";
ntcp2.enable = mkEnableTrueOption "NTCP2.";
ntcp2.published = mkEnableOption "NTCP2 publication.";
ntcp2.port = mkOption {
type = types.int;
default = 0;
description = ''
Port to listen for incoming NTCP2 connections (0=auto).
'';
};
limits.transittunnels = mkOption {
type = types.int;
default = 2500;
description = ''
Maximum number of active transit sessions
Maximum number of active transit sessions.
'';
};
limits.coreSize = mkOption {
type = types.int;
default = 0;
description = ''
Maximum size of corefile in Kb (0 - use system limit).
'';
};
limits.openFiles = mkOption {
type = types.int;
default = 0;
description = ''
Maximum number of open files (0 - use system default).
'';
};
limits.ntcpHard = mkOption {
type = types.int;
default = 0;
description = ''
Maximum number of active transit sessions.
'';
};
limits.ntcpSoft = mkOption {
type = types.int;
default = 0;
description = ''
Threshold to start probabalistic backoff with ntcp sessions (default: use system limit).
'';
};
limits.ntcpThreads = mkOption {
type = types.int;
default = 1;
description = ''
Maximum number of threads used by NTCP DH worker.
'';
};
proto.http = (mkEndpointOpt "http" "127.0.0.1" 7070) // {
auth = mkOption {
type = types.bool;
default = false;
description = ''
Enable authentication for webconsole.
'';
};
auth = mkEnableOption "Webconsole authentication";
user = mkOption {
type = types.str;
default = "i2pd";
@ -373,6 +546,7 @@ in
Username for webconsole access
'';
};
pass = mkOption {
type = types.str;
default = "i2pd";
@ -380,11 +554,35 @@ in
Password for webconsole access.
'';
};
strictHeaders = mkOption {
type = with types; nullOr bool;
default = null;
description = ''
Enable strict host checking on WebUI.
'';
};
hostname = mkOption {
type = with types; nullOr str;
default = null;
description = ''
Expected hostname for WebUI.
'';
};
};
proto.httpProxy = mkKeyedEndpointOpt "httpproxy" "127.0.0.1" 4444 "";
proto.socksProxy = (mkKeyedEndpointOpt "socksproxy" "127.0.0.1" 4447 "")
proto.httpProxy = (mkKeyedEndpointOpt "httpproxy" "127.0.0.1" 4444 "httpproxy-keys.dat")
// {
outproxy = mkOption {
type = with types; nullOr str;
default = null;
description = "Upstream outproxy bind address.";
};
};
proto.socksProxy = (mkKeyedEndpointOpt "socksproxy" "127.0.0.1" 4447 "socksproxy-keys.dat")
// {
outproxyEnable = mkEnableOption "SOCKS outproxy";
outproxy = mkOption {
type = types.str;
default = "127.0.0.1";
@ -408,8 +606,8 @@ in
{ name, ... }: {
options = {
destinationPort = mkOption {
type = types.int;
default = 0;
type = with types; nullOr int;
default = null;
description = "Connect to particular port at destination.";
};
} // commonTunOpts name;