⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 router.c

📁 关于tor匿名通信的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
  /* OP's don't need persistent keys; just make up an identity and
   * initialize the TLS context. */
  if (!server_mode(options)) {
    if (!(prkey = crypto_new_pk_env()))
      return -1;
    if (crypto_pk_generate_key(prkey)) {
      crypto_free_pk_env(prkey);
      return -1;
    }
    set_identity_key(prkey);
    /* Create a TLS context; default the client nickname to "client". */
    if (tor_tls_context_new(get_identity_key(), MAX_SSL_KEY_LIFETIME) < 0) {
      log_err(LD_GENERAL,"Error creating TLS context for Tor client.");
      return -1;
    }
    return 0;
  }
  /* Make sure DataDirectory exists, and is private. */
  if (check_private_dir(options->DataDirectory, CPD_CREATE)) {
    return -1;
  }
  /* Check the key directory. */
  keydir = get_datadir_fname("keys");
  if (check_private_dir(keydir, CPD_CREATE)) {
    tor_free(keydir);
    return -1;
  }
  tor_free(keydir);

  /* 1a. Read v3 directory authority key/cert information. */
  memset(v3_digest, 0, sizeof(v3_digest));
  if (authdir_mode_v3(options)) {
    if (init_v3_authority_keys()<0) {
      log_err(LD_GENERAL, "We're configured as a V3 authority, but we "
              "were unable to load our v3 authority keys and certificate! "
              "Use tor-gencert to generate them. Dying.");
      return -1;
    }
    cert = get_my_v3_authority_cert();
    if (cert) {
      crypto_pk_get_digest(get_my_v3_authority_cert()->identity_key,
                           v3_digest);
      v3_digest_set = 1;
    }
  }

  /* 1. Read identity key. Make it if none is found. */
  keydir = get_datadir_fname2("keys", "secret_id_key");
  log_info(LD_GENERAL,"Reading/making identity key \"%s\"...",keydir);
  prkey = init_key_from_file(keydir, 1, LOG_ERR);
  tor_free(keydir);
  if (!prkey) return -1;
  set_identity_key(prkey);

  /* 2. Read onion key.  Make it if none is found. */
  keydir = get_datadir_fname2("keys", "secret_onion_key");
  log_info(LD_GENERAL,"Reading/making onion key \"%s\"...",keydir);
  prkey = init_key_from_file(keydir, 1, LOG_ERR);
  tor_free(keydir);
  if (!prkey) return -1;
  set_onion_key(prkey);
  if (options->command == CMD_RUN_TOR) {
    /* only mess with the state file if we're actually running Tor */
    or_state_t *state = get_or_state();
    if (state->LastRotatedOnionKey > 100 && state->LastRotatedOnionKey < now) {
      /* We allow for some parsing slop, but we don't want to risk accepting
       * values in the distant future.  If we did, we might never rotate the
       * onion key. */
      onionkey_set_at = state->LastRotatedOnionKey;
    } else {
      /* We have no LastRotatedOnionKey set; either we just created the key
       * or it's a holdover from 0.1.2.4-alpha-dev or earlier.  In either case,
       * start the clock ticking now so that we will eventually rotate it even
       * if we don't stay up for a full MIN_ONION_KEY_LIFETIME. */
      state->LastRotatedOnionKey = onionkey_set_at = now;
      or_state_mark_dirty(state, options->AvoidDiskWrites ?
                                   time(NULL)+3600 : 0);
    }
  }

  keydir = get_datadir_fname2("keys", "secret_onion_key.old");
  if (!lastonionkey && file_status(keydir) == FN_FILE) {
    prkey = init_key_from_file(keydir, 1, LOG_ERR);
    if (prkey)
      lastonionkey = prkey;
  }
  tor_free(keydir);

  /* 3. Initialize link key and TLS context. */
  if (tor_tls_context_new(get_identity_key(), MAX_SSL_KEY_LIFETIME) < 0) {
    log_err(LD_GENERAL,"Error initializing TLS context");
    return -1;
  }
  /* 4. Build our router descriptor. */
  /* Must be called after keys are initialized. */
  mydesc = router_get_my_descriptor();
  if (authdir_mode(options)) {
    const char *m;
    routerinfo_t *ri;
    /* We need to add our own fingerprint so it gets recognized. */
    if (dirserv_add_own_fingerprint(options->Nickname, get_identity_key())) {
      log_err(LD_GENERAL,"Error adding own fingerprint to approved set");
      return -1;
    }
    if (mydesc) {
      ri = router_parse_entry_from_string(mydesc, NULL, 1, 0, NULL);
      if (!ri) {
        log_err(LD_GENERAL,"Generated a routerinfo we couldn't parse.");
        return -1;
      }
      if (dirserv_add_descriptor(ri, &m) < 0) {
        log_err(LD_GENERAL,"Unable to add own descriptor to directory: %s",
                m?m:"<unknown error>");
        return -1;
      }
    }
  }

  /* 5. Dump fingerprint to 'fingerprint' */
  keydir = get_datadir_fname("fingerprint");
  log_info(LD_GENERAL,"Dumping fingerprint to \"%s\"...",keydir);
  if (crypto_pk_get_fingerprint(get_identity_key(), fingerprint, 1)<0) {
    log_err(LD_GENERAL,"Error computing fingerprint");
    tor_free(keydir);
    return -1;
  }
  tor_assert(strlen(options->Nickname) <= MAX_NICKNAME_LEN);
  if (tor_snprintf(fingerprint_line, sizeof(fingerprint_line),
                   "%s %s\n",options->Nickname, fingerprint) < 0) {
    log_err(LD_GENERAL,"Error writing fingerprint line");
    tor_free(keydir);
    return -1;
  }
  /* Check whether we need to write the fingerprint file. */
  cp = NULL;
  if (file_status(keydir) == FN_FILE)
    cp = read_file_to_str(keydir, 0, NULL);
  if (!cp || strcmp(cp, fingerprint_line)) {
    if (write_str_to_file(keydir, fingerprint_line, 0)) {
      log_err(LD_FS, "Error writing fingerprint line to file");
      tor_free(keydir);
      return -1;
    }
  }
  tor_free(cp);
  tor_free(keydir);

  log(LOG_NOTICE, LD_GENERAL,
      "Your Tor server's identity key fingerprint is '%s %s'",
      options->Nickname, fingerprint);
  if (!authdir_mode(options))
    return 0;
  /* 6. [authdirserver only] load approved-routers file */
  if (dirserv_load_fingerprint_file() < 0) {
    log_err(LD_GENERAL,"Error loading fingerprints");
    return -1;
  }
  /* 6b. [authdirserver only] add own key to approved directories. */
  crypto_pk_get_digest(get_identity_key(), digest);
  type = ((options->V1AuthoritativeDir ? V1_AUTHORITY : NO_AUTHORITY) |
          (options->V2AuthoritativeDir ? V2_AUTHORITY : NO_AUTHORITY) |
          (options->V3AuthoritativeDir ? V3_AUTHORITY : NO_AUTHORITY) |
          (options->BridgeAuthoritativeDir ? BRIDGE_AUTHORITY : NO_AUTHORITY) |
          (options->HSAuthoritativeDir ? HIDSERV_AUTHORITY : NO_AUTHORITY));

  ds = router_get_trusteddirserver_by_digest(digest);
  if (!ds) {
    ds = add_trusted_dir_server(options->Nickname, NULL,
                                (uint16_t)options->DirPort,
                                (uint16_t)options->ORPort,
                                digest,
                                v3_digest,
                                type);
    if (!ds) {
      log_err(LD_GENERAL,"We want to be a directory authority, but we "
              "couldn't add ourselves to the authority list. Failing.");
      return -1;
    }
  }
  if (ds->type != type) {
    log_warn(LD_DIR,  "Configured authority type does not match authority "
             "type in DirServer list.  Adjusting. (%d v %d)",
             type, ds->type);
    ds->type = type;
  }
  if (v3_digest_set && (ds->type & V3_AUTHORITY) &&
      memcmp(v3_digest, ds->v3_identity_digest, DIGEST_LEN)) {
    log_warn(LD_DIR, "V3 identity key does not match identity declared in "
             "DirServer line.  Adjusting.");
    memcpy(ds->v3_identity_digest, v3_digest, DIGEST_LEN);
  }

  if (cert) { /* add my own cert to the list of known certs */
    log_info(LD_DIR, "adding my own v3 cert");
    if (trusted_dirs_load_certs_from_string(
                      cert->cache_info.signed_descriptor_body, 0, 0)<0) {
      log_warn(LD_DIR, "Unable to parse my own v3 cert! Failing.");
      return -1;
    }
  }

  return 0; /* success */
}

