router.c 25.1 KB
Newer Older
1
2
3
4
5
6
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
/* See LICENSE for licensing information */
/* $Id$ */

#include "or.h"

Roger Dingledine's avatar
Roger Dingledine committed
7
8
9
/**
 * \file router.c
 * \brief OR functionality, including key maintenance, generating
Nick Mathewson's avatar
Nick Mathewson committed
10
 * and uploading server descriptors, retrying OR connections.
Roger Dingledine's avatar
Roger Dingledine committed
11
 **/
Nick Mathewson's avatar
Nick Mathewson committed
12

13
extern or_options_t options; /* command-line and config-file options */
Roger Dingledine's avatar
Roger Dingledine committed
14
extern long stats_n_seconds_uptime;
15

16
/** Exposed for test.c. */ void get_platform_str(char *platform, int len);
17

18
19
/************************************************************/

Nick Mathewson's avatar
Nick Mathewson committed
20
21
22
23
/*****
 * Key management: ORs only.
 *****/

Roger Dingledine's avatar
Roger Dingledine committed
24
/** Private keys for this OR.  There is also an SSL key managed by tortls.c.
Nick Mathewson's avatar
Nick Mathewson committed
25
 */
26
static tor_mutex_t *key_lock=NULL;
Nick Mathewson's avatar
Nick Mathewson committed
27
static time_t onionkey_set_at=0; /* When was onionkey last changed? */
28
static crypto_pk_env_t *onionkey=NULL;
29
static crypto_pk_env_t *lastonionkey=NULL;
30
31
static crypto_pk_env_t *identitykey=NULL;

Nick Mathewson's avatar
Nick Mathewson committed
32
/** Replace the current onion key with <b>k</b>.  Does not affect lastonionkey;
Nick Mathewson's avatar
Nick Mathewson committed
33
34
 * to update onionkey correctly, call rotate_onion_key().
 */
35
void set_onion_key(crypto_pk_env_t *k) {
36
  tor_mutex_acquire(key_lock);
37
  onionkey = k;
38
  onionkey_set_at = time(NULL);
39
  tor_mutex_release(key_lock);
40
41
}

Roger Dingledine's avatar
Roger Dingledine committed
42
/** Return the current onion key.  Requires that the onion key has been
Nick Mathewson's avatar
Nick Mathewson committed
43
 * loaded or generated. */
44
crypto_pk_env_t *get_onion_key(void) {
Roger Dingledine's avatar
Roger Dingledine committed
45
  tor_assert(onionkey);
46
47
48
  return onionkey;
}

Roger Dingledine's avatar
Roger Dingledine committed
49
/** Return the onion key that was current before the most recent onion
Nick Mathewson's avatar
Nick Mathewson committed
50
51
52
 * key rotation.  If no rotation has been performed since this process
 * started, return NULL.
 */
53
54
crypto_pk_env_t *get_previous_onion_key(void) {
  return lastonionkey;
55
56
}

57
58
59
60
61
62
void dup_onion_keys(crypto_pk_env_t **key, crypto_pk_env_t **last)
{
  tor_assert(key && last);
  tor_mutex_acquire(key_lock);
  *key = crypto_pk_dup_key(onionkey);
  if (lastonionkey)
Nick Mathewson's avatar
Nick Mathewson committed
63
    *last = crypto_pk_dup_key(lastonionkey);
64
65
66
67
68
  else
    *last = NULL;
  tor_mutex_release(key_lock);
}

Roger Dingledine's avatar
Roger Dingledine committed
69
/** Return the time when the onion key was last set.  This is either the time
Nick Mathewson's avatar
Nick Mathewson committed
70
71
72
 * when the process launched, or the time of the most recent key rotation since
 * the process launched.
 */
73
74
time_t get_onion_key_set_at(void) {
  return onionkey_set_at;
75
76
}

Roger Dingledine's avatar
Roger Dingledine committed
77
/** Set the current identity key to k.
Nick Mathewson's avatar
Nick Mathewson committed
78
 */
79
80
81
82
void set_identity_key(crypto_pk_env_t *k) {
  identitykey = k;
}

Roger Dingledine's avatar
Roger Dingledine committed
83
/** Returns the current identity key; requires that the identity key has been
Nick Mathewson's avatar
Nick Mathewson committed
84
85
 * set.
 */
86
crypto_pk_env_t *get_identity_key(void) {
Roger Dingledine's avatar
Roger Dingledine committed
87
  tor_assert(identitykey);
88
89
90
  return identitykey;
}

Roger Dingledine's avatar
Roger Dingledine committed
91
/** Replace the previous onion key with the current onion key, and generate
92
93
 * a new previous onion key.  Immediately after calling this function,
 * the OR should:
Roger Dingledine's avatar
Roger Dingledine committed
94
95
96
 *   - schedule all previous cpuworkers to shut down _after_ processing
 *     pending work.  (This will cause fresh cpuworkers to be generated.)
 *   - generate and upload a fresh routerinfo.
97
98
99
100
 */
