dirserv.c 106 KB
Newer Older
1
2
/* Copyright (c) 2001-2004, Roger Dingledine.
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3
 * Copyright (c) 2007-2008, The Tor Project, Inc. */
4
5
/* See LICENSE for licensing information */
/* $Id$ */
6
7
const char dirserv_c_id[] =
  "$Id$";
8

9
#define DIRSERV_PRIVATE
10
11
#include "or.h"

Roger Dingledine's avatar
Roger Dingledine committed
12
13
/**
 * \file dirserv.c
14
15
 * \brief Directory server core implementation. Manages directory
 * contents and generates directories.
16
 */
Nick Mathewson's avatar
Nick Mathewson committed
17

Roger Dingledine's avatar
Roger Dingledine committed
18
/** How far in the future do we allow a router to get? (seconds) */
19
#define ROUTER_ALLOW_SKEW (60*60*12)
20
/** How many seconds do we wait before regenerating the directory? */
21
#define DIR_REGEN_SLACK_TIME 30
22
23
24
/** If we're a cache, keep this many networkstatuses around from non-trusted
 * directory authorities. */
#define MAX_UNTRUSTED_NETWORKSTATUSES 16
Nick Mathewson's avatar
Nick Mathewson committed
25

26
27
28
29
30
/** If a v1 directory is older than this, discard it. */
#define MAX_V1_DIRECTORY_AGE (30*24*60*60)
/** If a v1 running-routers is older than this, discard it. */
#define MAX_V1_RR_AGE (7*24*60*60)

31
32
extern time_t time_of_process_start; /* from main.c */

Roger Dingledine's avatar
Roger Dingledine committed
33
/** Do we need to regenerate the directory when someone asks for it? */
34
35
36
static time_t the_directory_is_dirty = 1;
static time_t runningrouters_is_dirty = 1;
static time_t the_v2_networkstatus_is_dirty = 1;
37

38
39
40
41
42
43
44
/** Most recently generated encoded signed v1 directory. (v1 auth dirservers
 * only.) */
static cached_dir_t *the_directory = NULL;

/** For authoritative directories: the current (v1) network status. */
static cached_dir_t the_runningrouters = { NULL, NULL, 0, 0, 0, -1 };

45
static void directory_remove_invalid(void);
46
static cached_dir_t *dirserv_regenerate_directory(void);
47
static char *format_versions_list(config_line_t *ln);
48
struct authdir_config_t;
49
50
static int add_fingerprint_to_dir(const char *nickname, const char *fp,
                                  struct authdir_config_t *list);
51
52
53
static uint32_t dirserv_router_get_status(const routerinfo_t *router,
                                          const char **msg);
static uint32_t
54
55
56
57
58
dirserv_get_status_impl(const char *fp, const char *nickname,
                        const char *address,
                        uint32_t addr, uint16_t or_port,
                        const char *platform, const char *contact,
                        const char **msg, int should_log);
59
static void clear_cached_dir(cached_dir_t *d);
60
61
62
static signed_descriptor_t *get_signed_descriptor_by_fp(const char *fp,
                                                        int extrainfo,
                                                        time_t publish_cutoff);
63
64
static int dirserv_add_extrainfo(extrainfo_t *ei, const char **msg);

65
66
/************** Fingerprint handling code ************/

67
68
69
#define FP_NAMED   1  /**< Listed in fingerprint file. */
#define FP_INVALID 2  /**< Believed invalid. */
#define FP_REJECT  4  /**< We will not publish this router. */
70
71
72
#define FP_BADDIR  8  /**< We'll tell clients to avoid using this as a dir. */
#define FP_BADEXIT 16  /**< We'll tell clients not to use this as an exit. */
#define FP_UNNAMED 32 /**< Another router has this name in fingerprint file. */
73

74
75
/** Encapsulate a nickname and an FP_* status; target of status_by_digest
 * map. */
76
77
78
79
typedef struct router_status_t {
  char nickname[MAX_NICKNAME_LEN+1];
  uint32_t status;
} router_status_t;
80

Nick Mathewson's avatar
Nick Mathewson committed
81
/** List of nickname-\>identity fingerprint mappings for all the routers
82
 * that we name.  Used to prevent router impersonation. */
83
typedef struct authdir_config_t {
Roger Dingledine's avatar
Roger Dingledine committed
84
85
  strmap_t *fp_by_name; /**< Map from lc nickname to fingerprint. */
  digestmap_t *status_by_digest; /**< Map from digest to router_status_t. */
86
87
} authdir_config_t;

Roger Dingledine's avatar
Roger Dingledine committed
88
/** Should be static; exposed for testing. */
89
static authdir_config_t *fingerprint_list = NULL;
90

91
/** Allocate and return a new, empty, authdir_config_t. */
92
93
94
95
96
97
98
99
static authdir_config_t *
authdir_config_new(void)
{
  authdir_config_t *list = tor_malloc_zero(sizeof(authdir_config_t));
  list->fp_by_name = strmap_new();
  list->status_by_digest = digestmap_new();
  return list;
}
100

