Tor 0.4.9.0-alpha-dev
fmt_routerstatus.c
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"
16
17#include "core/or/policies.h"
23
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 */
46char *
47routerstatus_format_entry(const routerstatus_t *rs, const char *version,
48 const char *protocols,
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);
75
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",
96 }
97
98 if (format == NS_V3_CONSENSUS || format == NS_V3_CONSENSUS_MICRODESC)
99 goto done;
100
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) {
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,
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
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 }
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 */
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. */
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) {
202 " GuardFraction=%d",
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) {
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",
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}
int tor_addr_is_null(const tor_addr_t *addr)
Definition: address.c:780
const char * fmt_addrport(const tor_addr_t *addr, uint16_t port)
Definition: address.c:1199
#define fmt_addr(a)
Definition: address.h:239
void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen)
Definition: binascii.c:478
#define BASE64_DIGEST256_LEN
Definition: crypto_digest.h:29
#define HEX_DIGEST_LEN
Definition: crypto_digest.h:35
#define BASE64_DIGEST_LEN
Definition: crypto_digest.h:26
void digest256_to_base64(char *d64, const char *digest)
void digest_to_base64(char *d64, const char *digest)
Header for crypto_format.c.
int tor_memeq(const void *a, const void *b, size_t sz)
Definition: di_ops.c:107
#define tor_memneq(a, b, sz)
Definition: di_ops.h:21
#define DIGEST_LEN
Definition: digest_sizes.h:20
Header file for dirvote.c.
Format routerstatus entries for controller, vote, or consensus.
routerstatus_format_type_t
@ NS_V3_VOTE
@ NS_CONTROL_PORT
@ NS_V3_CONSENSUS
@ NS_V3_CONSENSUS_MICRODESC
@ NS_V2
#define MAX_V_LINE_LEN
char * routerstatus_format_entry(const routerstatus_t *rs, const char *version, const char *protocols, routerstatus_format_type_t format, const vote_routerstatus_t *vrs, time_t declared_publish_time)
#define LD_BUG
Definition: log.h:86
#define tor_free(p)
Definition: malloc.h:56
Master header file for Tor-specific functionality.
char * policy_summarize(smartlist_t *policy, sa_family_t family)
Definition: policies.c:2593
Header file for policies.c.
double rep_hist_get_stability(const char *id, time_t when)
Definition: rephist.c:895
double rep_hist_get_weighted_fractional_uptime(const char *id, time_t when)
Definition: rephist.c:907
long rep_hist_get_weighted_time_known(const char *id, time_t when)
Definition: rephist.c:923
Header file for rephist.c.
Router descriptor structure.
const routerinfo_t * router_get_by_id_digest(const char *digest)
Definition: routerlist.c:779
uint32_t router_get_advertised_bandwidth_capped(const routerinfo_t *router)
Definition: routerlist.c:660
Header file for routerlist.c.
void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern,...)
Definition: smartlist.c:36
char * smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, size_t *len_out)
Definition: smartlist.c:279
void smartlist_add_strdup(struct smartlist_t *sl, const char *string)
smartlist_t * smartlist_new(void)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
smartlist_t * exit_policy
Definition: routerinfo_st.h:59
unsigned int is_bad_exit
uint16_t ipv6_orport
tor_addr_t ipv6_addr
unsigned int is_sybil
unsigned int is_staledesc
char descriptor_digest[DIGEST256_LEN]
char identity_digest[DIGEST_LEN]
unsigned int is_hs_dir
unsigned int has_guardfraction
unsigned int is_valid
char nickname[MAX_NICKNAME_LEN+1]
unsigned int has_bandwidth
uint16_t ipv4_dirport
unsigned int is_possible_guard
unsigned int is_stable
unsigned int is_flagged_running
unsigned int is_exit
unsigned int is_middle_only
unsigned int is_authority
uint32_t guardfraction_percentage
unsigned int is_fast
uint32_t bandwidth_kb
uint16_t ipv4_orport
char signed_descriptor_digest[DIGEST_LEN]
uint8_t ed25519_id[ED25519_PUBKEY_LEN]
void format_iso_time(char *buf, time_t t)
Definition: time_fmt.c:326
#define tor_assert(expr)
Definition: util_bug.h:103
int fast_mem_is_zero(const char *mem, size_t len)
Definition: util_string.c:76
Routerstatus (vote entry) structure.
#define ED25519_PUBKEY_LEN
Definition: x25519_sizes.h:27