void rotate_onion_key(void)
{
  char fname[512];
101
  char fname_prev[512];
102
  crypto_pk_env_t *prkey;
103
104
105
  sprintf(fname,"%s/keys/secret_onion_key",get_data_directory(&options));
  sprintf(fname_prev,"%s/keys/secret_onion_key.old",
          get_data_directory(&options));
106
107
108
109
  if (!(prkey = crypto_new_pk_env())) {
    log(LOG_ERR, "Error creating crypto environment.");
    goto error;
  }
110
  if (crypto_pk_generate_key(prkey)) {
111
    log(LOG_ERR, "Error generating onion key");
112
113
    goto error;
  }
114
115
116
117
  if (file_status(fname) == FN_FILE) {
    if (replace_file(fname, fname_prev))
      goto error;
  }
118
119
120
121
  if (crypto_pk_write_private_key_to_filename(prkey, fname)) {
    log(LOG_ERR, "Couldn't write generated key to %s.", fname);
    goto error;
  }
122
  tor_mutex_acquire(key_lock);
123
124
  if (lastonionkey)
    crypto_free_pk_env(lastonionkey);
125
  log_fn(LOG_INFO, "Rotating onion key");
126
127
  lastonionkey = onionkey;
  set_onion_key(prkey);
128
  tor_mutex_release(key_lock);
129
130
131
132
133
  return;
 error:
  log_fn(LOG_WARN, "Couldn't rotate onion key.");
}

134
/** The latest calculated bandwidth usage for our node. */
135
static int bw_capacity = 0;
136
/** Tuck <b>bw</b> away so we can produce it when somebody
137
 * calls router_get_bandwidth_capacity() below.
138
 */
139
140
void router_set_bandwidth_capacity(int bw) {
  bw_capacity = bw;
141
142
}
/** Return the value we tucked away above, or zero by default. */
143
144
int router_get_bandwidth_capacity(void) {
  return bw_capacity;
145
146
}

147
148
149
/* Read an RSA secret key key from a file that was once named fname_old,
 * but is now named fname_new.  Rename the file from old to new as needed.
 */
150
151
152
static crypto_pk_env_t *
init_key_from_file_name_changed(const char *fname_old,
                                const char *fname_new)
153
154
{

155
156
  if (file_status(fname_new) == FN_FILE || file_status(fname_old) != FN_FILE)
    /* The new filename is there, or both are, or neither is. */
157
158
159
160
161
162
163
164
165
166
167
    return init_key_from_file(fname_new);

  /* The old filename exists, and the new one doesn't.  Rename and load. */
  if (rename(fname_old, fname_new) < 0) {
    log_fn(LOG_ERR, "Couldn't rename %s to %s: %s", fname_old, fname_new,
           strerror(errno));
    return NULL;
  }
  return init_key_from_file(fname_new);
}

Nick Mathewson's avatar
Nick Mathewson committed
168
169
170
/** Try to read an RSA key from <b>fname</b>.  If <b>fname</b> doesn't exist,
 * create a new RSA key and save it in <b>fname</b>.  Return the read/created
 * key, or NULL on error.
171
172
 */
crypto_pk_env_t *init_key_from_file(const char *fname)
173
174
175
176
{
  crypto_pk_env_t *prkey = NULL;
  FILE *file = NULL;

177
  if (!(prkey = crypto_new_pk_env())) {
178
179
180
181
182
183
184
185
186
187
188
189
    log(LOG_ERR, "Error creating crypto environment.");
    goto error;
  }

  switch(file_status(fname)) {
  case FN_DIR:
  case FN_ERROR:
    log(LOG_ERR, "Can't read key from %s", fname);
    goto error;
  case FN_NOENT:
    log(LOG_INFO, "No key found in %s; generating fresh key.", fname);
    if (crypto_pk_generate_key(prkey)) {
190
      log(LOG_ERR, "Error generating onion key");
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
      goto error;
    }
    if (crypto_pk_check_key(prkey) <= 0) {
      log(LOG_ERR, "Generated key seems invalid");
      goto error;
    }
    log(LOG_INFO, "Generated key seems valid");
    if (crypto_pk_write_private_key_to_filename(prkey, fname)) {
      log(LOG_ERR, "Couldn't write generated key to %s.", fname);
      goto error;
    }
    return prkey;
  case FN_FILE:
    if (crypto_pk_read_private_key_from_filename(prkey, fname)) {
      log(LOG_ERR, "Error loading private key.");
      goto error;
    }
    return prkey;
  default:
Roger Dingledine's avatar
Roger Dingledine committed
210
    tor_assert(0);
211
212
213
214
215
216
217
218
219
220
  }

 error:
  if (prkey)
    crypto_free_pk_env(prkey);
  if (file)
    fclose(file);
  return NULL;
}

