dirserv.c 120 KB
Newer Older
1
2
/* Copyright (c) 2001-2004, Roger Dingledine.
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
Karsten Loesing's avatar
Karsten Loesing committed
3
 * Copyright (c) 2007-2009, The Tor Project, Inc. */
4
5
/* See LICENSE for licensing information */

6
#define DIRSERV_PRIVATE
7
8
#include "or.h"

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

Roger Dingledine's avatar
Roger Dingledine committed
15
/** How far in the future do we allow a router to get? (seconds) */
16
#define ROUTER_ALLOW_SKEW (60*60*12)
17
/** How many seconds do we wait before regenerating the directory? */
18
#define DIR_REGEN_SLACK_TIME 30
19
20
21
/** 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
22

23
24
25
26
27
/** 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)

28
29
extern time_t time_of_process_start; /* from main.c */

30
/** Do we need to regenerate the v1 directory when someone asks for it? */
31
static time_t the_directory_is_dirty = 1;
32
33
/** Do we need to regenerate the v1 runningrouters document when somebody
 * asks for it? */
34
static time_t runningrouters_is_dirty = 1;
35
36
/** Do we need to regenerate our v2 networkstatus document when somebody asks
 * for it? */
37
static time_t the_v2_networkstatus_is_dirty = 1;
38

39
40
41
42
43
/** 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. */
44
static cached_dir_t the_runningrouters;
45

46
static void directory_remove_invalid(void);
47
static cached_dir_t *dirserv_regenerate_directory(void);
48
static char *format_versions_list(config_line_t *ln);
49
struct authdir_config_t;
50
51
static int add_fingerprint_to_dir(const char *nickname, const char *fp,
                                  struct authdir_config_t *list);
52
53
54
static uint32_t dirserv_router_get_status(const routerinfo_t *router,
                                          const char **msg);
static uint32_t
55
56
57
58
59
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);
60
static void clear_cached_dir(cached_dir_t *d);
61
62
63
static signed_descriptor_t *get_signed_descriptor_by_fp(const char *fp,
                                                        int extrainfo,
                                                        time_t publish_cutoff);
64
65
static int dirserv_add_extrainfo(extrainfo_t *ei, const char **msg);

66
67
68
/************** Measured Bandwidth parsing code ******/
#define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */

69
70
/************** Fingerprint handling code ************/

71
72
73
#define FP_NAMED   1  /**< Listed in fingerprint file. */
#define FP_INVALID 2  /**< Believed invalid. */
#define FP_REJECT  4  /**< We will not publish this router. */
74
75
76
#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. */
77

78
79
/** Encapsulate a nickname and an FP_* status; target of status_by_digest
 * map. */
80
81
82
83
typedef struct router_status_t {
  char nickname[MAX_NICKNAME_LEN+1];
  uint32_t status;
} router_status_t;
84

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

Roger Dingledine's avatar
Roger Dingledine committed
92
/** Should be static; exposed for testing. */
93
static authdir_config_t *fingerprint_list = NULL;
94

95
/** Allocate and return a new, empty, authdir_config_t. */
96
97
98
99
100
101
102
103
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;
}
104

Nick Mathewson's avatar
Nick Mathewson committed
105
/** Add the fingerprint <b>fp</b> for the nickname <b>nickname</b> to
106
107
 * 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
108
 */
109
/* static */ int
110
111
add_fingerprint_to_dir(const char *nickname, const char *fp,
                       authdir_config_t *list)
Nick Mathewson's avatar
Nick Mathewson committed
112
{
113
  char *fingerprint;
114
115
  char d[DIGEST_LEN];
  router_status_t *status;
116
117
118
  tor_assert(nickname);
  tor_assert(fp);
  tor_assert(list);
119

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

129
130
131
  if (!strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) {
    log_warn(LD_DIRSERV, "Tried to add a mapping for reserved nickname %s",
             UNNAMED_ROUTER_NICKNAME);
132
    tor_free(fingerprint);
133
134
135
    return 0;
  }

136
137
138
139
140
141
  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);
  }

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

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