/* Keep track of whether we should upload our server descriptor,
 * and what type of server we are.
 */

/** Whether we can reach our ORPort from the outside. */
static int can_reach_or_port = 0;
/** Whether we can reach our DirPort from the outside. */
static int can_reach_dir_port = 0;

/** Forget what we have learned about our reachability status. */
void
router_reset_reachability(void)
{
  can_reach_or_port = can_reach_dir_port = 0;
}

/** Return 1 if ORPort is known reachable; else return 0. */
int
check_whether_orport_reachable(void)
{
  or_options_t *options = get_options();
  return options->AssumeReachable ||
         can_reach_or_port;
}

/** Return 1 if we don't have a dirport configured, or if it's reachable. */
int
check_whether_dirport_reachable(void)
{
  or_options_t *options = get_options();
  return !options->DirPort ||
         options->AssumeReachable ||
         we_are_hibernating() ||
         can_reach_dir_port;
}

/** Look at a variety of factors, and return 0 if we don't want to
 * advertise the fact that we have a DirPort open. Else return the
 * DirPort we want to advertise.
 *
 * Log a helpful message if we change our mind about whether to publish
 * a DirPort.
 */
static int
decide_to_advertise_dirport(or_options_t *options, uint16_t dir_port)
{
  static int advertising=1; /* start out assuming we will advertise */
  int new_choice=1;
  const char *reason = NULL;

  /* Section one: reasons to publish or not publish that aren't
   * worth mentioning to the user, either because they're obvious
   * or because they're normal behavior. */

  if (!dir_port) /* short circuit the rest of the function */
    return 0;
  if (authdir_mode(options)) /* always publish */
    return dir_port;
  if (we_are_hibernating())
    return 0;
  if (!check_whether_dirport_reachable())
    return 0;

  /* Section two: reasons to publish or not publish that the user
   * might find surprising. These are generally config options that
   * make us choose not to publish. */

  if (accounting_is_enabled(options)) {
    /* if we might potentially hibernate */
    new_choice = 0;
    reason = "AccountingMax enabled";
#define MIN_BW_TO_ADVERTISE_DIRPORT 51200
  } else if (options->BandwidthRate < MIN_BW_TO_ADVERTISE_DIRPORT ||
             (options->RelayBandwidthRate > 0 &&
              options->RelayBandwidthRate < MIN_BW_TO_ADVERTISE_DIRPORT)) {
    /* if we're advertising a small amount */
    new_choice = 0;
    reason = "BandwidthRate under 50KB";
  }

  if (advertising != new_choice) {
    if (new_choice == 1) {
      log(LOG_NOTICE, LD_DIR, "Advertising DirPort as %d", dir_port);
    } else {
      tor_assert(reason);
      log(LOG_NOTICE, LD_DIR, "Not advertising DirPort (Reason: %s)", reason);
    }
    advertising = new_choice;
  }

  return advertising ? dir_port : 0;
}