Roger Dingledine's avatar
Roger Dingledine committed
221
/** Initialize all OR private keys, and the TLS context, as necessary.
Nick Mathewson's avatar
Nick Mathewson committed
222
223
 * On OPs, this only initializes the tls context.
 */
224
225
int init_keys(void) {
  char keydir[512];
226
  char keydir2[512];
227
228
  char fingerprint[FINGERPRINT_LEN+MAX_NICKNAME_LEN+3];
  char *cp;
229
  const char *tmp, *mydesc, *datadir;
230
  crypto_pk_env_t *prkey;
231
  char digest[20];
232

233
  if (!key_lock)
Nick Mathewson's avatar
Nick Mathewson committed
234
    key_lock = tor_mutex_new();
235

236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
  /* OP's don't need persistant keys; just make up an identity and
   * initialize the TLS context. */
  if (!server_mode()) {
#if 0
    /* XXXX008 enable this once we make ORs tolerate unknown routers. */
    if (!(prkey = crypto_new_pk_env()))
      return -1;
    if (crypto_pk_generate_key(prkey))
      return -1;
    set_identity_key(prkey);
    if (tor_tls_context_new(get_identity_key(), 1, options.Nickname,
                            MAX_SSL_KEY_LIFETIME) < 0) {
      log_fn(LOG_ERR, "Error creating TLS context for OP.");
      return -1;
    }
#endif
    if (tor_tls_context_new(NULL, 0, NULL, MAX_SSL_KEY_LIFETIME)<0) {
253
254
255
256
257
      log_fn(LOG_ERR, "Error creating TLS context for OP.");
      return -1;
    }
    return 0;
  }
Nick Mathewson's avatar
Nick Mathewson committed
258
  /* Make sure DataDirectory exists, and is private. */
259
260
261
  datadir = get_data_directory(&options);
  tor_assert(datadir);
  if (strlen(datadir) > (512-128)) {
262
263
264
    log_fn(LOG_ERR, "DataDirectory is too long.");
    return -1;
  }
265
  if (check_private_dir(datadir, 1)) {
266
267
    return -1;
  }
Nick Mathewson's avatar
Nick Mathewson committed
268
  /* Check the key directory. */
269
  sprintf(keydir,"%s/keys", datadir);
270
271
272
273
274
275
  if (check_private_dir(keydir, 1)) {
    return -1;
  }
  cp = keydir + strlen(keydir); /* End of string. */

  /* 1. Read identity key. Make it if none is found. */
276
277
278
279
  sprintf(keydir,"%s/keys/identity.key",datadir);
  sprintf(keydir2,"%s/keys/secret_id_key",datadir);
  log_fn(LOG_INFO,"Reading/making identity key %s...",keydir2);
  prkey = init_key_from_file_name_changed(keydir,keydir2);
280
281
282
  if (!prkey) return -1;
  set_identity_key(prkey);
  /* 2. Read onion key.  Make it if none is found. */
283
284
285
286
  sprintf(keydir,"%s/keys/onion.key",datadir);
  sprintf(keydir2,"%s/keys/secret_onion_key",datadir);
  log_fn(LOG_INFO,"Reading/making onion key %s...",keydir2);
  prkey = init_key_from_file_name_changed(keydir,keydir2);
287
288
  if (!prkey) return -1;
  set_onion_key(prkey);
289
290
291
292
293
294
  sprintf(keydir,"%s/keys/secret_onion_key.old",datadir);
  if (file_status(keydir) == FN_FILE) {
    prkey = init_key_from_file(keydir);
    if (prkey)
      lastonionkey = prkey;
  }
295
296

  /* 3. Initialize link key and TLS context. */
297
298
  if (tor_tls_context_new(get_identity_key(), 1, options.Nickname,
                          MAX_SSL_KEY_LIFETIME) < 0) {
299
300
301
302
303
    log_fn(LOG_ERR, "Error initializing TLS context");
    return -1;
  }
  /* 4. Dump router descriptor to 'router.desc' */
  /* Must be called after keys are initialized. */
Roger Dingledine's avatar
Roger Dingledine committed
304
305
  tmp = mydesc = router_get_my_descriptor();
  if (!mydesc) {
306
307
308
    log_fn(LOG_ERR, "Error initializing descriptor.");
    return -1;
  }
Roger Dingledine's avatar
Roger Dingledine committed
309
310
311
312
313
314
315
316
317
318
  if(authdir_mode()) {
    /* We need to add our own fingerprint so it gets recognized. */
    if (dirserv_add_own_fingerprint(options.Nickname, get_identity_key())) {
      log_fn(LOG_ERR, "Error adding own fingerprint to approved set");
      return -1;
    }
    if (dirserv_add_descriptor(&tmp) != 1) {
      log(LOG_ERR, "Unable to add own descriptor to directory.");
      return -1;
    }
319
  }
Roger Dingledine's avatar
Roger Dingledine committed
320

321
  sprintf(keydir,"%s/router.desc", datadir);
322
  log_fn(LOG_INFO,"Dumping descriptor to %s...",keydir);
323
  if (write_str_to_file(keydir, mydesc,0)) {
324
325
326
    return -1;
  }
  /* 5. Dump fingerprint to 'fingerprint' */
327
  sprintf(keydir,"%s/fingerprint", datadir);
328
  log_fn(LOG_INFO,"Dumping fingerprint to %s...",keydir);
Roger Dingledine's avatar
Roger Dingledine committed
329
  tor_assert(strlen(options.Nickname) <= MAX_NICKNAME_LEN);
330
331
332
  strcpy(fingerprint, options.Nickname);
  strcat(fingerprint, " ");
  if (crypto_pk_get_fingerprint(get_identity_key(),
333
                                fingerprint+strlen(fingerprint), 1)<0) {
334
335
336
337
    log_fn(LOG_ERR, "Error computing fingerprint");
    return -1;
  }
  strcat(fingerprint, "\n");
338
  if (write_str_to_file(keydir, fingerprint, 0))
339
    return -1;
Roger Dingledine's avatar
Roger Dingledine committed
340
  if(!authdir_mode())
341
    return 0;
Roger Dingledine's avatar
Roger Dingledine committed
342
  /* 6. [authdirserver only] load approved-routers file */
343
  sprintf(keydir,"%s/approved-routers", datadir);
344
345
346
347
348
  log_fn(LOG_INFO,"Loading approved fingerprints from %s...",keydir);
  if(dirserv_parse_fingerprint_file(keydir) < 0) {
    log_fn(LOG_ERR, "Error loading fingerprints");
    return -1;
  }
349
350
351
352
353
354
355
356
357
358
  /* 6b. [authdirserver only] add own key to approved directories. */
  crypto_pk_get_digest(get_identity_key(), digest);
  if (!router_digest_is_trusted_dir(digest)) {
    uint32_t addr;
    if(resolve_my_address(options.Address, &addr) < 0) {
      log_fn(LOG_WARN,"options.Address didn't resolve into an IP.");
      return -1;
    }
    add_trusted_dir_server(addr, options.DirPort, digest);
  }
Roger Dingledine's avatar
Roger Dingledine committed
359
  /* 7. [authdirserver only] load old directory, if it's there */
360
  sprintf(keydir,"%s/cached-directory", datadir);
361
  log_fn(LOG_INFO,"Loading cached directory from %s...",keydir);
362
  cp = read_file_to_str(keydir,0);
363
364
365
  if(!cp) {
    log_fn(LOG_INFO,"Cached directory %s not present. Ok.",keydir);
  } else {
366
    tor_strstrip(cp,"\r"); /* XXXX Workaround for win32 read_file_to_str bug. */ 
Roger Dingledine's avatar
Roger Dingledine committed
367
368
369
370
    if(dirserv_load_from_directory_string(cp) < 0){
      log_fn(LOG_ERR, "Cached directory %s is corrupt", keydir);
      tor_free(cp);
      return -1;
371
    }
372
    tor_free(cp);
373
374
375
376
377
  }
  /* success */
  return 0;
}