183
184
185
186
187
188
/** 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. */
189
int
190
dirserv_load_fingerprint_file(void)
191
{
192
  char *fname;
193
  char *cf;
194
  char *nickname, *fingerprint;
195
  authdir_config_t *fingerprint_list_new;
196
  int result;
197
  config_line_t *front=NULL, *list;
198
199
  or_options_t *options = get_options();

200
  fname = get_datadir_fname("approved-routers");
201
202
  log_info(LD_GENERAL,
           "Reloading approved fingerprints from \"%s\"...", fname);
203

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

218
219
220
  result = config_get_lines(cf, &front);
  tor_free(cf);
  if (result < 0) {
221
    log_warn(LD_CONFIG, "Error reading from fingerprint file");
222
223
224
    return -1;
  }

225
  fingerprint_list_new = authdir_config_new();
226

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

  config_free_lines(front);
  dirserv_free_fingerprint_list();
  fingerprint_list = fingerprint_list_new;
  /* Delete any routers whose fingerprints we no longer recognize */
281
  directory_remove_invalid();
282
  return 0;
283
}
284

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

296
  if (crypto_pk_get_digest(router->identity_pkey, d)) {
297
    log_warn(LD_BUG,"Error computing fingerprint");
298
299
    if (msg)
      *msg = "Bug: Error computing fingerprint";
300
    return FP_REJECT;
301
302
  }

303
  return dirserv_get_status_impl(d, router->nickname,
304
305
306
307
308
309
310
311
312
313
314
                                 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)
{
315
  uint32_t res;
316

317
  res = dirserv_get_status_impl(rs->identity_digest, rs->nickname,
318
319
320
321
322
                                "", /* address is only used in logs */
                                rs->addr, rs->or_port,
                                NULL, NULL,
                                NULL, 0);

323
  return (res & FP_REJECT) != 0;
324
325
}

326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
/** 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;
}

348
349
350
351
352
353
354
/** 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.)
 */
355
356
static uint32_t
dirserv_get_status_impl(const char *id_digest, const char *nickname,
357
358
359
360
361
                        const char *address,
                        uint32_t addr, uint16_t or_port,
                        const char *platform, const char *contact,
                        const char **msg, int should_log)
{
362
  int reject_unlisted = get_options()->AuthDirRejectUnlisted;
363
364
  uint32_t result = 0;
  router_status_t *status_by_digest;
365

366
  if (!fingerprint_list)
367
368
    fingerprint_list = authdir_config_new();

369
  if (should_log)
370
371
    log_debug(LD_DIRSERV, "%d fingerprints, %d digests known.",
              strmap_size(fingerprint_list->fp_by_name),
372
              digestmap_size(fingerprint_list->status_by_digest));
373

374
375
376
377
  /* Tor 0.1.2.x is pretty old, but there are a lot of them running still,
   * and there aren't any critical relay-side vulnerabilities. Once more
   * of them die off, we should raise this minimum to 0.2.0.x. */
  if (platform && !tor_version_as_new_as(platform,"0.1.2.14")) {
378
379
380
381
382
    if (msg)
      *msg = "Tor version is far too old to work.";
    return FP_REJECT;
  }

383
384
385
386
387
388
389
390
  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);
391
      log_info(LD_DIRSERV,
392
393
394
395
396
397
               "Mismatched fingerprint for '%s'. "
               "ContactInfo '%s', platform '%s'.)",
               nickname,
               esc_contact,
               platform ? escaped(platform) : "");
      tor_free(esc_contact);
398
    }
399
400
401
    if (msg)
      *msg = "Rejected: There is already a named server with this nickname "
        "and a different fingerprint.";
402
  }
403

404
405
  status_by_digest = digestmap_get(fingerprint_list->status_by_digest,
                                   id_digest);
406
407
  if (status_by_digest)
    result |= (status_by_digest->status & ~FP_NAMED);
408
409
410
411
412
413
414
415
416

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

418
419
420
421
422
423
424
425
  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;
  }

