123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- /* Copyright (c) 2001-2004, Roger Dingledine.
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2018, The Tor Project, Inc. */
- /* See LICENSE for licensing information */
- /**
- * \file fmt_routerstatus.h
- * \brief Format routerstatus entries for controller, vote, or consensus.
- *
- * (Because controllers consume this format, we can't make this
- * code dirauth-only.)
- **/
- #include "core/or/or.h"
- #include "feature/nodelist/fmt_routerstatus.h"
- /* #include "lib/container/buffers.h" */
- /* #include "app/config/config.h" */
- /* #include "app/config/confparse.h" */
- /* #include "core/or/channel.h" */
- /* #include "core/or/channeltls.h" */
- /* #include "core/or/command.h" */
- /* #include "core/mainloop/connection.h" */
- /* #include "core/or/connection_or.h" */
- /* #include "feature/dircache/conscache.h" */
- /* #include "feature/dircache/consdiffmgr.h" */
- /* #include "feature/control/control.h" */
- /* #include "feature/dircache/directory.h" */
- /* #include "feature/dircache/dirserv.h" */
- /* #include "feature/hibernate/hibernate.h" */
- /* #include "feature/dirauth/keypin.h" */
- /* #include "core/mainloop/mainloop.h" */
- /* #include "feature/nodelist/microdesc.h" */
- /* #include "feature/nodelist/networkstatus.h" */
- /* #include "feature/nodelist/nodelist.h" */
- #include "core/or/policies.h"
- /* #include "core/or/protover.h" */
- /* #include "feature/stats/rephist.h" */
- /* #include "feature/relay/router.h" */
- /* #include "feature/nodelist/dirlist.h" */
- #include "feature/nodelist/routerlist.h"
- /* #include "feature/nodelist/routerparse.h" */
- /* #include "feature/nodelist/routerset.h" */
- /* #include "feature/nodelist/torcert.h" */
- /* #include "feature/dircommon/voting_schedule.h" */
- #include "feature/dirauth/dirvote.h"
- /* #include "feature/dircache/cached_dir_st.h" */
- /* #include "feature/dircommon/dir_connection_st.h" */
- /* #include "feature/nodelist/extrainfo_st.h" */
- /* #include "feature/nodelist/microdesc_st.h" */
- /* #include "feature/nodelist/node_st.h" */
- #include "feature/nodelist/routerinfo_st.h"
- /* #include "feature/nodelist/routerlist_st.h" */
- /* #include "core/or/tor_version_st.h" */
- #include "feature/nodelist/vote_routerstatus_st.h"
- /* #include "lib/compress/compress.h" */
- /* #include "lib/container/order.h" */
- #include "lib/crypt_ops/crypto_format.h"
- /* #include "lib/encoding/confline.h" */
- /* #include "lib/encoding/keyval.h" */
- /** Helper: write the router-status information in <b>rs</b> into a newly
- * allocated character buffer. Use the same format as in network-status
- * documents. If <b>version</b> is non-NULL, add a "v" line for the platform.
- *
- * consensus_method is the current consensus method when format is
- * NS_V3_CONSENSUS or NS_V3_CONSENSUS_MICRODESC. It is ignored for other
- * formats: pass ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD.
- *
- * Return 0 on success, -1 on failure.
- *
- * The format argument has one of the following values:
- * NS_V2 - Output an entry suitable for a V2 NS opinion document
- * NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry
- * for consensus_method.
- * NS_V3_CONSENSUS_MICRODESC - Output the first portion of a V3 microdesc
- * consensus entry for consensus_method.
- * NS_V3_VOTE - Output a complete V3 NS vote. If <b>vrs</b> is present,
- * it contains additional information for the vote.
- * NS_CONTROL_PORT - Output a NS document for the control port.
- */
- char *
- routerstatus_format_entry(const routerstatus_t *rs, const char *version,
- const char *protocols,
- routerstatus_format_type_t format,
- int consensus_method,
- const vote_routerstatus_t *vrs)
- {
- char *summary;
- char *result = NULL;
- char published[ISO_TIME_LEN+1];
- char identity64[BASE64_DIGEST_LEN+1];
- char digest64[BASE64_DIGEST_LEN+1];
- smartlist_t *chunks = smartlist_new();
- format_iso_time(published, rs->published_on);
- digest_to_base64(identity64, rs->identity_digest);
- digest_to_base64(digest64, rs->descriptor_digest);
- smartlist_add_asprintf(chunks,
- "r %s %s %s%s%s %s %d %d\n",
- rs->nickname,
- identity64,
- (format==NS_V3_CONSENSUS_MICRODESC)?"":digest64,
- (format==NS_V3_CONSENSUS_MICRODESC)?"":" ",
- published,
- fmt_addr32(rs->addr),
- (int)rs->or_port,
- (int)rs->dir_port);
- /* TODO: Maybe we want to pass in what we need to build the rest of
- * this here, instead of in the caller. Then we could use the
- * networkstatus_type_t values, with an additional control port value
- * added -MP */
- /* V3 microdesc consensuses only have "a" lines in later consensus methods
- */
- if (format == NS_V3_CONSENSUS_MICRODESC &&
- consensus_method < MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS)
- goto done;
- /* Possible "a" line. At most one for now. */
- if (!tor_addr_is_null(&rs->ipv6_addr)) {
- smartlist_add_asprintf(chunks, "a %s\n",
- fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport));
- }
- if (format == NS_V3_CONSENSUS || format == NS_V3_CONSENSUS_MICRODESC)
- goto done;
- smartlist_add_asprintf(chunks,
- "s%s%s%s%s%s%s%s%s%s%s\n",
- /* These must stay in alphabetical order. */
- rs->is_authority?" Authority":"",
- rs->is_bad_exit?" BadExit":"",
- rs->is_exit?" Exit":"",
- rs->is_fast?" Fast":"",
- rs->is_possible_guard?" Guard":"",
- rs->is_hs_dir?" HSDir":"",
- rs->is_flagged_running?" Running":"",
- rs->is_stable?" Stable":"",
- rs->is_v2_dir?" V2Dir":"",
- rs->is_valid?" Valid":"");
- /* length of "opt v \n" */
- #define V_LINE_OVERHEAD 7
- if (version && strlen(version) < MAX_V_LINE_LEN - V_LINE_OVERHEAD) {
- smartlist_add_asprintf(chunks, "v %s\n", version);
- }
- if (protocols) {
- smartlist_add_asprintf(chunks, "pr %s\n", protocols);
- }
- if (format != NS_V2) {
- const routerinfo_t* desc = router_get_by_id_digest(rs->identity_digest);
- uint32_t bw_kb;
- if (format != NS_CONTROL_PORT) {
- /* Blow up more or less nicely if we didn't get anything or not the
- * thing we expected.
- */
- if (!desc) {
- char id[HEX_DIGEST_LEN+1];
- char dd[HEX_DIGEST_LEN+1];
- base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
- base16_encode(dd, sizeof(dd), rs->descriptor_digest, DIGEST_LEN);
- log_warn(LD_BUG, "Cannot get any descriptor for %s "
- "(wanted descriptor %s).",
- id, dd);
- goto err;
- }
- /* This assert could fire for the control port, because
- * it can request NS documents before all descriptors
- * have been fetched. Therefore, we only do this test when
- * format != NS_CONTROL_PORT. */
- if (tor_memneq(desc->cache_info.signed_descriptor_digest,
- rs->descriptor_digest,
- DIGEST_LEN)) {
- char rl_d[HEX_DIGEST_LEN+1];
- char rs_d[HEX_DIGEST_LEN+1];
- char id[HEX_DIGEST_LEN+1];
- base16_encode(rl_d, sizeof(rl_d),
- desc->cache_info.signed_descriptor_digest, DIGEST_LEN);
- base16_encode(rs_d, sizeof(rs_d), rs->descriptor_digest, DIGEST_LEN);
- base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
- log_err(LD_BUG, "descriptor digest in routerlist does not match "
- "the one in routerstatus: %s vs %s "
- "(router %s)\n",
- rl_d, rs_d, id);
- tor_assert(tor_memeq(desc->cache_info.signed_descriptor_digest,
- rs->descriptor_digest,
- DIGEST_LEN));
- }
- }
- if (format == NS_CONTROL_PORT && rs->has_bandwidth) {
- bw_kb = rs->bandwidth_kb;
- } else {
- tor_assert(desc);
- bw_kb = router_get_advertised_bandwidth_capped(desc) / 1000;
- }
- smartlist_add_asprintf(chunks,
- "w Bandwidth=%d", bw_kb);
- if (format == NS_V3_VOTE && vrs && vrs->has_measured_bw) {
- smartlist_add_asprintf(chunks,
- " Measured=%d", vrs->measured_bw_kb);
- }
- /* Write down guardfraction information if we have it. */
- if (format == NS_V3_VOTE && vrs && vrs->status.has_guardfraction) {
- smartlist_add_asprintf(chunks,
- " GuardFraction=%d",
- vrs->status.guardfraction_percentage);
- }
- smartlist_add_strdup(chunks, "\n");
- if (desc) {
- summary = policy_summarize(desc->exit_policy, AF_INET);
- smartlist_add_asprintf(chunks, "p %s\n", summary);
- tor_free(summary);
- }
- if (format == NS_V3_VOTE && vrs) {
- if (tor_mem_is_zero((char*)vrs->ed25519_id, ED25519_PUBKEY_LEN)) {
- smartlist_add_strdup(chunks, "id ed25519 none\n");
- } else {
- char ed_b64[BASE64_DIGEST256_LEN+1];
- digest256_to_base64(ed_b64, (const char*)vrs->ed25519_id);
- smartlist_add_asprintf(chunks, "id ed25519 %s\n", ed_b64);
- }
- }
- }
- done:
- result = smartlist_join_strings(chunks, "", 0, NULL);
- err:
- SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
- smartlist_free(chunks);
- return result;
- }
|