Nick Mathewson's avatar
Nick Mathewson committed
378
/*
Nick Mathewson's avatar
Nick Mathewson committed
379
 * Clique maintenance
Nick Mathewson's avatar
Nick Mathewson committed
380
 */
381

382
383
384
/** OR only: if in clique mode, try to open connections to all of the
 * other ORs we know about. Otherwise, open connections to those we
 * think are in clique mode.
Nick Mathewson's avatar
Nick Mathewson committed
385
 */
386
387
388
389
390
void router_retry_connections(void) {
  int i;
  routerinfo_t *router;
  routerlist_t *rl;

391
392
  tor_assert(server_mode());

393
  router_get_routerlist(&rl);
394
395
396
397
  for (i=0;i < smartlist_len(rl->routers);i++) {
    router = smartlist_get(rl->routers, i);
    if(router_is_me(router))
      continue;
398
399
    if(!clique_mode() && !router_is_clique_mode(router))
      continue;
400
401
    if(!connection_get_by_identity_digest(router->identity_digest,
                                          CONN_TYPE_OR)) {
402
403
      /* not in the list */
      log_fn(LOG_DEBUG,"connecting to OR %s:%u.",router->address,router->or_port);
404
      connection_or_connect(router->addr, router->or_port, router->identity_digest);
405
406
407
408
    }
  }
}

409
410
411
int router_is_clique_mode(routerinfo_t *router) {
  if(router->is_trusted_dir)
    return 1;
412
  if(!tor_version_as_new_as(router->platform, "0.0.8pre1"))
413
414
415
416
    return 1;
  return 0;
}