426
427
428
429
430
431
432
433
  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)) {
434
    if (!authdir_policy_permits_address(addr, or_port)) {
435
      if (should_log)
436
437
        log_info(LD_DIRSERV, "Rejecting '%s' because of address '%s'",
                 nickname, address);
438
439
440
441
      if (msg)
        *msg = "Authdir is rejecting routers in this range.";
      return FP_REJECT;
    }
442
    if (!authdir_policy_valid_address(addr, or_port)) {
443
      if (should_log)
444
445
        log_info(LD_DIRSERV, "Not marking '%s' valid because of address '%s'",
                 nickname, address);
446
      result |= FP_INVALID;
447
    }
448
449
450
    if (reject_unlisted) {
      if (msg)
        *msg = "Authdir rejects unknown routers.";
451
      return FP_REJECT;
452
    }
453
  }
454
455

  return result;
456
457
}

458
/** If we are an authoritative dirserver, and the list of approved
459
460
 * servers contains one whose identity key digest is <b>digest</b>,
 * return that router's nickname.  Otherwise return NULL. */
461
462
const char *
dirserv_get_nickname_by_digest(const char *digest)
463
{
464
  router_status_t *status;
465
  if (!fingerprint_list)
466
467
468
    return NULL;
  tor_assert(digest);

469
470
  status = digestmap_get(fingerprint_list->status_by_digest, digest);
  return status ? status->nickname : NULL;
471
472
}

Roger Dingledine's avatar
Roger Dingledine committed
473
/** Clear the current fingerprint list. */
Roger Dingledine's avatar
Roger Dingledine committed
474
void
475
dirserv_free_fingerprint_list(void)
476
{
477
478
479
  if (!fingerprint_list)
    return;

480
481
482
  strmap_free(fingerprint_list->fp_by_name, _tor_free);
  digestmap_free(fingerprint_list->status_by_digest, _tor_free);
  tor_free(fingerprint_list);
483
484
485
486
487
}

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

489
490
491
492
493
494
495
496
497
/** 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)) {
498
499
    log_info(LD_DIRSERV,"Router '%s' published non-IP address '%s'. Refusing.",
             ri->nickname, ri->address);
500
501
    return -1;
  }
502
  if (is_internal_IP(ntohl(iaddr.s_addr), 0)) {
503
504
505
    log_info(LD_DIRSERV,
             "Router '%s' published internal IP address '%s'. Refusing.",
             ri->nickname, ri->address);
506
507
508
509
510
    return -1; /* it's a private IP, we should reject it */
  }
  return 0;
}

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

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

568
569
570
  return 0;
}

571
/** True iff <b>a</b> is more severe than <b>b</b>. */
572
573
574
static int
WRA_MORE_SEVERE(was_router_added_t a, was_router_added_t b)
{
575
  return a < b;
576
577
}

578
/** As for dirserv_add_descriptor(), but accepts multiple documents, and
579
 * returns the most severe error that occurred for any one of them. */
580
was_router_added_t
581
dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
582
                                 const char *source,
583
                                 const char **msg)
584
{
585
  was_router_added_t r, r_tmp;
586
  const char *msg_out;
587
588
589
  smartlist_t *list;
  const char *s;
  int n_parsed = 0;
590
  time_t now = time(NULL);
Roger Dingledine's avatar
Roger Dingledine committed
591
  char annotation_buf[ROUTER_ANNOTATION_BUF_LEN];
592
593
  char time_buf[ISO_TIME_LEN+1];
  int general = purpose == ROUTER_PURPOSE_GENERAL;
594
  tor_assert(msg);
595

596
  r=ROUTER_ADDED_SUCCESSFULLY; /*Least severe return value. */
597

598
599
600
601
602
603
604
605
606
607
608
609
  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;
  }

610
611
  s = desc;
  list = smartlist_create();
612
  if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 0, 0,
613
                                     annotation_buf)) {
614
    SMARTLIST_FOREACH(list, routerinfo_t *, ri, {
615
        msg_out = NULL;
616
        tor_assert(ri->purpose == purpose);
617
        r_tmp = dirserv_add_descriptor(ri, &msg_out, source);
618
        if (WRA_MORE_SEVERE(r_tmp, r)) {
619
620
621
622
          r = r_tmp;
          *msg = msg_out;
        }
      });
623
  }
