Merge pull request #3241 from ehmry/cjdns
cjdns declarative configuration
This commit is contained in:
commit
a6dfb4dc28
@ -1,13 +1,3 @@
|
|||||||
# You may notice the commented out sections in this file,
|
|
||||||
# it would be great to configure cjdns from nix, but cjdns
|
|
||||||
# reads its configuration from stdin, including the private
|
|
||||||
# key and admin password, all nested in a JSON structure.
|
|
||||||
#
|
|
||||||
# Until a good method of storing the keys outside the nix
|
|
||||||
# store and mixing them back into a string is devised
|
|
||||||
# (without too much shell hackery), a skeleton of the
|
|
||||||
# configuration building lies commented out.
|
|
||||||
|
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
@ -16,41 +6,35 @@ let
|
|||||||
|
|
||||||
cfg = config.services.cjdns;
|
cfg = config.services.cjdns;
|
||||||
|
|
||||||
/*
|
# would be nice to merge 'cfg' with a //,
|
||||||
# can't keep keys and passwords in the nix store,
|
# but the json nesting is wacky.
|
||||||
# but don't want to deal with this stdin quagmire.
|
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 [ ];
|
||||||
|
};
|
||||||
|
|
||||||
cjdrouteConf = '' {
|
privateKey = "@CJDNS_PRIVATE_KEY@";
|
||||||
"admin": {"bind": "${cfg.admin.bind}", "password": "\${CJDNS_ADMIN}" },
|
|
||||||
"privateKey": "\${CJDNS_KEY}",
|
|
||||||
|
|
||||||
"interfaces": {
|
resetAfterInactivitySeconds = 100;
|
||||||
''
|
|
||||||
|
|
||||||
+ optionalString (cfg.interfaces.udp.bind.address != null) ''
|
router = {
|
||||||
"UDPInterface": [ {
|
interface = { type = "TUNInterface"; };
|
||||||
"bind": "${cfg.interfaces.udp.bind.address}:"''
|
ipTunnel = {
|
||||||
${if cfg.interfaces.upd.bind.port != null
|
allowedConnections = [];
|
||||||
then ${toString cfg.interfaces.udp.bind.port}
|
outgoingConnections = [];
|
||||||
else ${RANDOM}
|
};
|
||||||
fi)
|
};
|
||||||
+ '' } ]''
|
|
||||||
|
|
||||||
+ (if cfg.interfaces.eth.bind != null then ''
|
security = [ { exemptAngel = 1; setuser = "nobody"; } ];
|
||||||
"ETHInterface": [ {
|
|
||||||
"bind": "${cfg.interfaces.eth.bind}",
|
});
|
||||||
"beacon": ${toString cfg.interfaces.eth.beacon}
|
|
||||||
} ]
|
|
||||||
'' fi )
|
|
||||||
+ ''
|
|
||||||
},
|
|
||||||
"router": { "interface": { "type": "TUNInterface" }, },
|
|
||||||
"security": [ { "setuser": "nobody" } ]
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
|
|
||||||
cjdrouteConfFile = pkgs.writeText "cjdroute.conf" cjdrouteConf
|
|
||||||
*/
|
|
||||||
in
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -62,146 +46,180 @@ in
|
|||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = ''
|
description = ''
|
||||||
Enable this option to start a instance of the
|
Whether to enable the cjdns network encryption
|
||||||
cjdns network encryption and and routing engine.
|
and routing engine. A file at /etc/cjdns.keys will
|
||||||
Configuration will be read from <literal>confFile</literal>.
|
be created if it does not exist to contain a random
|
||||||
|
secret key that your IPv6 address will be derived from.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
confFile = mkOption {
|
authorizedPasswords = mkOption {
|
||||||
default = "/etc/cjdroute.conf";
|
type = types.listOf types.str;
|
||||||
description = ''
|
default = [ ];
|
||||||
Configuration file to pipe to cjdroute.
|
example = [
|
||||||
|
"snyrfgkqsc98qh1y4s5hbu0j57xw5s0"
|
||||||
|
"z9md3t4p45mfrjzdjurxn4wuj0d8swv"
|
||||||
|
"49275fut6tmzu354pq70sr5b95qq0vj"
|
||||||
|
];
|
||||||
|
description = ''
|
||||||
|
Any remote cjdns nodes that offer these passwords on
|
||||||
|
connection will be allowed to route through this node.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
admin = {
|
admin = {
|
||||||
bind = mkOption {
|
bind = mkOption {
|
||||||
|
type = types.string;
|
||||||
default = "127.0.0.1:11234";
|
default = "127.0.0.1:11234";
|
||||||
description = ''
|
description = ''
|
||||||
Bind the administration port to this address and port.
|
Bind the administration port to this address and port.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
passwordFile = mkOption {
|
UDPInterface = {
|
||||||
example = "/root/cjdns.adminPassword";
|
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.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
ETHInterface = {
|
||||||
|
bind = mkOption {
|
||||||
|
default = "";
|
||||||
|
example = "eth0";
|
||||||
description = ''
|
description = ''
|
||||||
File containing a password to the administration port.
|
Bind to this device for native ethernet operation.
|
||||||
'';
|
'';
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
keyFile = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
example = "/root/cjdns.key";
|
|
||||||
description = ''
|
|
||||||
Path to a file containing a cjdns private key on a single line.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
passwordsFile = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = null;
|
|
||||||
example = "/root/cjdns.authorizedPasswords";
|
|
||||||
description = ''
|
|
||||||
A file containing a list of json dictionaries with passwords.
|
|
||||||
For example:
|
|
||||||
{"password": "s8xf5z7znl4jt05g922n3wpk75wkypk"},
|
|
||||||
{ "name": "nice guy",
|
|
||||||
"password": "xhthk1mglz8tpjrbbvdlhyc092rhpx5"},
|
|
||||||
{"password": "3qfxyhmrht7uwzq29pmhbdm9w4bnc8w"}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
interfaces = {
|
|
||||||
udp = {
|
|
||||||
bind = {
|
|
||||||
address = mkOption {
|
|
||||||
default = "0.0.0.0";
|
|
||||||
description = ''
|
|
||||||
Address to bind UDP tunnels to; disable by setting to null;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
port = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
Port to bind UDP tunnels to.
|
|
||||||
A port will be choosen at random if this is not set.
|
|
||||||
This option is required to act as the server end of
|
|
||||||
a tunnel.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
eth = {
|
|
||||||
bind = mkOption {
|
|
||||||
default = null;
|
|
||||||
example = "eth0";
|
|
||||||
description = ''
|
|
||||||
Bind to this device and operate with native wire format.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
beacon = mkOption {
|
|
||||||
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.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
connectTo = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [];
|
|
||||||
description = ''
|
|
||||||
Credentials for connecting look similar to UDP credientials
|
|
||||||
except they begin with the mac address, for example:
|
|
||||||
"01:02:03:04:05:06":{"password":"a","publicKey":"b"}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
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.
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf config.services.cjdns.enable {
|
config = mkIf config.services.cjdns.enable {
|
||||||
|
|
||||||
boot.kernelModules = [ "tun" ];
|
boot.kernelModules = [ "tun" ];
|
||||||
|
|
||||||
/*
|
# networking.firewall.allowedUDPPorts = ...
|
||||||
networking.firewall.allowedUDPPorts = mkIf (cfg.udp.bind.port != null) [
|
|
||||||
cfg.udp.bind.port
|
|
||||||
];
|
|
||||||
*/
|
|
||||||
|
|
||||||
systemd.services.cjdns = {
|
systemd.services.cjdns = {
|
||||||
description = "encrypted networking for everybody";
|
description = "encrypted networking for everybody";
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
wants = [ "network.target" ];
|
after = [ "network-interfaces.target" ];
|
||||||
before = [ "network.target" ];
|
|
||||||
path = [ pkgs.cjdns ];
|
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" \
|
||||||
|
| ${pkgs.cjdns}/sbin/cjdroute
|
||||||
|
'';
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "forking";
|
Type = "forking";
|
||||||
ExecStart = ''
|
|
||||||
${pkgs.stdenv.shell} -c "${pkgs.cjdns}/sbin/cjdroute < ${cfg.confFile}"
|
|
||||||
'';
|
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
system.activationScripts.cjdns = ''
|
||||||
|
grep -q "CJDNS_PRIVATE_KEY=" /etc/cjdns.keys || \
|
||||||
|
echo "CJDNS_PRIVATE_KEY=$(${pkgs.cjdns}/sbin/makekey)" \
|
||||||
|
>> /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";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
@ -1,21 +1,27 @@
|
|||||||
{ stdenv, fetchgit, nodejs, which, python27 }:
|
{ stdenv, fetchgit, nodejs, which, python27 }:
|
||||||
|
|
||||||
let
|
let
|
||||||
date = "20140303";
|
date = "20140829";
|
||||||
rev = "f11ce1fd4795b0173ac0ef18c8a6f752aa824adb";
|
rev = "9595d67f9edd759054c5bd3aaee0968ff55e361a";
|
||||||
in
|
in
|
||||||
stdenv.mkDerivation {
|
stdenv.mkDerivation {
|
||||||
name = "cjdns-${date}-${stdenv.lib.strings.substring 0 7 rev}";
|
name = "cjdns-${date}-${stdenv.lib.strings.substring 0 7 rev}";
|
||||||
|
|
||||||
src = fetchgit {
|
src = fetchgit {
|
||||||
url = "git://github.com/cjdelisle/cjdns.git";
|
url = "https://github.com/cjdelisle/cjdns.git";
|
||||||
inherit rev;
|
inherit rev;
|
||||||
sha256 = "1bxhf9f1v0slf9mz3ll6jf45mkwvwxlf3yqxx9k23kjyr1nsc8s8";
|
sha256 = "519c549c42ae26c5359ae13a4548c44b51e36db403964b4d9f78c19b749dfb83";
|
||||||
};
|
};
|
||||||
|
|
||||||
buildInputs = [ which python27 nodejs];
|
buildInputs = [ which python27 nodejs];
|
||||||
|
|
||||||
builder = ./builder.sh;
|
patches = [ ./makekey.patch ];
|
||||||
|
|
||||||
|
buildPhase = "bash do";
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out/sbin
|
||||||
|
cp cjdroute makekey $out/sbin
|
||||||
|
'';
|
||||||
|
|
||||||
meta = {
|
meta = {
|
||||||
homepage = https://github.com/cjdelisle/cjdns;
|
homepage = https://github.com/cjdelisle/cjdns;
|
||||||
|
64
pkgs/tools/networking/cjdns/makekey.patch
Normal file
64
pkgs/tools/networking/cjdns/makekey.patch
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
diff --git a/contrib/c/makekey.c b/contrib/c/makekey.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..c7184e5
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/contrib/c/makekey.c
|
||||||
|
@@ -0,0 +1,46 @@
|
||||||
|
+/* vim: set expandtab ts=4 sw=4: */
|
||||||
|
+/*
|
||||||
|
+ * You may redistribute this program and/or modify it under the terms of
|
||||||
|
+ * the GNU General Public License as published by the Free Software Foundation,
|
||||||
|
+ * either version 3 of the License, or (at your option) any later version.
|
||||||
|
+ *
|
||||||
|
+ * This program is distributed in the hope that it will be useful,
|
||||||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
+ * GNU General Public License for more details.
|
||||||
|
+ *
|
||||||
|
+ * You should have received a copy of the GNU General Public License
|
||||||
|
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
+ */
|
||||||
|
+#include "crypto/random/Random.h"
|
||||||
|
+#include "memory/MallocAllocator.h"
|
||||||
|
+#include "crypto/AddressCalc.h"
|
||||||
|
+#include "util/AddrTools.h"
|
||||||
|
+#include "util/Hex.h"
|
||||||
|
+
|
||||||
|
+#include "crypto_scalarmult_curve25519.h"
|
||||||
|
+
|
||||||
|
+#include <stdio.h>
|
||||||
|
+
|
||||||
|
+int main(int argc, char** argv)
|
||||||
|
+{
|
||||||
|
+ struct Allocator* alloc = MallocAllocator_new(1<<22);
|
||||||
|
+ struct Random* rand = Random_new(alloc, NULL, NULL);
|
||||||
|
+
|
||||||
|
+ uint8_t privateKey[32];
|
||||||
|
+ uint8_t publicKey[32];
|
||||||
|
+ uint8_t ip[16];
|
||||||
|
+ uint8_t hexPrivateKey[65];
|
||||||
|
+
|
||||||
|
+ for (;;) {
|
||||||
|
+ Random_bytes(rand, privateKey, 32);
|
||||||
|
+ crypto_scalarmult_curve25519_base(publicKey, privateKey);
|
||||||
|
+ if (AddressCalc_addressForPublicKey(ip, publicKey)) {
|
||||||
|
+ Hex_encode(hexPrivateKey, 65, privateKey, 32);
|
||||||
|
+ printf(hexPrivateKey);
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
diff --git a/node_build/make.js b/node_build/make.js
|
||||||
|
index 5e51645..11465e3 100644
|
||||||
|
--- a/node_build/make.js
|
||||||
|
+++ b/node_build/make.js
|
||||||
|
@@ -339,6 +339,7 @@ Builder.configure({
|
||||||
|
builder.buildExecutable('contrib/c/privatetopublic.c');
|
||||||
|
builder.buildExecutable('contrib/c/sybilsim.c');
|
||||||
|
builder.buildExecutable('contrib/c/makekeys.c');
|
||||||
|
+ builder.buildExecutable('contrib/c/makekey.c');
|
||||||
|
|
||||||
|
builder.buildExecutable('crypto/random/randombytes.c');
|
||||||
|
|
Loading…
Reference in New Issue
Block a user