Nick Mathewson's avatar
Nick Mathewson committed
417
/*
Nick Mathewson's avatar
Nick Mathewson committed
418
 * OR descriptor generation.
Nick Mathewson's avatar
Nick Mathewson committed
419
 */
Nick Mathewson's avatar
Nick Mathewson committed
420

421
/** My routerinfo. */
Nick Mathewson's avatar
Nick Mathewson committed
422
static routerinfo_t *desc_routerinfo = NULL;
423
/** String representation of my descriptor, signed by me. */
Nick Mathewson's avatar
Nick Mathewson committed
424
425
static char descriptor[8192];

Roger Dingledine's avatar
Roger Dingledine committed
426
/** OR only: try to upload our signed descriptor to all the directory servers
Nick Mathewson's avatar
Nick Mathewson committed
427
428
 * we know about.
 */
429
void router_upload_dir_desc_to_dirservers(void) {
Roger Dingledine's avatar
Roger Dingledine committed
430
  const char *s;
431

Roger Dingledine's avatar
Roger Dingledine committed
432
433
  s = router_get_my_descriptor();
  if (!s) {
434
435
436
    log_fn(LOG_WARN, "No descriptor; skipping upload");
    return;
  }
Roger Dingledine's avatar
Roger Dingledine committed
437
  directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_DIR, s, strlen(s));
438
439
}

440
#define DEFAULT_EXIT_POLICY "reject 0.0.0.0/8,reject 169.254.0.0/16,reject 127.0.0.0/8,reject 192.168.0.0/16,reject 10.0.0.0/8,reject 172.16.0.0/12,accept *:20-22,accept *:53,accept *:79-81,accept *:110,accept *:143,accept *:443,accept *:873,accept *:993,accept *:995,reject *:4661-4662,reject *:1214,reject *:6346,accept *:1024-65535,reject *:*"
441

Nick Mathewson's avatar
Nick Mathewson committed
442
443
444
/** Set the exit policy on <b>router</b> to match the exit policy in the
 * current configuration file.  If the exit policy doesn't have a catch-all
 * rule, then append the default exit policy as well.
Nick Mathewson's avatar
Nick Mathewson committed
445
 */
446
static void router_add_exit_policy_from_config(routerinfo_t *router) {
447
448
449
450
451
452
453
454
455
  struct exit_policy_t *ep;
  struct config_line_t default_policy;
  config_parse_exit_policy(options.ExitPolicy, &router->exit_policy);

  for (ep = router->exit_policy; ep; ep = ep->next) {
    if (ep->msk == 0 && ep->prt_min <= 1 && ep->prt_max >= 65535) {
      /* if exitpolicy includes a *:* line, then we're done. */
      return;
    }
456
  }
457
458
459
460
461
462

  /* Else, append the default exitpolicy. */
  default_policy.key = NULL;
  default_policy.value = DEFAULT_EXIT_POLICY;
  default_policy.next = NULL;
  config_parse_exit_policy(&default_policy, &router->exit_policy);
463
464
}

Roger Dingledine's avatar
Roger Dingledine committed
465
/** OR only: Return false if my exit policy says to allow connection to
Nick Mathewson's avatar
Nick Mathewson committed
466
 * conn.  Else return true.
467
 */
468
469
int router_compare_to_my_exit_policy(connection_t *conn)
{
Roger Dingledine's avatar
Roger Dingledine committed
470
  tor_assert(desc_routerinfo);
471
472
473
474
475
476

  /* make sure it's resolved to something. this way we can't get a
     'maybe' below. */
  if (!conn->addr)
    return -1;

477
  return router_compare_addr_to_exit_policy(conn->addr, conn->port,
478
                   desc_routerinfo->exit_policy);
479

480
481
}

Nick Mathewson's avatar
Nick Mathewson committed
482
483
/** Return true iff <b>router</b> has the same nickname as this OR.  (For an
 * OP, always returns false.)
Nick Mathewson's avatar
Nick Mathewson committed
484
 */
485
486
int router_is_me(routerinfo_t *router)
{
487
  routerinfo_t *me = router_get_my_routerinfo();
Roger Dingledine's avatar
Roger Dingledine committed
488
  tor_assert(router);
489
490
491
  if(!me || memcmp(me->identity_digest, router->identity_digest, DIGEST_LEN))
    return 0;
  return 1;
492
493
}

Roger Dingledine's avatar
Roger Dingledine committed
494
/** Return a routerinfo for this OR, rebuilding a fresh one if
Nick Mathewson's avatar
Nick Mathewson committed
495
 * necessary.  Return NULL on error, or if called on an OP. */
496
497
routerinfo_t *router_get_my_routerinfo(void)
{
498
  if (!server_mode())
499
500
501
502
503
504
505
506
507
    return NULL;

  if (!desc_routerinfo) {
    if (router_rebuild_descriptor())
      return NULL;
  }
  return desc_routerinfo;
}