Nick Mathewson's avatar
Nick Mathewson committed
101
/** Add the fingerprint <b>fp</b> for the nickname <b>nickname</b> to
102
103
 * the smartlist of fingerprint_entry_t's <b>list</b>. Return 0 if it's
 * new, or 1 if we replaced the old value.
Nick Mathewson's avatar
Nick Mathewson committed
104
 */
105
/* static */ int
106
107
add_fingerprint_to_dir(const char *nickname, const char *fp,
                       authdir_config_t *list)
Nick Mathewson's avatar
Nick Mathewson committed
108
{
109
  char *fingerprint;
110
111
  char d[DIGEST_LEN];
  router_status_t *status;
112
113
114
  tor_assert(nickname);
  tor_assert(fp);
  tor_assert(list);
115

116
  fingerprint = tor_strdup(fp);
117
  tor_strstrip(fingerprint, " ");
118
119
120
  if (base16_decode(d, DIGEST_LEN, fingerprint, strlen(fingerprint))) {
    log_warn(LD_DIRSERV, "Couldn't decode fingerprint \"%s\"",
             escaped(fp));
121
    tor_free(fingerprint);
122
123
    return 0;
  }
124

125
126
127
  if (!strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) {
    log_warn(LD_DIRSERV, "Tried to add a mapping for reserved nickname %s",
             UNNAMED_ROUTER_NICKNAME);
128
    tor_free(fingerprint);
129
130
131
    return 0;
  }

132
133
134
135
136
137
  status = digestmap_get(list->status_by_digest, d);
  if (!status) {
    status = tor_malloc_zero(sizeof(router_status_t));
    digestmap_set(list->status_by_digest, d, status);
  }

138
  if (nickname[0] != '!') {
139
    char *old_fp = strmap_get_lc(list->fp_by_name, nickname);
140
141
142
143
144
    if (old_fp && !strcasecmp(fingerprint, old_fp)) {
      tor_free(fingerprint);
    } else {
      tor_free(old_fp);
      strmap_set_lc(list->fp_by_name, nickname, fingerprint);
Nick Mathewson's avatar
Nick Mathewson committed
145
    }
146
147
148
    status->status |= FP_NAMED;
    strlcpy(status->nickname, nickname, sizeof(status->nickname));
  } else {
149
    tor_free(fingerprint);
150
151
152
153
    if (!strcasecmp(nickname, "!reject")) {
      status->status |= FP_REJECT;
    } else if (!strcasecmp(nickname, "!invalid")) {
      status->status |= FP_INVALID;
154
155
    } else if (!strcasecmp(nickname, "!baddir")) {
      status->status |= FP_BADDIR;
156
157
158
    } else if (!strcasecmp(nickname, "!badexit")) {
      status->status |= FP_BADEXIT;
    }
Nick Mathewson's avatar
Nick Mathewson committed
159
  }
160
  return 0;
Nick Mathewson's avatar
Nick Mathewson committed
161
162
}

163
164
/** Add the nickname and fingerprint for this OR to the
 * global list of recognized identity key fingerprints. */
Nick Mathewson's avatar
Nick Mathewson committed
165
166
167
168
int
dirserv_add_own_fingerprint(const char *nickname, crypto_pk_env_t *pk)
{
  char fp[FINGERPRINT_LEN+1];
169
  if (crypto_pk_get_fingerprint(pk, fp, 0)<0) {
170
    log_err(LD_BUG, "Error computing fingerprint");
Nick Mathewson's avatar
Nick Mathewson committed
171
172
    return -1;
  }
173
  if (!fingerprint_list)
174
    fingerprint_list = authdir_config_new();
175
  add_fingerprint_to_dir(nickname, fp, fingerprint_list);
Nick Mathewson's avatar
Nick Mathewson committed
176
177
178
  return 0;
}

179
180
181
182
183
184
/** Load the nickname-\>fingerprint mappings stored in the approved-routers
 * file.  The file format is line-based, with each non-blank holding one
 * nickname, some space, and a fingerprint for that nickname.  On success,
 * replace the current fingerprint list with the new list and return 0.  On
 * failure, leave the current fingerprint list untouched, and
 * return -1. */
185
int
186
dirserv_load_fingerprint_file(void)
187
{
188
  char *fname;
189
  char *cf;
190
  char *nickname, *fingerprint;
191
  authdir_config_t *fingerprint_list_new;
192
  int result;
193
  config_line_t *front=NULL, *list;
194
195
  or_options_t *options = get_options();

196
  fname = get_datadir_fname("approved-routers");
197
198
  log_info(LD_GENERAL,
           "Reloading approved fingerprints from \"%s\"...", fname);
199

200
  cf = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL);
201
  if (!cf) {
202
    if (options->NamingAuthoritativeDir) {
203
      log_warn(LD_FS, "Cannot open fingerprint file '%s'. Failing.", fname);
204
      tor_free(fname);
205
206
      return -1;
    } else {
Roger Dingledine's avatar
Roger Dingledine committed
207
      log_info(LD_FS, "Cannot open fingerprint file '%s'. That's ok.", fname);
208
      tor_free(fname);
209
210
      return 0;
    }
211
  }
