2014-04-14 14:26:48 +00:00
|
|
|
{ config, lib, pkgs, ... }:
|
2014-03-23 01:38:04 +00:00
|
|
|
|
2014-04-14 14:26:48 +00:00
|
|
|
with lib;
|
2014-03-23 01:38:04 +00:00
|
|
|
|
|
|
|
let
|
|
|
|
|
|
|
|
cfg = config.services.cjdns;
|
|
|
|
|
2014-08-31 19:42:38 +00:00
|
|
|
# would be nice to merge 'cfg' with a //,
|
|
|
|
# but the json nesting is wacky.
|
|
|
|
cjdrouteConf = builtins.toJSON ( {
|
|
|
|
admin = {
|
|
|
|
bind = cfg.admin.bind;
|
|
|
|
password = "@CJDNS_ADMIN_PASSWORD@";
|
|
|
|
};
|
|
|
|
authorizedPasswords = map (p: { password = p; }) cfg.authorizedPasswords;
|
|
|
|
interfaces = {
|
|
|
|
ETHInterface = if (cfg.ETHInterface.bind != "") then [ cfg.ETHInterface ] else [ ];
|
|
|
|
UDPInterface = if (cfg.UDPInterface.bind != "") then [ cfg.UDPInterface ] else [ ];
|
|
|
|
};
|
|
|
|
|
|
|
|
privateKey = "@CJDNS_PRIVATE_KEY@";
|
|
|
|
|
|
|
|
resetAfterInactivitySeconds = 100;
|
|
|
|
|
|
|
|
router = {
|
|
|
|
interface = { type = "TUNInterface"; };
|
|
|
|
ipTunnel = {
|
|
|
|
allowedConnections = [];
|
|
|
|
outgoingConnections = [];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
security = [ { exemptAngel = 1; setuser = "nobody"; } ];
|
|
|
|
|
|
|
|
});
|
|
|
|
|
2014-03-23 01:38:04 +00:00
|
|
|
in
|
|
|
|
|
|
|
|
{
|
|
|
|
options = {
|
|
|
|
|
|
|
|
services.cjdns = {
|
|
|
|
|
|
|
|
enable = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
description = ''
|
2014-08-31 19:42:38 +00:00
|
|
|
Whether to enable the cjdns network encryption
|
|
|
|
and routing engine. A file at /etc/cjdns.keys will
|
|
|
|
be created if it does not exist to contain a random
|
|
|
|
secret key that your IPv6 address will be derived from.
|
2014-03-23 01:38:04 +00:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2014-08-31 19:42:38 +00:00
|
|
|
authorizedPasswords = mkOption {
|
|
|
|
type = types.listOf types.str;
|
|
|
|
default = [ ];
|
|
|
|
example = [
|
|
|
|
"snyrfgkqsc98qh1y4s5hbu0j57xw5s0"
|
|
|
|
"z9md3t4p45mfrjzdjurxn4wuj0d8swv"
|
|
|
|
"49275fut6tmzu354pq70sr5b95qq0vj"
|
|
|
|
];
|
|
|
|
description = ''
|
|
|
|
Any remote cjdns nodes that offer these passwords on
|
|
|
|
connection will be allowed to route through this node.
|
2014-03-23 01:38:04 +00:00
|
|
|
'';
|
|
|
|
};
|
2014-08-31 19:42:38 +00:00
|
|
|
|
2014-03-23 01:38:04 +00:00
|
|
|
admin = {
|
|
|
|
bind = mkOption {
|
2014-08-31 19:42:38 +00:00
|
|
|
type = types.string;
|
2014-03-23 01:38:04 +00:00
|
|
|
default = "127.0.0.1:11234";
|
|
|
|
description = ''
|
|
|
|
Bind the administration port to this address and port.
|
|
|
|
'';
|
|
|
|
};
|
2014-08-31 19:42:38 +00:00
|
|
|
};
|
2014-03-23 01:38:04 +00:00
|
|
|
|
2014-08-31 19:42:38 +00:00
|
|
|
UDPInterface = {
|
|
|
|
bind = mkOption {
|
|
|
|
type = types.string;
|
|
|
|
default = "";
|
|
|
|
example = "192.168.1.32:43211";
|
|
|
|
description = ''
|
|
|
|
Address and port to bind UDP tunnels to.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
connectTo = mkOption {
|
|
|
|
type = types.attrsOf ( types.submodule (
|
|
|
|
{ options, ... }:
|
|
|
|
{ options = {
|
|
|
|
# TODO make host an option, and add it to networking.extraHosts
|
|
|
|
password = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
description = "Authorized password to the opposite end of the tunnel.";
|
|
|
|
};
|
|
|
|
publicKey = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
description = "Public key at the opposite end of the tunnel.";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
));
|
|
|
|
default = { };
|
|
|
|
example = {
|
|
|
|
"192.168.1.1:27313" = {
|
|
|
|
password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
|
|
|
|
publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
description = ''
|
|
|
|
Credentials for making UDP tunnels.
|
2014-03-23 01:38:04 +00:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2014-08-31 19:42:38 +00:00
|
|
|
ETHInterface = {
|
|
|
|
bind = mkOption {
|
|
|
|
default = "";
|
|
|
|
example = "eth0";
|
|
|
|
description = ''
|
|
|
|
Bind to this device for native ethernet operation.
|
2014-03-23 01:38:04 +00:00
|
|
|
'';
|
2014-08-31 19:42:38 +00:00
|
|
|
};
|
2014-03-23 01:38:04 +00:00
|
|
|
|
2014-08-31 19:42:38 +00:00
|
|
|
beacon = mkOption {
|
|
|
|
type = types.int;
|
|
|
|
default = 2;
|
|
|
|
description = ''
|
|
|
|
Auto-connect to other cjdns nodes on the same network.
|
|
|
|
Options:
|
|
|
|
0: Disabled.
|
|
|
|
1: Accept beacons, this will cause cjdns to accept incoming
|
|
|
|
beacon messages and try connecting to the sender.
|
|
|
|
2: Accept and send beacons, this will cause cjdns to broadcast
|
|
|
|
messages on the local network which contain a randomly
|
|
|
|
generated per-session password, other nodes which have this
|
|
|
|
set to 1 or 2 will hear the beacon messages and connect
|
|
|
|
automatically.
|
|
|
|
'';
|
2014-03-23 01:38:04 +00:00
|
|
|
};
|
2014-08-31 19:42:38 +00:00
|
|
|
|
|
|
|
connectTo = mkOption {
|
|
|
|
type = types.attrsOf ( types.submodule (
|
|
|
|
{ options, ... }:
|
|
|
|
{ options = {
|
|
|
|
password = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
description = "Authorized password to the opposite end of the tunnel.";
|
|
|
|
};
|
|
|
|
publicKey = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
description = "Public key at the opposite end of the tunnel.";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
));
|
|
|
|
default = { };
|
|
|
|
example = {
|
|
|
|
"01:02:03:04:05:06" = {
|
|
|
|
password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
|
|
|
|
publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
description = ''
|
|
|
|
Credentials for connecting look similar to UDP credientials
|
|
|
|
except they begin with the mac address.
|
|
|
|
'';
|
|
|
|
};
|
2014-03-23 01:38:04 +00:00
|
|
|
};
|
2014-08-31 19:42:38 +00:00
|
|
|
|
2014-03-23 01:38:04 +00:00
|
|
|
};
|
2014-08-31 19:42:38 +00:00
|
|
|
|
2014-03-23 01:38:04 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf config.services.cjdns.enable {
|
|
|
|
|
|
|
|
boot.kernelModules = [ "tun" ];
|
|
|
|
|
2014-08-31 19:42:38 +00:00
|
|
|
# networking.firewall.allowedUDPPorts = ...
|
2014-03-23 01:38:04 +00:00
|
|
|
|
|
|
|
systemd.services.cjdns = {
|
|
|
|
description = "encrypted networking for everybody";
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
2014-08-31 19:42:38 +00:00
|
|
|
after = [ "network-interfaces.target" ];
|
|
|
|
|
|
|
|
script = ''
|
|
|
|
source /etc/cjdns.keys
|
|
|
|
echo '${cjdrouteConf}' | sed \
|
|
|
|
-e "s/@CJDNS_ADMIN_PASSWORD@/$CJDNS_ADMIN_PASSWORD/g" \
|
|
|
|
-e "s/@CJDNS_PRIVATE_KEY@/$CJDNS_PRIVATE_KEY/g" \
|
2014-09-23 17:53:35 +00:00
|
|
|
| ${pkgs.cjdns}/bin/cjdroute
|
2014-08-31 19:42:38 +00:00
|
|
|
'';
|
2014-03-23 01:38:04 +00:00
|
|
|
|
|
|
|
serviceConfig = {
|
|
|
|
Type = "forking";
|
|
|
|
Restart = "on-failure";
|
|
|
|
};
|
|
|
|
};
|
2014-08-31 19:42:38 +00:00
|
|
|
|
|
|
|
system.activationScripts.cjdns = ''
|
|
|
|
grep -q "CJDNS_PRIVATE_KEY=" /etc/cjdns.keys || \
|
2014-09-23 17:53:35 +00:00
|
|
|
echo "CJDNS_PRIVATE_KEY=$(${pkgs.cjdns}/bin/makekey)" \
|
2014-08-31 19:42:38 +00:00
|
|
|
>> /etc/cjdns.keys
|
|
|
|
|
|
|
|
grep -q "CJDNS_ADMIN_PASSWORD=" /etc/cjdns.keys || \
|
|
|
|
echo "CJDNS_ADMIN_PASSWORD=$(${pkgs.coreutils}/bin/head -c 96 /dev/urandom | ${pkgs.coreutils}/bin/tr -dc A-Za-z0-9)" \
|
|
|
|
>> /etc/cjdns.keys
|
|
|
|
|
|
|
|
chmod 600 /etc/cjdns.keys
|
|
|
|
'';
|
|
|
|
|
|
|
|
assertions = [
|
|
|
|
{ assertion = ( cfg.ETHInterface.bind != "" || cfg.UDPInterface.bind != "" );
|
|
|
|
message = "Neither cjdns.ETHInterface.bind nor cjdns.UDPInterface.bind defined.";
|
|
|
|
}
|
|
|
|
{ assertion = config.networking.enableIPv6;
|
|
|
|
message = "networking.enableIPv6 must be enabled for CJDNS to work";
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
2014-03-23 01:38:04 +00:00
|
|
|
};
|
2014-08-31 19:42:38 +00:00
|
|
|
|
|
|
|
}
|