Roger Dingledine's avatar
Roger Dingledine committed
508
/** OR only: Return a signed server descriptor for this OR, rebuilding a fresh
Nick Mathewson's avatar
Nick Mathewson committed
509
510
 * one if necessary.  Return NULL on error.
 */
511
512
513
514
515
516
517
518
519
const char *router_get_my_descriptor(void) {
  if (!desc_routerinfo) {
    if (router_rebuild_descriptor())
      return NULL;
  }
  log_fn(LOG_DEBUG,"my desc is '%s'",descriptor);
  return descriptor;
}

Roger Dingledine's avatar
Roger Dingledine committed
520
/** Rebuild a fresh routerinfo and signed server descriptor for this
Nick Mathewson's avatar
Nick Mathewson committed
521
522
 * OR.  Return 0 on success, -1 on error.
 */
523
524
int router_rebuild_descriptor(void) {
  routerinfo_t *ri;
525
  uint32_t addr;
526
  char platform[256];
527
528
529
530
  struct in_addr in;

  if(resolve_my_address(options.Address, &addr) < 0) {
    log_fn(LOG_WARN,"options.Address didn't resolve into an IP.");
531
532
    return -1;
  }
533

534
  ri = tor_malloc_zero(sizeof(routerinfo_t));
535
536
  in.s_addr = htonl(addr);
  ri->address = tor_strdup(inet_ntoa(in));
537
  ri->nickname = tor_strdup(options.Nickname);
538
  ri->addr = addr;
539
540
541
542
  ri->or_port = options.ORPort;
  ri->socks_port = options.SocksPort;
  ri->dir_port = options.DirPort;
  ri->published_on = time(NULL);
543
  ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); /* must invoke from main thread */
544
  ri->identity_pkey = crypto_pk_dup_key(get_identity_key());
545
546
547
548
  if (crypto_pk_get_digest(ri->identity_pkey, ri->identity_digest)<0) {
    routerinfo_free(ri);
    return -1;
  }
549
550
  get_platform_str(platform, sizeof(platform));
  ri->platform = tor_strdup(platform);
551
552
  ri->bandwidthrate = options.BandwidthRate;
  ri->bandwidthburst = options.BandwidthBurst;
553
  ri->bandwidthcapacity = router_get_bandwidth_capacity();
554
555
  ri->exit_policy = NULL; /* zero it out first */
  router_add_exit_policy_from_config(ri);
556
  ri->is_trusted_dir = authdir_mode();
557
558
559
  if(desc_routerinfo) /* inherit values */
    ri->is_verified = desc_routerinfo->is_verified;

560
561
562
563
564
565
566
567
568
569
  if (desc_routerinfo)
    routerinfo_free(desc_routerinfo);
  desc_routerinfo = ri;
  if (router_dump_router_to_string(descriptor, 8192, ri, get_identity_key())<0) {
    log_fn(LOG_WARN, "Couldn't dump router to string.");
    return -1;
  }
  return 0;
}

Nick Mathewson's avatar
Nick Mathewson committed
570
571
/** Set <b>platform</b> (max length <b>len</b>) to a NUL-terminated short
 * string describing the version of Tor and the operating system we're
Nick Mathewson's avatar
Nick Mathewson committed
572
573
 * currently running on.
 */
574
void get_platform_str(char *platform, int len)
575
{
576
577
  snprintf(platform, len-1, "Tor %s on %s",
           VERSION, get_uname());
578
579
580
581
582
583
584
585
586
  platform[len-1] = '\0';
  return;
}

/* XXX need to audit this thing and count fenceposts. maybe
 *     refactor so we don't have to keep asking if we're
 *     near the end of maxlen?
 */
#define DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
Nick Mathewson's avatar
Nick Mathewson committed
587

Nick Mathewson's avatar
Nick Mathewson committed
588
589
590
591
/** OR only: Given a routerinfo for this router, and an identity key to sign
 * with, encode the routerinfo as a signed server descriptor and write the
 * result into <b>s</b>, using at most <b>maxlen</b> bytes.  Return -1 on
 * failure, and the number of bytes used on success.
Nick Mathewson's avatar
Nick Mathewson committed
592
 */