212
213
  tor_free(fname);

214
215
216
  result = config_get_lines(cf, &front);
  tor_free(cf);
  if (result < 0) {
217
    log_warn(LD_CONFIG, "Error reading from fingerprint file");
218
219
220
    return -1;
  }

221
  fingerprint_list_new = authdir_config_new();
222

223
  for (list=front; list; list=list->next) {
224
    char digest_tmp[DIGEST_LEN];
225
    nickname = list->key; fingerprint = list->value;
226
    if (strlen(nickname) > MAX_NICKNAME_LEN) {
227
228
229
      log_notice(LD_CONFIG,
                 "Nickname '%s' too long in fingerprint file. Skipping.",
                 nickname);
230
      continue;
231
    }
232
    if (!is_legal_nickname(nickname) &&
Nick Mathewson's avatar
Nick Mathewson committed
233
        strcasecmp(nickname, "!reject") &&
234
235
        strcasecmp(nickname, "!invalid") &&
        strcasecmp(nickname, "!badexit")) {
236
237
238
      log_notice(LD_CONFIG,
                 "Invalid nickname '%s' in fingerprint file. Skipping.",
                 nickname);
239
240
      continue;
    }
241
242
243
244
    tor_strstrip(fingerprint, " "); /* remove spaces */
    if (strlen(fingerprint) != HEX_DIGEST_LEN ||
        base16_decode(digest_tmp, sizeof(digest_tmp),
                      fingerprint, HEX_DIGEST_LEN) < 0) {
245
246
247
248
      log_notice(LD_CONFIG,
                 "Invalid fingerprint (nickname '%s', "
                 "fingerprint %s). Skipping.",
                 nickname, fingerprint);
249
      continue;
250
    }
251
    if (0==strcasecmp(nickname, DEFAULT_CLIENT_NICKNAME)) {
252
253
      /* If you approved an OR called "client", then clients who use
       * the default nickname could all be rejected.  That's no good. */
254
      log_notice(LD_CONFIG,
255
                 "Authorizing nickname '%s' would break "
256
257
258
259
260
261
                 "many clients; skipping.",
                 DEFAULT_CLIENT_NICKNAME);
      continue;
    }
    if (0==strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) {
      /* If you approved an OR called "unnamed", then clients will be
262
       * confused. */
263
      log_notice(LD_CONFIG,
264
                 "Authorizing nickname '%s' is not allowed; skipping.",
265
266
267
                 UNNAMED_ROUTER_NICKNAME);
      continue;
    }
268
269
    if (add_fingerprint_to_dir(nickname, fingerprint, fingerprint_list_new)
        != 0)
270
      log_notice(LD_CONFIG, "Duplicate nickname '%s'.", nickname);
271
  }
272
273
274
275
276

  config_free_lines(front);
  dirserv_free_fingerprint_list();
  fingerprint_list = fingerprint_list_new;
  /* Delete any routers whose fingerprints we no longer recognize */
277
  directory_remove_invalid();
278
  return 0;
279
}
280

Nick Mathewson's avatar
Nick Mathewson committed
281
/** Check whether <b>router</b> has a nickname/identity key combination that
282
 * we recognize from the fingerprint list, or an IP we automatically act on
283
284
285
 * according to our configuration.  Return the appropriate router status.
 *
 * If the status is 'FP_REJECT' and <b>msg</b> is provided, set
286
 * *<b>msg</b> to an explanation of why. */
287
static uint32_t
288
dirserv_router_get_status(const routerinfo_t *router, const char **msg)
289
{
290
  char d[DIGEST_LEN];
291

292
  if (crypto_pk_get_digest(router->identity_pkey, d)) {
293
    log_warn(LD_BUG,"Error computing fingerprint");
294
295
    if (msg)
      *msg = "Bug: Error computing fingerprint";
296
    return FP_REJECT;
297
298
  }

299
  return dirserv_get_status_impl(d, router->nickname,
300
301
302
303
304
305
306
307
308
309
310
                                 router->address,
                                 router->addr, router->or_port,
                                 router->platform, router->contact_info,
                                 msg, 1);
}

/** Return true if there is no point in downloading the router described by
 * <b>rs</b> because this directory would reject it. */
int
dirserv_would_reject_router(routerstatus_t *rs)
{
311
  uint32_t res;
312

313
  res = dirserv_get_status_impl(rs->identity_digest, rs->nickname,
314
315
316
317
318
                                "", /* address is only used in logs */
                                rs->addr, rs->or_port,
                                NULL, NULL,
                                NULL, 0);

319
  return (res & FP_REJECT) != 0;
320
321
}

322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
/** Helper: Based only on the ID/Nickname combination,
 * return FP_UNNAMED (unnamed), FP_NAMED (named), or 0 (neither).
 */