624
625
626
627
  n_parsed += smartlist_len(list);
  smartlist_clear(list);

  s = desc;
628
629
  if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 1, 0,
                                     NULL)) {
630
    SMARTLIST_FOREACH(list, extrainfo_t *, ei, {
631
        msg_out = NULL;
632

633
        r_tmp = dirserv_add_extrainfo(ei, &msg_out);
634
        if (WRA_MORE_SEVERE(r_tmp, r)) {
635
636
637
638
639
640
641
          r = r_tmp;
          *msg = msg_out;
        }
      });
  }
  n_parsed += smartlist_len(list);
  smartlist_free(list);
642

643
644
645
  if (! *msg) {
    if (!n_parsed) {
      *msg = "No descriptors found in your POST.";
646
647
      if (WRA_WAS_ADDED(r))
        r = ROUTER_WAS_NOT_NEW;
648
649
650
651
652
    } else {
      *msg = "(no message)";
    }
  }

653
  return r;
654
655
}

656
657
/** 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
658
659
 * passed back to the origin of this descriptor, or NULL if there is no such
 * message. Use <b>source</b> to produce better log messages.
660
 *
661
 * Return the status of the operation
662
663
664
 *
 * This function is only called when fresh descriptors are posted, not when
 * we re-load the cache.
665
 */
666
was_router_added_t
667
dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source)
668
{
669
  was_router_added_t r;
670
  routerinfo_t *ri_old;
671
  char *desc, *nickname;
672
  size_t desclen = 0;
673
  *msg = NULL;
674

675
676
677
  /* 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) {
678
679
    log_notice(LD_DIR, "Somebody attempted to publish a router descriptor '%s'"
               " (source: %s) with size %d. Either this is an attack, or the "
680
               "MAX_DESCRIPTOR_UPLOAD_SIZE (%d) constant is too low.",
681
               ri->nickname, source, (int)ri->cache_info.signed_descriptor_len,
682
683
684
685
686
687
               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);
688
    return ROUTER_AUTHDIR_REJECTS;
689
690
  }

691
692
693
694
  /* 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.) */
695
696
  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
697
698
      && router_differences_are_cosmetic(ri_old, ri)
      && !router_is_me(ri)) {
699
    log_info(LD_DIRSERV,
700
701
702
             "Not replacing descriptor from '%s' (source: %s); "
             "differences are cosmetic.",
             ri->nickname, source);
703
704
    *msg = "Not replacing router descriptor; no information has changed since "
      "the last one with this identity.";
705
706
707
    control_event_or_authdir_new_descriptor("DROPPED",
                         ri->cache_info.signed_descriptor_body,
                         ri->cache_info.signed_descriptor_len, *msg);
708
    routerinfo_free(ri);
709
    return ROUTER_WAS_NOT_NEW;
710
  }
711
712
713
714
715
716

  /* 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);
  nickname = tor_strdup(ri->nickname);
717

718
719
720
  r = router_add_to_routerlist(ri, msg, 0, 0);
  if (!WRA_WAS_ADDED(r)) {
    /* unless the routerinfo was fine, just out-of-date */
721
    if (WRA_WAS_REJECTED(r))
722
      control_event_or_authdir_new_descriptor("REJECTED", desc, desclen, *msg);
723
724
    log_info(LD_DIRSERV,
             "Did not add descriptor from '%s' (source: %s): %s.",
725
             nickname, source, *msg ? *msg : "(no message)");
726
  } else {
727
    smartlist_t *changed;
728
    control_event_or_authdir_new_descriptor("ACCEPTED", desc, desclen, *msg);
729

730
    changed = smartlist_create();
731
732
733
    smartlist_add(changed, ri);
    control_event_descriptors_changed(changed);
    smartlist_free(changed);
734
    if (!*msg) {
735
736
      *msg =  ri->is_valid ? "Descriptor for valid server accepted" :
        "Descriptor for invalid server accepted";
737
    }
738
739
740
    log_info(LD_DIRSERV,
             "Added descriptor from '%s' (source: %s): %s.",
             nickname, source, *msg);
741
  }
