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

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

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

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

296
  return dirserv_get_status_impl(d, router->nickname,
297
298
299
300
301
302
303
304
305
306
307
                                 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)
{
308
  uint32_t res;
309

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

316
  return (res & FP_REJECT) != 0;
317
318
}

319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
/** 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;
}

341
342
343
344
345
346
347
/** 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.)
 */
348
349
static uint32_t
dirserv_get_status_impl(const char *id_digest, const char *nickname,
350
351
352
353
354
                        const char *address,
                        uint32_t addr, uint16_t or_port,
                        const char *platform, const char *contact,
                        const char **msg, int should_log)
{
355
  int reject_unlisted = get_options()->AuthDirRejectUnlisted;
356
357
  uint32_t result = 0;
  router_status_t *status_by_digest;
358

359
  if (!fingerprint_list)
360
361
    fingerprint_list = authdir_config_new();

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

367
368
369
370
371
372
373
374
  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);
375
      log_info(LD_DIRSERV,
376
377
378
379
380
381
               "Mismatched fingerprint for '%s'. "
               "ContactInfo '%s', platform '%s'.)",
               nickname,
               esc_contact,
               platform ? escaped(platform) : "");
      tor_free(esc_contact);
382
    }
383
384
385
    if (msg)
      *msg = "Rejected: There is already a named server with this nickname "
        "and a different fingerprint.";
386
  }
387

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

  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";
  }
401

402
403
404
405
406
407
408
409
  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;
  }

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

  return result;
444
445
}

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

457
458
  status = digestmap_get(fingerprint_list->status_by_digest, digest);
  return status ? status->nickname : NULL;
459
460
}

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

468
469
470
  strmap_free(fingerprint_list->fp_by_name, _tor_free);
  digestmap_free(fingerprint_list->status_by_digest, _tor_free);
  tor_free(fingerprint_list);
471
472
473
474
475
}

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

477
478
479
480
481
482
483
484
485
/** 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)) {
486
487
    log_info(LD_DIRSERV,"Router '%s' published non-IP address '%s'. Refusing.",
             ri->nickname, ri->address);
488
489
    return -1;
  }
490
  if (is_internal_IP(ntohl(iaddr.s_addr), 0)) {
491
492
493
    log_info(LD_DIRSERV,
             "Router '%s' published internal IP address '%s'. Refusing.",
             ri->nickname, ri->address);
494
495
496
497
498
    return -1; /* it's a private IP, we should reject it */
  }
  return 0;
}

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

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

556
557
558
  return 0;
}

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

578
579
580
581
582
583
584
585
586
587
588
589
  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;
  }

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

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

613
614
615
616
617
618
619
620
621
        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);
622

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

633
  return r <= 2 ? r : 2;
634
635
}

636
637
638
/** 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.
639
 *
640
641
 * 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
642
 *  0 if well-formed but redundant with one we already have;
643
 * -1 if it is rejected and origin should hear *msg;
644
645
646
 *
 * This function is only called when fresh descriptors are posted, not when
 * we re-load the cache.
647
648
 */
int
649
dirserv_add_descriptor(routerinfo_t *ri, const char **msg)
650
{
651
  int r;
652
  routerinfo_t *ri_old;
653
654
  char *desc = NULL;
  size_t desclen = 0;
655

656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
  /* 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;
  }

672
673
674
675
  /* 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.) */
676
677
  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
678
679
      && router_differences_are_cosmetic(ri_old, ri)
      && !router_is_me(ri)) {
680
681
682
    log_info(LD_DIRSERV,
             "Not replacing descriptor from '%s'; differences are cosmetic.",
             ri->nickname);
683
684
    *msg = "Not replacing router descriptor; no information has changed since "
      "the last one with this identity.";
685
686
687
    control_event_or_authdir_new_descriptor("DROPPED",
                         ri->cache_info.signed_descriptor_body,
                         ri->cache_info.signed_descriptor_len, *msg);
688
    routerinfo_free(ri);
689
690
    return 0;
  }
691
692
693
694
695
696
697
  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);
  }

698
  if ((r = router_add_to_routerlist(ri, msg, 0, 0))<0) {
699
700
701
    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);
702
    return r == -1 ? 0 : -1;
703
  } else {
704
    smartlist_t *changed;
705
    control_event_or_authdir_new_descriptor("ACCEPTED", desc, desclen, *msg);
706

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

720
/** As dirserv_add_descriptor, but for an extrainfo_t <b>ei</b>. */
721
722
723
724
static int
dirserv_add_extrainfo(extrainfo_t *ei, const char **msg)
{
  routerinfo_t *ri;
725
  int r;
726
727
728
729
730
731
732
733
734
  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;
  }
735
736
737
738
739
740
741
742
743
744
745
746
747
748

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

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

757
758
759
/** 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
760
 */
761
static void
762
directory_remove_invalid(void)
763
764
{
  int i;
765
  int changed = 0;
766
  routerlist_t *rl = router_get_routerlist();
767

768
769
  routerlist_assert_ok(rl);

770
  for (i = 0; i < smartlist_len(rl->routers); ++i) {
771
    const char *msg;
772
    routerinfo_t *ent = smartlist_get(rl->routers, i);
773
774
775
776
    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:"");
777
778
      routerlist_remove(rl, ent, 0);
      i--;
779
      changed = 1;
780
      continue;
781
    }
782
    if (bool_neq((r & FP_NAMED), ent->is_named)) {
783
784
785
786
787
788
      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;
    }
789
    if (bool_neq((r & FP_INVALID), !ent->is_valid)) {
790
791
792
793
794
      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;
    }
795
796
797
798
799
800
    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;
    }
801
    if (bool_neq((r & FP_BADEXIT), ent->is_bad_exit)) {
802
803
804
805
      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;
806
807
    }
  }
808
809
  if (changed)
    directory_set_dirty();
810
811

  routerlist_assert_ok(rl);
812
813
}

814
815
816
817
/** 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.
 */
818
819
820
int
getinfo_helper_dirserv_unregistered(control_connection_t *control_conn,
                                    const char *question, char **answer_out)
821
822
823
824
{
  smartlist_t *answerlist;
  char buf[1024];
  char *answer;
825
  int min_bw = atoi(question);
826
  routerlist_t *rl = router_get_routerlist();
827

828
829
830
831
832
833
  (void) control_conn;

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

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

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

864
865
  /* Regenerate stubs only every 8 hours.
   * XXXX021 It would be nice to generate less often. */
866
867
868
869
870
871
872
873
874
875
876
877
878
#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;
  }
879
880
  if (!the_v2_networkstatus_is_dirty)
    the_v2_networkstatus_is_dirty = now;
881
882
}

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

894
895
896
897
898
899
  tor_assert(desc);

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

911
912
913
/** 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. */
914
#define REACHABLE_TIMEOUT (45*60)
915

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

924
  if (router_is_me(router) && !we_are_hibernating())
925
926
927
928
929
930
931
932
933
934
935
    answer = 1;
  else
    answer = get_options()->AssumeReachable ||
             now < router->last_reachable + REACHABLE_TIMEOUT;

  if (router->is_running && !answer) {
    /* it was running but now it's not. tell rephist. */
    rep_hist_note_router_unreachable(router->cache_info.identity_digest, now);
  }

  router->is_running = answer;
936
937