anchor.diff:  
     cfg = config.services.cjdns;
   
  -  /*
  -  # can't keep keys and passwords in the nix store,
  -  # but don't want to deal with this stdin quagmire.
  -
  -  cjdrouteConf = '' {
  -    "admin": {"bind": "${cfg.admin.bind}", "password": "\${CJDNS_ADMIN}" },
  -    "privateKey": "\${CJDNS_KEY}",
  -
  -    "interfaces": {
  -    ''
  -
  -    + optionalString (cfg.interfaces.udp.bind.address != null) ''
  -      "UDPInterface": [ {
  -        "bind": "${cfg.interfaces.udp.bind.address}:"''
  -	   ${if cfg.interfaces.upd.bind.port != null
  -             then ${toString cfg.interfaces.udp.bind.port}
  -	     else ${RANDOM}
  -	   fi)
  -      + '' } ]''
  -
  -    + (if cfg.interfaces.eth.bind != null then ''
  -      "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
  -    */
  +  # 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"; } ];
  +
  +  });
  +
   in
   
   {
  
positive.code: # 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, ... }:
  
  with lib;
  
negative.code:         type = types.bool;
  	default = false;
          description = ''
            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.
          '';
        };
  
        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.
          '';
        };
      
        admin = {
          bind = mkOption {
            type = types.string;
  	  default = "127.0.0.1:11234";
  	  description = ''
              Bind the administration port to this address and port.
  	  '';
          };
        };
  
        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.
  	  '';
  	};
        };
  
        ETHInterface = {
          bind = mkOption {
  	  default = "";
  	  example = "eth0";
  	  description = ''
  	    Bind to this device for native ethernet operation.
  	  '';
          };
  
          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 {
  
      boot.kernelModules = [ "tun" ];
  
      # networking.firewall.allowedUDPPorts = ...
  
      systemd.services.cjdns = {
        description = "encrypted networking for everybody";
        wantedBy = [ "multi-user.target" ];
        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" \
              | ${pkgs.cjdns}/sbin/cjdroute
        '';
  
        serviceConfig = {
          Type = "forking";
  	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";
        }
      ];
  
    };
  
  }