static uint32_t
dirserv_get_name_status(const char *id_digest, const char *nickname)
{
  char fp[HEX_DIGEST_LEN+1];
  char *fp_by_name;

  base16_encode(fp, sizeof(fp), id_digest, DIGEST_LEN);

  if ((fp_by_name =
       strmap_get_lc(fingerprint_list->fp_by_name, nickname))) {
    if (!strcasecmp(fp, fp_by_name)) {
      return FP_NAMED;
    } else {
      return FP_UNNAMED; /* Wrong fingerprint. */
    }
  }
  return 0;
}

344
345
346
347
348
349
350
/** Helper: As dirserv_get_router_status, but takes the router fingerprint
 * (hex, no spaces), nickname, address (used for logging only), IP address, OR
 * port, platform (logging only) and contact info (logging only) as arguments.
 *
 * If should_log is false, do not log messages.  (There's not much point in
 * logging that we're rejecting servers we'll not download.)
 */
351
352
static uint32_t
dirserv_get_status_impl(const char *id_digest, const char *nickname,
353
354
355
356
357
                        const char *address,
                        uint32_t addr, uint16_t or_port,
                        const char *platform, const char *contact,
                        const char **msg, int should_log)
{
358
  int reject_unlisted = get_options()->AuthDirRejectUnlisted;
359
360
  uint32_t result = 0;
  router_status_t *status_by_digest;
361

362
  if (!fingerprint_list)
363
364
    fingerprint_list = authdir_config_new();

365
  if (should_log)
366
367
    log_debug(LD_DIRSERV, "%d fingerprints, %d digests known.",
              strmap_size(fingerprint_list->fp_by_name),
368
              digestmap_size(fingerprint_list->status_by_digest));
369

370
371
372
373
374
375
376
377
  result = dirserv_get_name_status(id_digest, nickname);
  if (result & FP_NAMED) {
    if (should_log)
      log_debug(LD_DIRSERV,"Good fingerprint for '%s'",nickname);
  }
  if (result & FP_UNNAMED) {
    if (should_log) {
      char *esc_contact = esc_for_log(contact);
378
      log_info(LD_DIRSERV,
379
380
381
382
383
384
               "Mismatched fingerprint for '%s'. "
               "ContactInfo '%s', platform '%s'.)",
               nickname,
               esc_contact,
               platform ? escaped(platform) : "");
      tor_free(esc_contact);
385
    }
386
387
388
    if (msg)
      *msg = "Rejected: There is already a named server with this nickname "
        "and a different fingerprint.";
389
  }
390

391
392
  status_by_digest = digestmap_get(fingerprint_list->status_by_digest,
                                   id_digest);
393
394
  if (status_by_digest)
    result |= (status_by_digest->status & ~FP_NAMED);
395
396
397
398
399
400
401
402
403

  if (result & FP_REJECT) {
    if (msg)
      *msg = "Fingerprint is marked rejected";
    return FP_REJECT;
  } else if (result & FP_INVALID) {
    if (msg)
      *msg = "Fingerprint is marked invalid";
  }
404

405
406
407
408
409
410
411
412
  if (authdir_policy_baddir_address(addr, or_port)) {
    if (should_log)
      log_info(LD_DIRSERV,
               "Marking '%s' as bad directory because of address '%s'",
               nickname, address);
    result |= FP_BADDIR;
  }

413
414
415
416
417
418
419
420
  if (authdir_policy_badexit_address(addr, or_port)) {
    if (should_log)
      log_info(LD_DIRSERV, "Marking '%s' as bad exit because of address '%s'",
               nickname, address);
    result |= FP_BADEXIT;
  }

  if (!(result & FP_NAMED)) {
421
    if (!authdir_policy_permits_address(addr, or_port)) {
422
      if (should_log)
423
424
        log_info(LD_DIRSERV, "Rejecting '%s' because of address '%s'",
                 nickname, address);
425
426
427
428
      if (msg)
        *msg = "Authdir is rejecting routers in this range.";
      return FP_REJECT;
    }
429
    if (!authdir_policy_valid_address(addr, or_port)) {
430
      if (should_log)
431
432
        log_info(LD_DIRSERV, "Not marking '%s' valid because of address '%s'",
                 nickname, address);
433
      result |= FP_INVALID;
434
    }
435
436
437
    if (reject_unlisted) {
      if (msg)
        *msg = "Authdir rejects unknown routers.";
438
      return FP_REJECT;
439
    }
440
    /* 0.1.0.2-rc was the first version that did enough self-testing that
441
     * we're willing to take its word about whether it's running. */
442
    if (platform && !tor_version_as_new_as(platform,"0.1.0.2-rc"))
443
      result |= FP_INVALID;
444
  }
445
446

  return result;
447
448
}

449
/** If we are an authoritative dirserver, and the list of approved
450
451
 * servers contains one whose identity key digest is <b>digest</b>,
 * return that router's nickname.  Otherwise return NULL. */
452
453
const char *
dirserv_get_nickname_by_digest(const char *digest)
454
{
455
  router_status_t *status;
456
  if (!fingerprint_list)
457
458
459
    return NULL;
  tor_assert(digest);

460
461
  status = digestmap_get(fingerprint_list->status_by_digest, digest);
  return status ? status->nickname : NULL;
462
463
}