/** Some time has passed, or we just got new directory information.
 * See if we currently believe our ORPort or DirPort to be
 * unreachable. If so, launch a new test for it.
 *
 * For ORPort, we simply try making a circuit that ends at ourselves.
 * Success is noticed in onionskin_answer().
 *
 * For DirPort, we make a connection via Tor to our DirPort and ask
 * for our own server descriptor.
 * Success is noticed in connection_dir_client_reached_eof().
 */
void
consider_testing_reachability(int test_or, int test_dir)
{
  routerinfo_t *me = router_get_my_routerinfo();
  int orport_reachable = check_whether_orport_reachable();
  if (!me)
    return;

  if (test_or && (!orport_reachable || !circuit_enough_testing_circs())) {
    log_info(LD_CIRC, "Testing %s of my ORPort: %s:%d.",
             !orport_reachable ? "reachability" : "bandwidth",
             me->address, me->or_port);
    circuit_launch_by_router(CIRCUIT_PURPOSE_TESTING, me,
                             CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL);
    control_event_server_status(LOG_NOTICE,
                                "CHECKING_REACHABILITY ORADDRESS=%s:%d",
                                me->address, me->or_port);
  }

  if (test_dir && !check_whether_dirport_reachable() &&
      !connection_get_by_type_addr_port_purpose(
                CONN_TYPE_DIR, me->addr, me->dir_port,
                DIR_PURPOSE_FETCH_SERVERDESC)) {
    /* ask myself, via tor, for my server descriptor. */
    directory_initiate_command(me->address, me->addr,
                               me->or_port, me->dir_port,
                               0, /* does not matter */
                               0, me->cache_info.identity_digest,
                               DIR_PURPOSE_FETCH_SERVERDESC,
                               ROUTER_PURPOSE_GENERAL,
                               1, "authority.z", NULL, 0, 0);

    control_event_server_status(LOG_NOTICE,
                                "CHECKING_REACHABILITY DIRADDRESS=%s:%d",
                                me->address, me->dir_port);
  }
}