742
743
  tor_free(desc);
  tor_free(nickname);
744
  return r;
745
746
}

747
/** As dirserv_add_descriptor, but for an extrainfo_t <b>ei</b>. */
748
static was_router_added_t
749
750
751
dirserv_add_extrainfo(extrainfo_t *ei, const char **msg)
{
  routerinfo_t *ri;
752
  int r;
753
754
755
756
757
758
759
  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);
760
    return ROUTER_BAD_EI;
761
  }
762
763
764
765
766
767
768
769
770
771
772

  /* 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);
773
    return ROUTER_BAD_EI;
774
775
  }

776
  if ((r = routerinfo_incompatible_with_extrainfo(ri, ei, NULL, msg))) {
777
    extrainfo_free(ei);
778
    return r < 0 ? ROUTER_WAS_NOT_NEW : ROUTER_BAD_EI;
779
780
  }
  router_add_extrainfo_to_routerlist(ei, msg, 0, 0);
781
  return ROUTER_ADDED_SUCCESSFULLY;
782
783
}

784
785
786
/** 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
787
 */
788
static void
789
directory_remove_invalid(void)
790
791
{
  int i;
792
  int changed = 0;
793
  routerlist_t *rl = router_get_routerlist();
794

795
796
  routerlist_assert_ok(rl);

797
  for (i = 0; i < smartlist_len(rl->routers); ++i) {
798
    const char *msg;
799
    routerinfo_t *ent = smartlist_get(rl->routers, i);
800
801
802
803
    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:"");
804
      routerlist_remove(rl, ent, 0, time(NULL));
805
      i--;
806
      changed = 1;
807
      continue;
808
    }
809
    if (bool_neq((r & FP_NAMED), ent->is_named)) {
810
811
812
813
814
815
      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;
    }
816
    if (bool_neq((r & FP_INVALID), !ent->is_valid)) {
817
818
819
820
821
      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;
    }
822
823
824
825
826
827
    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;
    }
828
    if (bool_neq((r & FP_BADEXIT), ent->is_bad_exit)) {
829
830
831
832
      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;
833
834
    }
  }
835
836
  if (changed)
    directory_set_dirty();
837
838

  routerlist_assert_ok(rl);
839
840
}

Nick Mathewson's avatar
Nick Mathewson committed
841
/** Mark the directory as <b>dirty</b> -- when we're next asked for a
Nick Mathewson's avatar
Nick Mathewson committed
842
843
844
 * directory, we will rebuild it instead of reusing the most recently
 * generated one.
 */
Roger Dingledine's avatar
Roger Dingledine committed
845
void
846
directory_set_dirty(void)
847
{
848
  time_t now = time(NULL);
849
  int set_v1_dirty=0;
850

851
  /* Regenerate stubs only every 8 hours.
852
853
   * XXXX It would be nice to generate less often, but these are just
   * stubs: it doesn't matter. */
854
855
856
857
858
859
860
861
862
863
864
865
866
#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;
  }
867
868
  if (!the_v2_networkstatus_is_dirty)
    the_v2_networkstatus_is_dirty = now;
869
870
}

871
872
/**
 * Allocate and return a description of the status of the server <b>desc</b>,
873
 * for use in a v1-style router-status line.  The server is listed
874
 * as running iff <b>is_live</b> is true.
Nick Mathewson's avatar
Nick Mathewson committed
875
 */
876
static char *
877
list_single_server_status(routerinfo_t *desc, int is_live)
878
{
879
  char buf[MAX_NICKNAME_LEN+HEX_DIGEST_LEN+4]; /* !nickname=$hexdigest\0 */
880
  char *cp;
881

882
883
884
885
886
887
  tor_assert(desc);

  cp = buf;
  if (!is_live) {
    *cp++ = '!';
  }
888
  if (desc->is_valid) {
Nick Mathewson's avatar
Nick Mathewson committed
889
    strlcpy(cp, desc->nickname, sizeof(buf)-(cp-buf));
890
    cp += strlen(cp);
891
    *cp++ = '=';
892
  }
893
  *cp++ = '$';
894
  base16_encode(cp,