Roger Dingledine's avatar
Roger Dingledine committed
464
/** Clear the current fingerprint list. */
Roger Dingledine's avatar
Roger Dingledine committed
465
void
466
dirserv_free_fingerprint_list(void)
467
{
468
469
470
  if (!fingerprint_list)
    return;

471
472
473
  strmap_free(fingerprint_list->fp_by_name, _tor_free);
  digestmap_free(fingerprint_list->status_by_digest, _tor_free);
  tor_free(fingerprint_list);
474
475
476
477
478
}

/*
 *    Descriptor list
 */
Nick Mathewson's avatar
Nick Mathewson committed
479

480
481
482
483
484
485
486
487
488
/** Return -1 if <b>ri</b> has a private or otherwise bad address,
 * unless we're configured to not care. Return 0 if all ok. */
static int
dirserv_router_has_valid_address(routerinfo_t *ri)
{
  struct in_addr iaddr;
  if (get_options()->DirAllowPrivateAddresses)
    return 0; /* whatever it is, we're fine with it */
  if (!tor_inet_aton(ri->address, &iaddr)) {
489
490
    log_info(LD_DIRSERV,"Router '%s' published non-IP address '%s'. Refusing.",
             ri->nickname, ri->address);
491
492
    return -1;
  }
493
  if (is_internal_IP(ntohl(iaddr.s_addr), 0)) {
494
495
496
    log_info(LD_DIRSERV,
             "Router '%s' published internal IP address '%s'. Refusing.",
             ri->nickname, ri->address);
497
498
499
500
501
    return -1; /* it's a private IP, we should reject it */
  }
  return 0;
}

502
/** Check whether we, as a directory server, want to accept <b>ri</b>.  If so,
503
 * set its is_valid,named,running fields and return 0.  Otherwise, return -1.
504
 *
505
 * If the router is rejected, set *<b>msg</b> to an explanation of why.
506
507
508
 *
 * If <b>complain</b> then explain at log-level 'notice' why we refused
 * a descriptor; else explain at log-level 'info'.
509
 */
510
int
511
512
authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
                               int complain)
513
514
{
  /* Okay.  Now check whether the fingerprint is recognized. */
515
  uint32_t status = dirserv_router_get_status(ri, msg);
516
  time_t now;
517
  int severity = complain ? LOG_NOTICE : LOG_INFO;
Nick Mathewson's avatar
Nick Mathewson committed
518
  tor_assert(msg);
519
  if (status & FP_REJECT)
520
521
    return -1; /* msg is already set. */

Nick Mathewson's avatar
Nick Mathewson committed
522
  /* Is there too much clock skew? */
523
  now = time(NULL);
524
  if (ri->cache_info.published_on > now+ROUTER_ALLOW_SKEW) {
525
526
    log_fn(severity, LD_DIRSERV, "Publication time for nickname '%s' is too "
           "far (%d minutes) in the future; possible clock skew. Not adding "
527
           "(%s)",
528
           ri->nickname, (int)((ri->cache_info.published_on-now)/60),
529
           esc_router_info(ri));
530
531
    *msg = "Rejected: Your clock is set too far in the future, or your "
      "timezone is not correct.";
532
    return -1;
533
  }
534
  if (ri->cache_info.published_on < now-ROUTER_MAX_AGE_TO_PUBLISH) {
535
    log_fn(severity, LD_DIRSERV,
536
           "Publication time for router with nickname '%s' is too far "
537
           "(%d minutes) in the past. Not adding (%s)",
538
           ri->nickname, (int)((now-ri->cache_info.published_on)/60),
539
           esc_router_info(ri));
540
541
    *msg = "Rejected: Server is expired, or your clock is too far in the past,"
      " or your timezone is not correct.";
542
    return -1;
543
  }
544
  if (dirserv_router_has_valid_address(ri) < 0) {
545
546
    log_fn(severity, LD_DIRSERV,
           "Router with nickname '%s' has invalid address '%s'. "
547
           "Not adding (%s).",
548
           ri->nickname, ri->address,
549
           esc_router_info(ri));
550
551
    *msg = "Rejected: Address is not an IP, or IP is a private address.";
    return -1;
552
  }
553
  /* Okay, looks like we're willing to accept this one. */
554
555
  ri->is_named = (status & FP_NAMED) ? 1 : 0;
  ri->is_valid = (status & FP_INVALID) ? 0 : 1;
556
  ri->is_bad_directory = (status & FP_BADDIR) ? 1 : 0;
557
  ri->is_bad_exit = (status & FP_BADEXIT) ? 1 : 0;
558

559
560
561
  return 0;
}

562
563
564
/** As for dirserv_add_descriptor, but accepts multiple documents, and
 * returns the most severe error that occurred for any one of them. */
int
565
dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
566
                                 const char *source,
567
                                 const char **msg)