/** Annotate that we found our ORPort reachable. */
void
router_orport_found_reachable(void)
{
  if (!can_reach_or_port) {
    routerinfo_t *me = router_get_my_routerinfo();
    log_notice(LD_OR,"Self-testing indicates your ORPort is reachable from "
               "the outside. Excellent.%s",
               get_options()->_PublishServerDescriptor != NO_AUTHORITY ?
                 " Publishing server descriptor." : "");
    can_reach_or_port = 1;
    mark_my_descriptor_dirty();
    if (!me)
      return;
    control_event_server_status(LOG_NOTICE,
                                "REACHABILITY_SUCCEEDED ORADDRESS=%s:%d",
                                me->address, me->or_port);
  }
}

/** Annotate that we found our DirPort reachable. */
void
router_dirport_found_reachable(void)
{
  if (!can_reach_dir_port) {
    routerinfo_t *me = router_get_my_routerinfo();
    log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable "
               "from the outside. Excellent.");
    can_reach_dir_port = 1;
    if (!me || decide_to_advertise_dirport(get_options(), me->dir_port))
      mark_my_descriptor_dirty();
    if (!me)
      return;
    control_event_server_status(LOG_NOTICE,
                                "REACHABILITY_SUCCEEDED DIRADDRESS=%s:%d",
                                me->address, me->dir_port);
  }
}

/** We have enough testing circuits open. Send a bunch of "drop"
 * cells down each of them, to exercise our bandwidth. */
void
router_perform_bandwidth_test(int num_circs, time_t now)
{
  int num_cells = (int)(get_options()->BandwidthRate * 10 / CELL_NETWORK_SIZE);
  int max_cells = num_cells < CIRCWINDOW_START ?
                    num_cells : CIRCWINDOW_START;
  int cells_per_circuit = max_cells / num_circs;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -