fmt_routerstatus.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /* Copyright (c) 2001-2004, Roger Dingledine.
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2019, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. /**
  6. * \file fmt_routerstatus.h
  7. * \brief Format routerstatus entries for controller, vote, or consensus.
  8. *
  9. * (Because controllers consume this format, we can't make this
  10. * code dirauth-only.)
  11. **/
  12. #include "core/or/or.h"
  13. #include "feature/nodelist/fmt_routerstatus.h"
  14. #include "core/or/policies.h"
  15. #include "feature/nodelist/routerlist.h"
  16. #include "feature/dirauth/dirvote.h"
  17. #include "feature/nodelist/routerinfo_st.h"
  18. #include "feature/nodelist/vote_routerstatus_st.h"
  19. #include "lib/crypt_ops/crypto_format.h"
  20. /** Helper: write the router-status information in <b>rs</b> into a newly
  21. * allocated character buffer. Use the same format as in network-status
  22. * documents. If <b>version</b> is non-NULL, add a "v" line for the platform.
  23. *
  24. * consensus_method is the current consensus method when format is
  25. * NS_V3_CONSENSUS or NS_V3_CONSENSUS_MICRODESC. It is ignored for other
  26. * formats: pass ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD.
  27. *
  28. * Return 0 on success, -1 on failure.
  29. *
  30. * The format argument has one of the following values:
  31. * NS_V2 - Output an entry suitable for a V2 NS opinion document
  32. * NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry
  33. * for consensus_method.
  34. * NS_V3_CONSENSUS_MICRODESC - Output the first portion of a V3 microdesc
  35. * consensus entry for consensus_method.
  36. * NS_V3_VOTE - Output a complete V3 NS vote. If <b>vrs</b> is present,
  37. * it contains additional information for the vote.
  38. * NS_CONTROL_PORT - Output a NS document for the control port.
  39. */
  40. char *
  41. routerstatus_format_entry(const routerstatus_t *rs, const char *version,
  42. const char *protocols,
  43. routerstatus_format_type_t format,
  44. int consensus_method,
  45. const vote_routerstatus_t *vrs)
  46. {
  47. char *summary;
  48. char *result = NULL;
  49. char published[ISO_TIME_LEN+1];
  50. char identity64[BASE64_DIGEST_LEN+1];
  51. char digest64[BASE64_DIGEST_LEN+1];
  52. smartlist_t *chunks = smartlist_new();
  53. format_iso_time(published, rs->published_on);
  54. digest_to_base64(identity64, rs->identity_digest);
  55. digest_to_base64(digest64, rs->descriptor_digest);
  56. smartlist_add_asprintf(chunks,
  57. "r %s %s %s%s%s %s %d %d\n",
  58. rs->nickname,
  59. identity64,
  60. (format==NS_V3_CONSENSUS_MICRODESC)?"":digest64,
  61. (format==NS_V3_CONSENSUS_MICRODESC)?"":" ",
  62. published,
  63. fmt_addr32(rs->addr),
  64. (int)rs->or_port,
  65. (int)rs->dir_port);
  66. /* TODO: Maybe we want to pass in what we need to build the rest of
  67. * this here, instead of in the caller. Then we could use the
  68. * networkstatus_type_t values, with an additional control port value
  69. * added -MP */
  70. /* V3 microdesc consensuses only have "a" lines in later consensus methods
  71. */
  72. if (format == NS_V3_CONSENSUS_MICRODESC &&
  73. consensus_method < MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS)
  74. goto done;
  75. /* Possible "a" line. At most one for now. */
  76. if (!tor_addr_is_null(&rs->ipv6_addr)) {
  77. smartlist_add_asprintf(chunks, "a %s\n",
  78. fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport));
  79. }
  80. if (format == NS_V3_CONSENSUS || format == NS_V3_CONSENSUS_MICRODESC)
  81. goto done;
  82. smartlist_add_asprintf(chunks,
  83. "s%s%s%s%s%s%s%s%s%s%s%s\n",
  84. /* These must stay in alphabetical order. */
  85. rs->is_authority?" Authority":"",
  86. rs->is_bad_exit?" BadExit":"",
  87. rs->is_exit?" Exit":"",
  88. rs->is_fast?" Fast":"",
  89. rs->is_possible_guard?" Guard":"",
  90. rs->is_hs_dir?" HSDir":"",
  91. rs->is_flagged_running?" Running":"",
  92. rs->is_stable?" Stable":"",
  93. rs->is_staledesc?" StaleDesc":"",
  94. rs->is_v2_dir?" V2Dir":"",
  95. rs->is_valid?" Valid":"");
  96. /* length of "opt v \n" */
  97. #define V_LINE_OVERHEAD 7
  98. if (version && strlen(version) < MAX_V_LINE_LEN - V_LINE_OVERHEAD) {
  99. smartlist_add_asprintf(chunks, "v %s\n", version);
  100. }
  101. if (protocols) {
  102. smartlist_add_asprintf(chunks, "pr %s\n", protocols);
  103. }
  104. if (format != NS_V2) {
  105. const routerinfo_t* desc = router_get_by_id_digest(rs->identity_digest);
  106. uint32_t bw_kb;
  107. if (format != NS_CONTROL_PORT) {
  108. /* Blow up more or less nicely if we didn't get anything or not the
  109. * thing we expected.
  110. */
  111. if (!desc) {
  112. char id[HEX_DIGEST_LEN+1];
  113. char dd[HEX_DIGEST_LEN+1];
  114. base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
  115. base16_encode(dd, sizeof(dd), rs->descriptor_digest, DIGEST_LEN);
  116. log_warn(LD_BUG, "Cannot get any descriptor for %s "
  117. "(wanted descriptor %s).",
  118. id, dd);
  119. goto err;
  120. }
  121. /* This assert could fire for the control port, because
  122. * it can request NS documents before all descriptors
  123. * have been fetched. Therefore, we only do this test when
  124. * format != NS_CONTROL_PORT. */
  125. if (tor_memneq(desc->cache_info.signed_descriptor_digest,
  126. rs->descriptor_digest,
  127. DIGEST_LEN)) {
  128. char rl_d[HEX_DIGEST_LEN+1];
  129. char rs_d[HEX_DIGEST_LEN+1];
  130. char id[HEX_DIGEST_LEN+1];
  131. base16_encode(rl_d, sizeof(rl_d),
  132. desc->cache_info.signed_descriptor_digest, DIGEST_LEN);
  133. base16_encode(rs_d, sizeof(rs_d), rs->descriptor_digest, DIGEST_LEN);
  134. base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
  135. log_err(LD_BUG, "descriptor digest in routerlist does not match "
  136. "the one in routerstatus: %s vs %s "
  137. "(router %s)\n",
  138. rl_d, rs_d, id);
  139. tor_assert(tor_memeq(desc->cache_info.signed_descriptor_digest,
  140. rs->descriptor_digest,
  141. DIGEST_LEN));
  142. }
  143. }
  144. if (format == NS_CONTROL_PORT && rs->has_bandwidth) {
  145. bw_kb = rs->bandwidth_kb;
  146. } else {
  147. tor_assert(desc);
  148. bw_kb = router_get_advertised_bandwidth_capped(desc) / 1000;
  149. }
  150. smartlist_add_asprintf(chunks,
  151. "w Bandwidth=%d", bw_kb);
  152. if (format == NS_V3_VOTE && vrs && vrs->has_measured_bw) {
  153. smartlist_add_asprintf(chunks,
  154. " Measured=%d", vrs->measured_bw_kb);
  155. }
  156. /* Write down guardfraction information if we have it. */
  157. if (format == NS_V3_VOTE && vrs && vrs->status.has_guardfraction) {
  158. smartlist_add_asprintf(chunks,
  159. " GuardFraction=%d",
  160. vrs->status.guardfraction_percentage);
  161. }
  162. smartlist_add_strdup(chunks, "\n");
  163. if (desc) {
  164. summary = policy_summarize(desc->exit_policy, AF_INET);
  165. smartlist_add_asprintf(chunks, "p %s\n", summary);
  166. tor_free(summary);
  167. }
  168. if (format == NS_V3_VOTE && vrs) {
  169. if (fast_mem_is_zero((char*)vrs->ed25519_id, ED25519_PUBKEY_LEN)) {
  170. smartlist_add_strdup(chunks, "id ed25519 none\n");
  171. } else {
  172. char ed_b64[BASE64_DIGEST256_LEN+1];
  173. digest256_to_base64(ed_b64, (const char*)vrs->ed25519_id);
  174. smartlist_add_asprintf(chunks, "id ed25519 %s\n", ed_b64);
  175. }
  176. }
  177. }
  178. done:
  179. result = smartlist_join_strings(chunks, "", 0, NULL);
  180. err:
  181. SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
  182. smartlist_free(chunks);
  183. return result;
  184. }