568
569
570
571
{
  int r=100; /* higher than any actual return value. */
  int r_tmp;
  const char *msg_out;
572
573
574
  smartlist_t *list;
  const char *s;
  int n_parsed = 0;
575
  time_t now = time(NULL);
Roger Dingledine's avatar
Roger Dingledine committed
576
  char annotation_buf[ROUTER_ANNOTATION_BUF_LEN];
577
578
  char time_buf[ISO_TIME_LEN+1];
  int general = purpose == ROUTER_PURPOSE_GENERAL;
579
  tor_assert(msg);
580

581
582
583
584
585
586
587
588
589
590
591
592
  format_iso_time(time_buf, now);
  if (tor_snprintf(annotation_buf, sizeof(annotation_buf),
                   "@uploaded-at %s\n"
                   "@source %s\n"
                   "%s%s%s", time_buf, escaped(source),
                   !general ? "@purpose " : "",
                   !general ? router_purpose_to_string(purpose) : "",
                   !general ? "\n" : "")<0) {
    *msg = "Couldn't format annotations";
    return -1;
  }

593
594
  s = desc;
  list = smartlist_create();
595
  if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 0, 0,
596
                                     annotation_buf)) {
597
    SMARTLIST_FOREACH(list, routerinfo_t *, ri, {
598
        msg_out = NULL;
599
        tor_assert(ri->purpose == purpose);
600
601
602
603
604
605
        r_tmp = dirserv_add_descriptor(ri, &msg_out);
        if (r_tmp < r) {
          r = r_tmp;
          *msg = msg_out;
        }
      });
606
  }
607
608
609
610
  n_parsed += smartlist_len(list);
  smartlist_clear(list);

  s = desc;
611
612
  if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 1, 0,
                                     NULL)) {
613
    SMARTLIST_FOREACH(list, extrainfo_t *, ei, {
614
        msg_out = NULL;
615

616
617
618
619
620
621
622
623
624
        r_tmp = dirserv_add_extrainfo(ei, &msg_out);
        if (r_tmp < r) {
          r = r_tmp;
          *msg = msg_out;
        }
      });
  }
  n_parsed += smartlist_len(list);
  smartlist_free(list);
625

626
627
628
629
630
631
632
633
634
635
  if (! *msg) {
    if (!n_parsed) {
      *msg = "No descriptors found in your POST.";
      if (r > -1)
        r = -1;
    } else {
      *msg = "(no message)";
    }
  }

636
  return r <= 2 ? r : 2;
637
638
}

639
640
641
/** Examine the parsed server descriptor in <b>ri</b> and maybe insert it into
 * the list of server descriptors. Set *<b>msg</b> to a message that should be
 * passed back to the origin of this descriptor.
642
 *
643
644
 * Return 2 if descriptor is well-formed and accepted;
 *  1 if well-formed and accepted but origin should hear *msg;
Roger Dingledine's avatar
Roger Dingledine committed
645
 *  0 if well-formed but redundant with one we already have;
646
 * -1 if it is rejected and origin should hear *msg;
647
648
649
 *
 * This function is only called when fresh descriptors are posted, not when
 * we re-load the cache.
650
651
 */
int
652
dirserv_add_descriptor(routerinfo_t *ri, const char **msg)
653
{
654
  int r;
655
  routerinfo_t *ri_old;
656
657
  char *desc = NULL;
  size_t desclen = 0;
658

659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
  /* If it's too big, refuse it now. Otherwise we'll cache it all over the
   * network and it'll clog everything up. */
  if (ri->cache_info.signed_descriptor_len > MAX_DESCRIPTOR_UPLOAD_SIZE) {
    log_notice(LD_DIR, "Somebody attempted to publish a router descriptor "
               "with size %d. Either this is an attack, or the "
               "MAX_DESCRIPTOR_UPLOAD_SIZE (%d) constant is too low.",
               (int)ri->cache_info.signed_descriptor_len,
               MAX_DESCRIPTOR_UPLOAD_SIZE);
    *msg = "Router descriptor was too large";
    control_event_or_authdir_new_descriptor("REJECTED",
               ri->cache_info.signed_descriptor_body,
               ri->cache_info.signed_descriptor_len, *msg);
    routerinfo_free(ri);
    return -1;
  }

675
676
677
678
  /* Check whether this descriptor is semantically identical to the last one
   * from this server.  (We do this here and not in router_add_to_routerlist
   * because we want to be able to accept the newest router descriptor that
   * another authority has, so we all converge on the same one.) */
679
680
  ri_old = router_get_by_digest(ri->cache_info.identity_digest);
  if (ri_old && ri_old->cache_info.published_on < ri->cache_info.published_on
681
682
      && router_differences_are_cosmetic(ri_old, ri)
      && !router_is_me(ri)) {
683
684
685
    log_info(LD_DIRSERV,
             "Not replacing descriptor from '%s'; differences are cosmetic.",
             ri->nickname);
686
687
    *msg = "Not replacing router descriptor; no information has changed since "
      "the last one with this identity.";
688
689
690
    control_event_or_authdir_new_descriptor("DROPPED",
                         ri->cache_info.signed_descriptor_body,
                         ri->cache_info.signed_descriptor_len, *msg);
691
    routerinfo_free(ri);
692
693
    return 0;
  }
694
695
696
697
698
699
700
  if (control_event_is_interesting(EVENT_AUTHDIR_NEWDESCS)) {
    /* Make a copy of desc, since router_add_to_routerlist might free
     * ri and its associated signed_descriptor_t. */
    desclen = ri->cache_info.signed_descriptor_len;
    desc = tor_strndup(ri->cache_info.signed_descriptor_body, desclen);
  }

701
  if ((r = router_add_to_routerlist(ri, msg, 0, 0))<0) {
702
703
704
    if (r < -1 && desc) /* unless the routerinfo was fine, just out-of-date */
      control_event_or_authdir_new_descriptor("REJECTED", desc, desclen, *msg);
    tor_free(desc);
705
    return r == -1 ? 0 : -1;
706
  } else {
707
    smartlist_t *changed;
708
    control_event_or_authdir_new_descriptor("ACCEPTED", desc, desclen, *msg);
709

710
    changed = smartlist_create();
711
712
713
    smartlist_add(changed, ri);
    control_event_descriptors_changed(changed);
    smartlist_free(changed);
714
    if (!*msg) {
715
716
      *msg =  ri->is_valid ? "Descriptor for valid server accepted" :
        "Descriptor for invalid server accepted";
717
    }
718
    tor_free(desc);
719
    return r == 0 ? 2 : 1;
720
  }
721
722
}

