LCOV - code coverage report
Current view: top level - feature/nodelist - fmt_routerstatus.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 69 89 77.5 %
Date: 2021-11-24 03:28:48 Functions: 1 1 100.0 %

          Line data    Source code
       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             :  *
      30             :  * Return 0 on success, -1 on failure.
      31             :  *
      32             :  * The format argument has one of the following values:
      33             :  *   NS_V2 - Output an entry suitable for a V2 NS opinion document
      34             :  *   NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry
      35             :  *        for consensus_method.
      36             :  *   NS_V3_CONSENSUS_MICRODESC - Output the first portion of a V3 microdesc
      37             :  *        consensus entry for consensus_method.
      38             :  *   NS_V3_VOTE - Output a complete V3 NS vote. If <b>vrs</b> is present,
      39             :  *        it contains additional information for the vote.
      40             :  *   NS_CONTROL_PORT - Output a NS document for the control port.
      41             :  */
      42             : char *
      43         239 : routerstatus_format_entry(const routerstatus_t *rs, const char *version,
      44             :                           const char *protocols,
      45             :                           routerstatus_format_type_t format,
      46             :                           const vote_routerstatus_t *vrs)
      47             : {
      48         239 :   char *summary;
      49         239 :   char *result = NULL;
      50             : 
      51         239 :   char published[ISO_TIME_LEN+1];
      52         239 :   char identity64[BASE64_DIGEST_LEN+1];
      53         239 :   char digest64[BASE64_DIGEST_LEN+1];
      54         239 :   smartlist_t *chunks = smartlist_new();
      55             : 
      56         239 :   const char *ip_str = fmt_addr(&rs->ipv4_addr);
      57         239 :   if (ip_str[0] == '\0')
      58           0 :     goto err;
      59             : 
      60         239 :   format_iso_time(published, rs->published_on);
      61         239 :   digest_to_base64(identity64, rs->identity_digest);
      62         239 :   digest_to_base64(digest64, rs->descriptor_digest);
      63             : 
      64         239 :   smartlist_add_asprintf(chunks,
      65             :                    "r %s %s %s%s%s %s %" PRIu16 " %" PRIu16 "\n",
      66         239 :                    rs->nickname,
      67             :                    identity64,
      68             :                    (format==NS_V3_CONSENSUS_MICRODESC)?"":digest64,
      69             :                    (format==NS_V3_CONSENSUS_MICRODESC)?"":" ",
      70             :                    published,
      71             :                    ip_str,
      72         239 :                    rs->ipv4_orport,
      73         239 :                    rs->ipv4_dirport);
      74             : 
      75             :   /* TODO: Maybe we want to pass in what we need to build the rest of
      76             :    * this here, instead of in the caller. Then we could use the
      77             :    * networkstatus_type_t values, with an additional control port value
      78             :    * added -MP */
      79             : 
      80             :   /* Possible "a" line. At most one for now. */
      81         239 :   if (!tor_addr_is_null(&rs->ipv6_addr)) {
      82          88 :     smartlist_add_asprintf(chunks, "a %s\n",
      83          88 :                            fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport));
      84             :   }
      85             : 
      86         239 :   if (format == NS_V3_CONSENSUS || format == NS_V3_CONSENSUS_MICRODESC)
      87          78 :     goto done;
      88             : 
      89         161 :   smartlist_add_asprintf(chunks,
      90             :                    "s%s%s%s%s%s%s%s%s%s%s%s%s\n",
      91             :                   /* These must stay in alphabetical order. */
      92         161 :                    rs->is_authority?" Authority":"",
      93         161 :                    rs->is_bad_exit?" BadExit":"",
      94         161 :                    rs->is_exit?" Exit":"",
      95         161 :                    rs->is_fast?" Fast":"",
      96         161 :                    rs->is_possible_guard?" Guard":"",
      97         161 :                    rs->is_hs_dir?" HSDir":"",
      98         161 :                    rs->is_flagged_running?" Running":"",
      99         161 :                    rs->is_stable?" Stable":"",
     100         161 :                    rs->is_staledesc?" StaleDesc":"",
     101         161 :                    rs->is_sybil?" Sybil":"",
     102         161 :                    rs->is_v2_dir?" V2Dir":"",
     103         161 :                    rs->is_valid?" Valid":"");
     104             : 
     105             :   /* length of "opt v \n" */
     106             : #define V_LINE_OVERHEAD 7
     107         161 :   if (version && strlen(version) < MAX_V_LINE_LEN - V_LINE_OVERHEAD) {
     108         108 :     smartlist_add_asprintf(chunks, "v %s\n", version);
     109             :   }
     110         161 :   if (protocols) {
     111         108 :     smartlist_add_asprintf(chunks, "pr %s\n", protocols);
     112             :   }
     113             : 
     114         161 :   if (format != NS_V2) {
     115         161 :     const routerinfo_t* desc = router_get_by_id_digest(rs->identity_digest);
     116         161 :     uint32_t bw_kb;
     117             : 
     118         161 :     if (format != NS_CONTROL_PORT) {
     119             :       /* Blow up more or less nicely if we didn't get anything or not the
     120             :        * thing we expected.
     121             :        * This should be kept in sync with the function
     122             :        * routerstatus_has_visibly_changed and the struct routerstatus_t
     123             :        */
     124         108 :       if (!desc) {
     125           0 :         char id[HEX_DIGEST_LEN+1];
     126           0 :         char dd[HEX_DIGEST_LEN+1];
     127             : 
     128           0 :         base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
     129           0 :         base16_encode(dd, sizeof(dd), rs->descriptor_digest, DIGEST_LEN);
     130           0 :         log_warn(LD_BUG, "Cannot get any descriptor for %s "
     131             :             "(wanted descriptor %s).",
     132             :             id, dd);
     133           0 :         goto err;
     134             :       }
     135             : 
     136             :       /* This assert could fire for the control port, because
     137             :        * it can request NS documents before all descriptors
     138             :        * have been fetched. Therefore, we only do this test when
     139             :        * format != NS_CONTROL_PORT. */
     140         108 :       if (tor_memneq(desc->cache_info.signed_descriptor_digest,
     141             :             rs->descriptor_digest,
     142             :             DIGEST_LEN)) {
     143           0 :         char rl_d[HEX_DIGEST_LEN+1];
     144           0 :         char rs_d[HEX_DIGEST_LEN+1];
     145           0 :         char id[HEX_DIGEST_LEN+1];
     146             : 
     147           0 :         base16_encode(rl_d, sizeof(rl_d),
     148             :             desc->cache_info.signed_descriptor_digest, DIGEST_LEN);
     149           0 :         base16_encode(rs_d, sizeof(rs_d), rs->descriptor_digest, DIGEST_LEN);
     150           0 :         base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
     151           0 :         log_err(LD_BUG, "descriptor digest in routerlist does not match "
     152             :             "the one in routerstatus: %s vs %s "
     153             :             "(router %s)\n",
     154             :             rl_d, rs_d, id);
     155             : 
     156           0 :         tor_assert(tor_memeq(desc->cache_info.signed_descriptor_digest,
     157             :               rs->descriptor_digest,
     158             :               DIGEST_LEN));
     159             :       }
     160             :     }
     161             : 
     162         161 :     if (format == NS_CONTROL_PORT && rs->has_bandwidth) {
     163          53 :       bw_kb = rs->bandwidth_kb;
     164             :     } else {
     165         108 :       tor_assert(desc);
     166         108 :       bw_kb = router_get_advertised_bandwidth_capped(desc) / 1000;
     167             :     }
     168         161 :     smartlist_add_asprintf(chunks,
     169             :                      "w Bandwidth=%d", bw_kb);
     170             : 
     171         161 :     if (format == NS_V3_VOTE && vrs && vrs->has_measured_bw) {
     172          12 :       smartlist_add_asprintf(chunks,
     173          12 :                        " Measured=%d", vrs->measured_bw_kb);
     174             :     }
     175             :     /* Write down guardfraction information if we have it. */
     176         161 :     if (format == NS_V3_VOTE && vrs && vrs->status.has_guardfraction) {
     177           0 :       smartlist_add_asprintf(chunks,
     178             :                              " GuardFraction=%d",
     179           0 :                              vrs->status.guardfraction_percentage);
     180             :     }
     181             : 
     182         161 :     smartlist_add_strdup(chunks, "\n");
     183             : 
     184         161 :     if (desc) {
     185         108 :       summary = policy_summarize(desc->exit_policy, AF_INET);
     186         108 :       smartlist_add_asprintf(chunks, "p %s\n", summary);
     187         108 :       tor_free(summary);
     188             :     }
     189             : 
     190         161 :     if (format == NS_V3_VOTE && vrs) {
     191         108 :       if (fast_mem_is_zero((char*)vrs->ed25519_id, ED25519_PUBKEY_LEN)) {
     192         108 :         smartlist_add_strdup(chunks, "id ed25519 none\n");
     193             :       } else {
     194           0 :         char ed_b64[BASE64_DIGEST256_LEN+1];
     195           0 :         digest256_to_base64(ed_b64, (const char*)vrs->ed25519_id);
     196           0 :         smartlist_add_asprintf(chunks, "id ed25519 %s\n", ed_b64);
     197             :       }
     198             : 
     199             :       /* We'll add a series of statistics to the vote per relays so we are
     200             :        * able to assess what each authorities sees and help our health and
     201             :        * performance work. */
     202         108 :       time_t now = time(NULL);
     203         108 :       smartlist_add_asprintf(chunks, "stats wfu=%.6f tk=%lu mtbf=%.0f\n",
     204             :         rep_hist_get_weighted_fractional_uptime(rs->identity_digest, now),
     205             :         rep_hist_get_weighted_time_known(rs->identity_digest, now),
     206             :         rep_hist_get_stability(rs->identity_digest, now));
     207             :     }
     208             :   }
     209             : 
     210          53 :  done:
     211         239 :   result = smartlist_join_strings(chunks, "", 0, NULL);
     212             : 
     213         239 :  err:
     214        1601 :   SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
     215         239 :   smartlist_free(chunks);
     216             : 
     217         239 :   return result;
     218             : }

Generated by: LCOV version 1.14