fmt_routerstatus.c 9.1 KB

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