723
/** As dirserv_add_descriptor, but for an extrainfo_t <b>ei</b>. */
724
725
726
727
static int
dirserv_add_extrainfo(extrainfo_t *ei, const char **msg)
{
  routerinfo_t *ri;
728
  int r;
729
730
731
732
733
734
735
736
737
  tor_assert(msg);
  *msg = NULL;

  ri = router_get_by_digest(ei->cache_info.identity_digest);
  if (!ri) {
    *msg = "No corresponding router descriptor for extra-info descriptor";
    extrainfo_free(ei);
    return -1;
  }
738
739
740
741
742
743
744
745
746
747
748
749
750
751

  /* If it's too big, refuse it now. Otherwise we'll cache it all over the
   * network and it'll clog everything up. */
  if (ei->cache_info.signed_descriptor_len > MAX_EXTRAINFO_UPLOAD_SIZE) {
    log_notice(LD_DIR, "Somebody attempted to publish an extrainfo "
               "with size %d. Either this is an attack, or the "
               "MAX_EXTRAINFO_UPLOAD_SIZE (%d) constant is too low.",
               (int)ei->cache_info.signed_descriptor_len,
               MAX_EXTRAINFO_UPLOAD_SIZE);
    *msg = "Extrainfo document was too large";
    extrainfo_free(ei);
    return -1;
  }

752
  if ((r = routerinfo_incompatible_with_extrainfo(ri, ei, NULL, msg))) {
753
    extrainfo_free(ei);
754
    return r < 0 ? 0 : -1;
755
756
757
758
759
  }
  router_add_extrainfo_to_routerlist(ei, msg, 0, 0);
  return 2;
}

760
761
762
/** Remove all descriptors whose nicknames or fingerprints no longer
 * are allowed by our fingerprint list. (Descriptors that used to be
 * good can become bad when we reload the fingerprint list.)
Nick Mathewson's avatar
Nick Mathewson committed
763
 */
764
static void
765
directory_remove_invalid(void)
766
767
{
  int i;
768
  int changed = 0;
769
  routerlist_t *rl = router_get_routerlist();
770

771
772
  routerlist_assert_ok(rl);

773
  for (i = 0; i < smartlist_len(rl->routers); ++i) {
774
    const char *msg;
775
    routerinfo_t *ent = smartlist_get(rl->routers, i);
776
777
778
779
    uint32_t r = dirserv_router_get_status(ent, &msg);
    if (r & FP_REJECT) {
      log_info(LD_DIRSERV, "Router '%s' is now rejected: %s",
               ent->nickname, msg?msg:"");
780
781
      routerlist_remove(rl, ent, 0);
      i--;
782
      changed = 1;
783
      continue;
784
    }
785
    if (bool_neq((r & FP_NAMED), ent->is_named)) {
786
787
788
789
790
791
      log_info(LD_DIRSERV,
               "Router '%s' is now %snamed.", ent->nickname,
               (r&FP_NAMED)?"":"un");
      ent->is_named = (r&FP_NAMED)?1:0;
      changed = 1;
    }
792
    if (bool_neq((r & FP_INVALID), !ent->is_valid)) {
793
794
795
796
797
      log_info(LD_DIRSERV, "Router '%s' is now %svalid.", ent->nickname,
               (r&FP_INVALID) ? "in" : "");
      ent->is_valid = (r&FP_INVALID)?0:1;
      changed = 1;
    }
798
799
800
801
802
803
    if (bool_neq((r & FP_BADDIR), ent->is_bad_directory)) {
      log_info(LD_DIRSERV, "Router '%s' is now a %s directory", ent->nickname,
               (r & FP_BADDIR) ? "bad" : "good");
      ent->is_bad_directory = (r&FP_BADDIR) ? 1: 0;
      changed = 1;
    }
804
    if (bool_neq((r & FP_BADEXIT), ent->is_bad_exit)) {
805
806
807
808
      log_info(LD_DIRSERV, "Router '%s' is now a %s exit", ent->nickname,
               (r & FP_BADEXIT) ? "bad" : "good");
      ent->is_bad_exit = (r&FP_BADEXIT) ? 1: 0;
      changed = 1;
809
810
    }
  }
811
812
  if (changed)
    directory_set_dirty();
813
814

  routerlist_assert_ok(rl);
815
816
}