593
594
int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router,
                                 crypto_pk_env_t *ident_key) {
Nick Mathewson's avatar
Nick Mathewson committed
595
596
  char *onion_pkey; /* Onion key, PEM-encoded. */
  char *identity_pkey; /* Identity key, PEM-encoded. */
597
598
599
  char digest[20];
  char signature[128];
  char published[32];
600
  char fingerprint[FINGERPRINT_LEN+1];
Nick Mathewson's avatar
Nick Mathewson committed
601
  struct in_addr in;
602
  int onion_pkeylen, identity_pkeylen;
603
604
605
  int written;
  int result=0;
  struct exit_policy_t *tmpe;
606
  char *bandwidth_usage;
607
#ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
Roger Dingledine's avatar
Roger Dingledine committed
608
  char *s_tmp, *s_dup;
609
  const char *cp;
610
611
  routerinfo_t *ri_tmp;
#endif
Roger Dingledine's avatar
Roger Dingledine committed
612

Nick Mathewson's avatar
Nick Mathewson committed
613
  /* Make sure the identity key matches the one in the routerinfo. */
614
615
616
617
618
  if (crypto_pk_cmp_keys(ident_key, router->identity_pkey)) {
    log_fn(LOG_WARN,"Tried to sign a router with a private key that didn't match router's public key!");
    return -1;
  }

619
  /* record our fingerprint, so we can include it in the descriptor */
620
  if (crypto_pk_get_fingerprint(router->identity_pkey, fingerprint, 1)<0) {
621
622
623
624
    log_fn(LOG_ERR, "Error computing fingerprint");
    return -1;
  }

Nick Mathewson's avatar
Nick Mathewson committed
625
  /* PEM-encode the onion key */
626
627
628
629
630
631
  if(crypto_pk_write_public_key_to_string(router->onion_pkey,
                                          &onion_pkey,&onion_pkeylen)<0) {
    log_fn(LOG_WARN,"write onion_pkey to string failed!");
    return -1;
  }

Nick Mathewson's avatar
Nick Mathewson committed
632
  /* PEM-encode the identity key key */
633
634
635
  if(crypto_pk_write_public_key_to_string(router->identity_pkey,
                                          &identity_pkey,&identity_pkeylen)<0) {
    log_fn(LOG_WARN,"write identity_pkey to string failed!");
Nick Mathewson's avatar
Nick Mathewson committed
636
    tor_free(onion_pkey);
637
638
639
    return -1;
  }

Nick Mathewson's avatar
Nick Mathewson committed
640
  /* Encode the publication time. */
641
  format_iso_time(published, router->published_on);
Roger Dingledine's avatar
Roger Dingledine committed
642

643
644
  /* How busy have we been? */
  bandwidth_usage = rep_hist_get_bandwidth_lines();
645

Nick Mathewson's avatar
Nick Mathewson committed
646
  /* Generate the easy portion of the router descriptor. */
Roger Dingledine's avatar
Roger Dingledine committed
647
  result = snprintf(s, maxlen,
648
                    "router %s %s %d %d %d\n"
649
650
                    "platform %s\n"
                    "published %s\n"
651
                    "opt fingerprint %s\n"
652
                    "opt uptime %ld\n"
653
                    "bandwidth %d %d %d\n"
654
                    "onion-key\n%s"
655
                    "signing-key\n%s%s",
656
657
658
659
    router->nickname,
    router->address,
    router->or_port,
    router->socks_port,
660
661
662
663
    /* Due to an 0.0.7 bug, we can't actually say that we have a dirport unles
     * we're an authoritative directory.
     */
    router->is_trusted_dir ? router->dir_port : 0,
664
    router->platform,
665
    published,
666
    fingerprint,
667
    stats_n_seconds_uptime,
668
669
    (int) router->bandwidthrate,
    (int) router->bandwidthburst,
670
    (int) router->bandwidthcapacity,
671
672
    onion_pkey, identity_pkey,
    bandwidth_usage);
673

Nick Mathewson's avatar
Nick Mathewson committed
674
675
  tor_free(onion_pkey);
  tor_free(identity_pkey);
Nick Mathewson's avatar
Nick Mathewson committed
676
  tor_free(bandwidth_usage);
677
678
679
680
681

  if(result < 0 || result >= maxlen) {
    /* apparently different glibcs do different things on snprintf error.. so check both */
    return -1;
  }
Nick Mathewson's avatar
Nick Mathewson committed
682
  /* From now on, we use 'written' to remember the current length of 's'. */
683
684
  written = result;

685
686
  if (router->dir_port && !router->is_trusted_dir) {
    /* dircacheport wasn't recognized before 0.0.8pre.  (When 0.0.7 is gone,
Nick Mathewson's avatar
Nick Mathewson committed
687
     * we can fold this back into dirport anyway.) */
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
    result = snprintf(s+written,maxlen-written, "opt dircacheport %d\n",
                      router->dir_port);
    if (result<0 || result+written > maxlen)
      return -1;
    written += result;
  }

  if (options.ContactInfo && strlen(options.ContactInfo)) {
    result = snprintf(s+written,maxlen-written, "opt contact %s\n",
                      options.ContactInfo);
    if (result<0 || result+written > maxlen)
      return -1;
    written += result;
  }

Nick Mathewson's avatar
Nick Mathewson committed
703
  /* Write the exit policy to the end of 's'. */
704
705
  for(tmpe=router->exit_policy; tmpe; tmpe=tmpe->next) {
    in.s_addr = htonl(tmpe->addr);
Nick Mathewson's avatar
Nick Mathewson committed
706
    /* Write: "accept 1.2.3.4" */
707
708
709
710
711
712
713
714
715
    result = snprintf(s+written, maxlen-written, "%s %s",
        tmpe->policy_type == EXIT_POLICY_ACCEPT ? "accept" : "reject",
        tmpe->msk == 0 ? "*" : inet_ntoa(in));
    if(result < 0 || result+written > maxlen) {
      /* apparently different glibcs do different things on snprintf error.. so check both */
      return -1;
    }
    written += result;
    if (tmpe->msk != 0xFFFFFFFFu && tmpe->msk != 0) {
Nick Mathewson's avatar
Nick Mathewson committed
716
      /* Write "/255.255.0.0" */
717
718
719
720
721
722
      in.s_addr = htonl(tmpe->msk);
      result = snprintf(s+written, maxlen-written, "/%s", inet_ntoa(in));
      if (result<0 || result+written > maxlen)
        return -1;
      written += result;
    }
723
    if (tmpe->prt_min <= 1 && tmpe->prt_max == 65535) {
Nick Mathewson's avatar
Nick Mathewson committed
724
      /* There is no port set; write ":*" */
725
726
727
728
729
      if (written > maxlen-4)
        return -1;
      strcat(s+written, ":*\n");
      written += 3;
    } else if (tmpe->prt_min == tmpe->prt_max) {
Nick Mathewson's avatar
Nick Mathewson committed
730
      /* There is only one port; write ":80". */
731
      result = snprintf(s+written, maxlen-written, ":%d\n", tmpe->prt_min);
732
733
734
735
      if (result<0 || result+written > maxlen)
        return -1;
      written += result;
    } else {
Nick Mathewson's avatar
Nick Mathewson committed
736
      /* There is a range of ports; write ":79-80". */
737
738
739
      result = snprintf(s+written, maxlen-written, ":%d-%d\n", tmpe->prt_min,
                        tmpe->prt_max);
      if (result<0 || result+written > maxlen)
740
        return -1;
741
      written += result;
742
    }
743
744
745
    if (tmpe->msk == 0 && tmpe->prt_min <= 1 && tmpe->prt_max == 65535)
      /* This was a catch-all rule, so future rules are irrelevant. */
      break;
746
747
748
749
  } /* end for */
  if (written > maxlen-256) /* Not enough room for signature. */
    return -1;

Nick Mathewson's avatar
Nick Mathewson committed
750
  /* Sign the directory */
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
  strcat(s+written, "router-signature\n");
  written += strlen(s+written);
  s[written] = '\0';
  if (router_get_router_hash(s, digest) < 0)
    return -1;

  if (crypto_pk_private_sign(ident_key, digest, 20, signature) < 0) {
    log_fn(LOG_WARN, "Error signing digest");
    return -1;
  }
  strcat(s+written, "-----BEGIN SIGNATURE-----\n");
  written += strlen(s+written);
  if (base64_encode(s+written, maxlen-written, signature, 128) < 0) {
    log_fn(LOG_WARN, "Couldn't base64-encode signature");
    return -1;
  }
  written += strlen(s+written);
  strcat(s+written, "-----END SIGNATURE-----\n");
  written += strlen(s+written);
Roger Dingledine's avatar
Roger Dingledine committed
770
771

  if (written > maxlen-2)
772
773
774
775
776
777
    return -1;
  /* include a last '\n' */
  s[written] = '\n';
  s[written+1] = 0;

#ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
778
  cp = s_tmp = s_dup = tor_strdup(s);
779
  ri_tmp = router_parse_entry_from_string(cp, NULL);
780
  if (!ri_tmp) {
Roger Dingledine's avatar
Roger Dingledine committed
781
    log_fn(LOG_ERR, "We just generated a router descriptor we can't parse: <<%s>>",
782
783
784
           s);
    return -1;
  }
Roger Dingledine's avatar
Roger Dingledine committed
785
  tor_free(s_dup);
786
787
788
789
790
791
  routerinfo_free(ri_tmp);
#endif

  return written+1;
}

792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
int is_legal_nickname(const char *s)
{
  size_t len;
  tor_assert(s);
  len = strlen(s);
  return len > 0 && len <= MAX_NICKNAME_LEN &&
    strspn(s,LEGAL_NICKNAME_CHARACTERS)==len;
}
int is_legal_nickname_or_hexdigest(const char *s)
{
  size_t len;
  tor_assert(s);
  if (*s!='$')
    return is_legal_nickname(s);

  len = strlen(s);
  return len == HEX_DIGEST_LEN+1 && strspn(s+1,HEX_CHARACTERS)==len-1;
}


812
813
814
815
816
817
818
/*
  Local Variables:
  mode:c
  indent-tabs-mode:nil
  c-basic-offset:2
  End:
*/