tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

fmt_routerstatus.c (9143B)


      1 /* Copyright (c) 2001-2004, Roger Dingledine.
      2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
      4 /* See LICENSE for licensing information */
      5 
      6 /**
      7 * \file fmt_routerstatus.h
      8 * \brief Format routerstatus entries for controller, vote, or consensus.
      9 *
     10 * (Because controllers consume this format, we can't make this
     11 * code dirauth-only.)
     12 **/
     13 
     14 #include "core/or/or.h"
     15 #include "feature/nodelist/fmt_routerstatus.h"
     16 
     17 #include "core/or/policies.h"
     18 #include "feature/dirauth/dirvote.h"
     19 #include "feature/nodelist/routerinfo_st.h"
     20 #include "feature/nodelist/routerlist.h"
     21 #include "feature/nodelist/vote_routerstatus_st.h"
     22 #include "feature/stats/rephist.h"
     23 
     24 #include "lib/crypt_ops/crypto_format.h"
     25 
     26 /** Helper: write the router-status information in <b>rs</b> into a newly
     27 * allocated character buffer.  Use the same format as in network-status
     28 * documents.  If <b>version</b> is non-NULL, add a "v" line for the platform.
     29 * If <b>declared_publish_time</b> is nonnegative, we declare it as the
     30 * publication time.  Otherwise we look for a publication time in <b>vrs</b>,
     31 * and fall back to a default (not useful) publication time.
     32 *
     33 * Return 0 on success, -1 on failure.
     34 *
     35 * The format argument has one of the following values:
     36 *   NS_V2 - Output an entry suitable for a V2 NS opinion document
     37 *   NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry
     38 *        for consensus_method.
     39 *   NS_V3_CONSENSUS_MICRODESC - Output the first portion of a V3 microdesc
     40 *        consensus entry for consensus_method.
     41 *   NS_V3_VOTE - Output a complete V3 NS vote. If <b>vrs</b> is present,
     42 *        it contains additional information for the vote.
     43 *   NS_CONTROL_PORT - Output a NS document for the control port.
     44 *
     45 */
     46 char *
     47 routerstatus_format_entry(const routerstatus_t *rs, const char *version,
     48                          const char *protocols,
     49                          routerstatus_format_type_t format,
     50                          const vote_routerstatus_t *vrs,
     51                          time_t declared_publish_time)
     52 {
     53  char *summary;
     54  char *result = NULL;
     55 
     56  char published[ISO_TIME_LEN+1];
     57  char identity64[BASE64_DIGEST_LEN+1];
     58  char digest64[BASE64_DIGEST_LEN+1];
     59  smartlist_t *chunks = smartlist_new();
     60 
     61  if (declared_publish_time >= 0) {
     62    format_iso_time(published, declared_publish_time);
     63  } else if (vrs) {
     64    format_iso_time(published, vrs->published_on);
     65  } else {
     66    strlcpy(published, "2038-01-01 00:00:00", sizeof(published));
     67  }
     68 
     69  const char *ip_str = fmt_addr(&rs->ipv4_addr);
     70  if (ip_str[0] == '\0')
     71    goto err;
     72 
     73  digest_to_base64(identity64, rs->identity_digest);
     74  digest_to_base64(digest64, rs->descriptor_digest);
     75 
     76  smartlist_add_asprintf(chunks,
     77                   "r %s %s %s%s%s %s %" PRIu16 " %" PRIu16 "\n",
     78                   rs->nickname,
     79                   identity64,
     80                   (format==NS_V3_CONSENSUS_MICRODESC)?"":digest64,
     81                   (format==NS_V3_CONSENSUS_MICRODESC)?"":" ",
     82                   published,
     83                   ip_str,
     84                   rs->ipv4_orport,
     85                   rs->ipv4_dirport);
     86 
     87  /* TODO: Maybe we want to pass in what we need to build the rest of
     88   * this here, instead of in the caller. Then we could use the
     89   * networkstatus_type_t values, with an additional control port value
     90   * added -MP */
     91 
     92  /* Possible "a" line. At most one for now. */
     93  if (!tor_addr_is_null(&rs->ipv6_addr)) {
     94    smartlist_add_asprintf(chunks, "a %s\n",
     95                           fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport));
     96  }
     97 
     98  if (format == NS_V3_CONSENSUS || format == NS_V3_CONSENSUS_MICRODESC)
     99    goto done;
    100 
    101  smartlist_add_asprintf(chunks,
    102                   "s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
    103                  /* These must stay in alphabetical order. */
    104                   rs->is_authority?" Authority":"",
    105                   rs->is_bad_exit?" BadExit":"",
    106                   rs->is_exit?" Exit":"",
    107                   rs->is_fast?" Fast":"",
    108                   rs->is_possible_guard?" Guard":"",
    109                   rs->is_hs_dir?" HSDir":"",
    110                   rs->is_middle_only?" MiddleOnly":"",
    111                   rs->is_flagged_running?" Running":"",
    112                   rs->is_stable?" Stable":"",
    113                   rs->is_staledesc?" StaleDesc":"",
    114                   rs->is_sybil?" Sybil":"",
    115                   rs->is_v2_dir?" V2Dir":"",
    116                   rs->is_valid?" Valid":"");
    117 
    118  /* length of "opt v \n" */
    119 #define V_LINE_OVERHEAD 7
    120  if (version && strlen(version) < MAX_V_LINE_LEN - V_LINE_OVERHEAD) {
    121    smartlist_add_asprintf(chunks, "v %s\n", version);
    122  }
    123  if (protocols) {
    124    smartlist_add_asprintf(chunks, "pr %s\n", protocols);
    125  }
    126 
    127  if (format != NS_V2) {
    128    const routerinfo_t* desc = router_get_by_id_digest(rs->identity_digest);
    129    uint32_t bw_kb;
    130 
    131    if (format != NS_CONTROL_PORT) {
    132      /* Blow up more or less nicely if we didn't get anything or not the
    133       * thing we expected.
    134       * This should be kept in sync with the function
    135       * routerstatus_has_visibly_changed and the struct routerstatus_t
    136       */
    137      if (!desc) {
    138        char id[HEX_DIGEST_LEN+1];
    139        char dd[HEX_DIGEST_LEN+1];
    140 
    141        base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
    142        base16_encode(dd, sizeof(dd), rs->descriptor_digest, DIGEST_LEN);
    143        log_warn(LD_BUG, "Cannot get any descriptor for %s "
    144            "(wanted descriptor %s).",
    145            id, dd);
    146        goto err;
    147      }
    148 
    149      /* This assert could fire for the control port, because
    150       * it can request NS documents before all descriptors
    151       * have been fetched. Therefore, we only do this test when
    152       * format != NS_CONTROL_PORT. */
    153      if (tor_memneq(desc->cache_info.signed_descriptor_digest,
    154            rs->descriptor_digest,
    155            DIGEST_LEN)) {
    156        char rl_d[HEX_DIGEST_LEN+1];
    157        char rs_d[HEX_DIGEST_LEN+1];
    158        char id[HEX_DIGEST_LEN+1];
    159 
    160        base16_encode(rl_d, sizeof(rl_d),
    161            desc->cache_info.signed_descriptor_digest, DIGEST_LEN);
    162        base16_encode(rs_d, sizeof(rs_d), rs->descriptor_digest, DIGEST_LEN);
    163        base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
    164        log_err(LD_BUG, "descriptor digest in routerlist does not match "
    165            "the one in routerstatus: %s vs %s "
    166            "(router %s)\n",
    167            rl_d, rs_d, id);
    168 
    169        tor_assert(tor_memeq(desc->cache_info.signed_descriptor_digest,
    170              rs->descriptor_digest,
    171              DIGEST_LEN));
    172      }
    173    }
    174 
    175    if (format == NS_CONTROL_PORT && rs->has_bandwidth) {
    176      bw_kb = rs->bandwidth_kb;
    177    } else {
    178      tor_assert(desc);
    179      bw_kb = router_get_advertised_bandwidth_capped(desc) / 1000;
    180    }
    181    smartlist_add_asprintf(chunks,
    182                     "w Bandwidth=%d", bw_kb);
    183 
    184    /* Include the bandwidth weight from our external bandwidth
    185     * authority, if we have one. */
    186    if (format == NS_V3_VOTE && vrs && vrs->has_measured_bw) {
    187      if (!rs->is_authority) { /* normal case */
    188        smartlist_add_asprintf(chunks,
    189                         " Measured=%d", vrs->measured_bw_kb);
    190      } else {
    191       /* dir auth special case: don't give it a Measured line, so we
    192        * can reserve its attention for authority-specific activities.
    193        * But do include the bwauth's opinion so it can be recorded for
    194        * posterity. See #40698 for details. */
    195        smartlist_add_asprintf(chunks,
    196                         " MeasuredButAuthority=%d", vrs->measured_bw_kb);
    197      }
    198    }
    199    /* Write down guardfraction information if we have it. */
    200    if (format == NS_V3_VOTE && vrs && vrs->status.has_guardfraction) {
    201      smartlist_add_asprintf(chunks,
    202                             " GuardFraction=%d",
    203                             vrs->status.guardfraction_percentage);
    204    }
    205 
    206    smartlist_add_strdup(chunks, "\n");
    207 
    208    if (desc) {
    209      summary = policy_summarize(desc->exit_policy, AF_INET);
    210      smartlist_add_asprintf(chunks, "p %s\n", summary);
    211      tor_free(summary);
    212    }
    213 
    214    if (format == NS_V3_VOTE && vrs) {
    215      if (fast_mem_is_zero((char*)vrs->ed25519_id, ED25519_PUBKEY_LEN)) {
    216        smartlist_add_strdup(chunks, "id ed25519 none\n");
    217      } else {
    218        char ed_b64[BASE64_DIGEST256_LEN+1];
    219        digest256_to_base64(ed_b64, (const char*)vrs->ed25519_id);
    220        smartlist_add_asprintf(chunks, "id ed25519 %s\n", ed_b64);
    221      }
    222 
    223      /* We'll add a series of statistics to the vote per relays so we are
    224       * able to assess what each authorities sees and help our health and
    225       * performance work. */
    226      time_t now = time(NULL);
    227      smartlist_add_asprintf(chunks, "stats wfu=%.6f tk=%lu mtbf=%.0f\n",
    228        rep_hist_get_weighted_fractional_uptime(rs->identity_digest, now),
    229        rep_hist_get_weighted_time_known(rs->identity_digest, now),
    230        rep_hist_get_stability(rs->identity_digest, now));
    231    }
    232  }
    233 
    234 done:
    235  result = smartlist_join_strings(chunks, "", 0, NULL);
    236 
    237 err:
    238  SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
    239  smartlist_free(chunks);
    240 
    241  return result;
    242 }