about summary refs log tree commit diff
path: root/nixos/modules/services/networking/cjdns.nix
blob: 9b715ec6384910b544f0fd5cb42a3f7c7f579d8b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# 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, pkgs, ... }:

with pkgs.lib;

let

  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
    */
in

{
  options = {

    services.cjdns = {

      enable = mkOption {
        type = types.bool;
	default = false;
        description = ''
          Enable this option to start a instance of the 
          cjdns network encryption and and routing engine.
          Configuration will be read from <literal>confFile</literal>.
        '';
      };

      confFile = mkOption {
	default = "/etc/cjdroute.conf";
        description = ''
          Configuration file to pipe to cjdroute.
        '';
      };

      /*
      admin = {
        bind = mkOption {
	  default = "127.0.0.1:11234";
	  description = ''
            Bind the administration port to this address and port.
	  '';
        };

	passwordFile = mkOption {
	  example = "/root/cjdns.adminPassword";
	  description = ''
	    File containing a password to the administration port.
	  '';
	};
      };

      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"}
	    '';
	  };
        };
      };
      */
    };
  };

  config = mkIf config.services.cjdns.enable {

    boot.kernelModules = [ "tun" ];

    /*
    networking.firewall.allowedUDPPorts = mkIf (cfg.udp.bind.port != null) [
      cfg.udp.bind.port
    ];
    */

    systemd.services.cjdns = {
      description = "encrypted networking for everybody";
      wantedBy = [ "multi-user.target" ];
      wants = [ "network.target" ];
      before = [ "network.target" ];
      path = [ pkgs.cjdns ];

      serviceConfig = {
        Type = "forking";
	ExecStart = ''
          ${pkgs.stdenv.shell} -c "${pkgs.cjdns}/sbin/cjdroute < ${cfg.confFile}"
	'';
	Restart = "on-failure";
      };
    };
  };
}