11 cfg = config.services.cjdns;
17 password = lib.mkOption {
19 description = "Authorized password to the opposite end of the tunnel.";
21 login = lib.mkOption {
24 description = "(optional) name your peer has for you";
26 peerName = lib.mkOption {
29 description = "(optional) human-readable name for peer";
31 publicKey = lib.mkOption {
33 description = "Public key at the opposite end of the tunnel.";
35 hostname = lib.mkOption {
37 example = "foobar.hype";
39 description = "Optional hostname to add to /etc/hosts; prevents reverse lookup failures.";
44 # Additional /etc/hosts entries for peers with an associated hostname
45 cjdnsExtraHosts = pkgs.runCommand "cjdns-hosts" { } ''
47 ${lib.concatStringsSep "\n" (
52 ) "echo $(${pkgs.cjdns}/bin/publictoip6 ${v.publicKey}) ${v.hostname}"
53 ) (cfg.ETHInterface.connectTo // cfg.UDPInterface.connectTo)
61 connectTo = lib.mapAttrs (name: value: { inherit (value) password publicKey; }) x.connectTo;
64 cjdrouteConf = builtins.toJSON (
67 bind = cfg.admin.bind;
68 password = "@CJDNS_ADMIN_PASSWORD@";
70 authorizedPasswords = map (p: { password = p; }) cfg.authorizedPasswords;
72 ETHInterface = if (cfg.ETHInterface.bind != "") then [ (parseModules cfg.ETHInterface) ] else [ ];
73 UDPInterface = if (cfg.UDPInterface.bind != "") then [ (parseModules cfg.UDPInterface) ] else [ ];
76 privateKey = "@CJDNS_PRIVATE_KEY@";
78 resetAfterInactivitySeconds = 100;
82 type = "TUNInterface";
85 allowedConnections = [ ];
86 outgoingConnections = [ ];
107 enable = lib.mkOption {
108 type = lib.types.bool;
111 Whether to enable the cjdns network encryption
112 and routing engine. A file at /etc/cjdns.keys will
113 be created if it does not exist to contain a random
114 secret key that your IPv6 address will be derived from.
118 extraConfig = lib.mkOption {
119 type = lib.types.attrs;
122 router.interface.tunDevice = "tun10";
125 Extra configuration, given as attrs, that will be merged recursively
126 with the rest of the JSON generated by this module, at the root node.
130 confFile = lib.mkOption {
131 type = lib.types.nullOr lib.types.path;
133 example = "/etc/cjdroute.conf";
135 Ignore all other cjdns options and load configuration from this file.
139 authorizedPasswords = lib.mkOption {
140 type = lib.types.listOf lib.types.str;
143 "snyrfgkqsc98qh1y4s5hbu0j57xw5s0"
144 "z9md3t4p45mfrjzdjurxn4wuj0d8swv"
145 "49275fut6tmzu354pq70sr5b95qq0vj"
148 Any remote cjdns nodes that offer these passwords on
149 connection will be allowed to route through this node.
154 bind = lib.mkOption {
155 type = lib.types.str;
156 default = "127.0.0.1:11234";
158 Bind the administration port to this address and port.
164 bind = lib.mkOption {
165 type = lib.types.str;
167 example = "192.168.1.32:43211";
169 Address and port to bind UDP tunnels to.
172 connectTo = lib.mkOption {
173 type = lib.types.attrsOf (lib.types.submodule (connectToSubmodule));
175 example = lib.literalExpression ''
177 "192.168.1.1:27313" = {
178 hostname = "homer.hype";
179 password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
180 publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
185 Credentials for making UDP tunnels.
191 bind = lib.mkOption {
192 type = lib.types.str;
196 Bind to this device for native ethernet operation.
197 `all` is a pseudo-name which will try to connect to all devices.
201 beacon = lib.mkOption {
202 type = lib.types.int;
205 Auto-connect to other cjdns nodes on the same network.
208 1: Accept beacons, this will cause cjdns to accept incoming
209 beacon messages and try connecting to the sender.
210 2: Accept and send beacons, this will cause cjdns to broadcast
211 messages on the local network which contain a randomly
212 generated per-session password, other nodes which have this
213 set to 1 or 2 will hear the beacon messages and connect
218 connectTo = lib.mkOption {
219 type = lib.types.attrsOf (lib.types.submodule (connectToSubmodule));
221 example = lib.literalExpression ''
223 "01:02:03:04:05:06" = {
224 hostname = "homer.hype";
225 password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
226 publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
231 Credentials for connecting look similar to UDP credientials
232 except they begin with the mac address.
237 addExtraHosts = lib.mkOption {
238 type = lib.types.bool;
241 Whether to add cjdns peers with an associated hostname to
242 {file}`/etc/hosts`. Beware that enabling this
243 incurs heavy eval-time costs.
251 config = lib.mkIf cfg.enable {
253 boot.kernelModules = [ "tun" ];
255 # networking.firewall.allowedUDPPorts = ...
257 systemd.services.cjdns = {
258 description = "cjdns: routing engine designed for security, scalability, speed and ease of use";
263 after = [ "network-online.target" ];
264 bindsTo = [ "network-online.target" ];
266 preStart = lib.optionalString (cfg.confFile == null) ''
267 [ -e /etc/cjdns.keys ] && source /etc/cjdns.keys
269 if [ -z "$CJDNS_PRIVATE_KEY" ]; then
271 ${pkg}/bin/makekeys | { read private ipv6 public; }
273 install -m 600 <(echo "CJDNS_PRIVATE_KEY=$private") /etc/cjdns.keys
274 install -m 444 <(echo -e "CJDNS_IPV6=$ipv6\nCJDNS_PUBLIC_KEY=$public") /etc/cjdns.public
277 if [ -z "$CJDNS_ADMIN_PASSWORD" ]; then
278 echo "CJDNS_ADMIN_PASSWORD=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 32)" \
284 if cfg.confFile != null then
285 "${pkg}/bin/cjdroute < ${cfg.confFile}"
288 source /etc/cjdns.keys
293 -e "s/@CJDNS_ADMIN_PASSWORD@/$CJDNS_ADMIN_PASSWORD/g" \
294 -e "s/@CJDNS_PRIVATE_KEY@/$CJDNS_PRIVATE_KEY/g" \
295 | ${pkg}/bin/cjdroute
299 startLimitIntervalSec = 0;
304 CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_RAW CAP_SETUID";
305 ProtectSystem = true;
306 # Doesn't work on i686, causing service to fail
307 MemoryDenyWriteExecute = !pkgs.stdenv.hostPlatform.isi686;
313 networking.hostFiles = lib.mkIf cfg.addExtraHosts [ cjdnsExtraHosts ];
317 assertion = (cfg.ETHInterface.bind != "" || cfg.UDPInterface.bind != "" || cfg.confFile != null);
318 message = "Neither cjdns.ETHInterface.bind nor cjdns.UDPInterface.bind defined.";
321 assertion = config.networking.enableIPv6;
322 message = "networking.enableIPv6 must be enabled for CJDNS to work";