817
818
819
820
/** Write a list of unregistered descriptors into a newly allocated
 * string and return it. Used by dirserv operators to keep track of
 * fast nodes that haven't registered.
 */
821
822
823
int
getinfo_helper_dirserv_unregistered(control_connection_t *control_conn,
                                    const char *question, char **answer_out)
824
825
826
827
{
  smartlist_t *answerlist;
  char buf[1024];
  char *answer;
828
  int min_bw = atoi(question);
829
  routerlist_t *rl = router_get_routerlist();
830

831
832
833
834
835
836
  (void) control_conn;

  if (strcmpstart(question, "unregistered-servers-"))
    return 0;
  question += strlen("unregistered-servers-");

837
  answerlist = smartlist_create();
838
  SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ent, {
839
    uint32_t r = dirserv_router_get_status(ent, NULL);
840
    if (router_get_advertised_bandwidth(ent) >= (size_t)min_bw &&
841
        !(r & FP_NAMED)) {
842
843
844
      /* then log this one */
      tor_snprintf(buf, sizeof(buf),
                   "%s: BW %d on '%s'.",
845
                   ent->nickname, router_get_advertised_bandwidth(ent),
846
847
848
                   ent->platform ? ent->platform : "");
      smartlist_add(answerlist, tor_strdup(buf));
    }
849
  });
850
851
852
  answer = smartlist_join_strings(answerlist, "\r\n", 0, NULL);
  SMARTLIST_FOREACH(answerlist, char *, cp, tor_free(cp));
  smartlist_free(answerlist);
853
854
  *answer_out = answer;
  return 0;
855
856
}

Nick Mathewson's avatar
Nick Mathewson committed
857
/** Mark the directory as <b>dirty</b> -- when we're next asked for a
Nick Mathewson's avatar
Nick Mathewson committed
858
859
860
 * directory, we will rebuild it instead of reusing the most recently
 * generated one.
 */
Roger Dingledine's avatar
Roger Dingledine committed
861
void
862
directory_set_dirty(void)
863
{
864
  time_t now = time(NULL);
865
  int set_v1_dirty=0;
866

867
868
  /* Regenerate stubs only every 8 hours.
   * XXXX021 It would be nice to generate less often. */
869
870
871
872
873
874
875
876
877
878
879
880
881
#define STUB_REGENERATE_INTERVAL (8*60*60)
  if (!the_directory || !the_runningrouters.dir)
    set_v1_dirty = 1;
  else if (the_directory->published < now - STUB_REGENERATE_INTERVAL ||
           the_runningrouters.published < now - STUB_REGENERATE_INTERVAL)
    set_v1_dirty = 1;

  if (set_v1_dirty) {
    if (!the_directory_is_dirty)
      the_directory_is_dirty = now;
    if (!runningrouters_is_dirty)
      runningrouters_is_dirty = now;
  }
882
883
  if (!the_v2_networkstatus_is_dirty)
    the_v2_networkstatus_is_dirty = now;
884
885
}

886
887
/**
 * Allocate and return a description of the status of the server <b>desc</b>,
888
 * for use in a v1-style router-status line.  The server is listed
889
 * as running iff <b>is_live</b> is true.
Nick Mathewson's avatar
Nick Mathewson committed
890
 */
891
static char *
892
list_single_server_status(routerinfo_t *desc, int is_live)
893
{
894
  char buf[MAX_NICKNAME_LEN+HEX_DIGEST_LEN+4]; /* !nickname=$hexdigest\0 */
895
  char *cp;
896

897
898
899
900
901
902
  tor_assert(desc);

  cp = buf;
  if (!is_live) {
    *cp++ = '!';
  }
903
  if (desc->is_valid) {
Nick Mathewson's avatar
Nick Mathewson committed
904
    strlcpy(cp, desc->nickname, sizeof(buf)-(cp-buf));
905
    cp += strlen(cp);
906
    *cp++ = '=';
907
  }
908
  *cp++ = '$';
909
  base16_encode(cp, HEX_DIGEST_LEN+1, desc->cache_info.identity_digest,
910
                DIGEST_LEN);
911
912
913
  return tor_strdup(buf);
}

914
915
916
/** Each server needs to have passed a reachability test no more
 * than this number of seconds ago, or he is listed as down in
 * the directory. */
917
#define REACHABLE_TIMEOUT (45*60)
918

919
920
/** Treat a router as alive if
 *    - It's me, and I'm not hibernating.
921
 * or - We've found it reachable recently. */
922
void
923
dirserv_set_router_is_running(routerinfo_t *router, time_t now)
924
{
925
926
  int a