describe.c (9650B)
1 /* Copyright (c) 2001 Matej Pfajfar. 2 * Copyright (c) 2001-2004, Roger Dingledine. 3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 4 * Copyright (c) 2007-2021, The Tor Project, Inc. */ 5 /* See LICENSE for licensing information */ 6 7 /** 8 * \file describe.c 9 * \brief Format short descriptions of relays. 10 */ 11 12 #define DESCRIBE_PRIVATE 13 14 #include "core/or/or.h" 15 #include "core/or/extendinfo.h" 16 #include "feature/nodelist/describe.h" 17 #include "feature/nodelist/nodelist.h" 18 #include "feature/nodelist/routerinfo.h" 19 #include "lib/crypt_ops/crypto_ed25519.h" 20 #include "lib/crypt_ops/crypto_format.h" 21 22 #include "core/or/extend_info_st.h" 23 #include "feature/nodelist/node_st.h" 24 #include "feature/nodelist/routerinfo_st.h" 25 #include "feature/nodelist/routerstatus_st.h" 26 #include "feature/nodelist/microdesc_st.h" 27 28 /** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to 29 * hold a human-readable description of a node with identity digest 30 * <b>id_digest</b>, nickname <b>nickname</b>, and addresses <b>addr32h</b> and 31 * <b>addr</b>. 32 * 33 * The <b>nickname</b>, <b>ipv6_addr</b> and <b>ipv4_addr</b> fields are 34 * optional and may be set to NULL or the null address. 35 * 36 * Return a pointer to the front of <b>buf</b>. 37 * If buf is NULL, return a string constant describing the error. 38 */ 39 STATIC const char * 40 format_node_description(char *buf, 41 const char *rsa_id_digest, 42 const ed25519_public_key_t *ed25519_id, 43 const char *nickname, 44 const tor_addr_t *ipv4_addr, 45 const tor_addr_t *ipv6_addr) 46 { 47 size_t rv = 0; 48 bool has_ipv6 = ipv6_addr && !tor_addr_is_null(ipv6_addr); 49 bool valid_ipv4 = false; 50 51 if (!buf) 52 return "<NULL BUFFER>"; 53 54 memset(buf, 0, NODE_DESC_BUF_LEN); 55 56 if (!rsa_id_digest) { 57 /* strlcpy() returns the length of the source string it attempted to copy, 58 * ignoring any required truncation due to the buffer length. */ 59 rv = strlcpy(buf, "<NULL ID DIGEST>", NODE_DESC_BUF_LEN); 60 tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); 61 return buf; 62 } 63 64 /* strlcat() returns the length of the concatenated string it attempted to 65 * create, ignoring any required truncation due to the buffer length. */ 66 rv = strlcat(buf, "$", NODE_DESC_BUF_LEN); 67 tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); 68 69 { 70 char hex_digest[HEX_DIGEST_LEN+1]; 71 memset(hex_digest, 0, sizeof(hex_digest)); 72 73 base16_encode(hex_digest, sizeof(hex_digest), 74 rsa_id_digest, DIGEST_LEN); 75 rv = strlcat(buf, hex_digest, NODE_DESC_BUF_LEN); 76 tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); 77 } 78 79 if (nickname) { 80 rv = strlcat(buf, "~", NODE_DESC_BUF_LEN); 81 tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); 82 rv = strlcat(buf, nickname, NODE_DESC_BUF_LEN); 83 tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); 84 } 85 if (ed25519_id) { 86 char ed_base64[ED25519_BASE64_LEN+1]; 87 ed25519_public_to_base64(ed_base64, ed25519_id); 88 rv = strlcat(buf, " [", NODE_DESC_BUF_LEN); 89 tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); 90 rv = strlcat(buf, ed_base64, NODE_DESC_BUF_LEN); 91 tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); 92 rv = strlcat(buf, "]", NODE_DESC_BUF_LEN); 93 tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); 94 } 95 if (ipv4_addr || has_ipv6) { 96 rv = strlcat(buf, " at ", NODE_DESC_BUF_LEN); 97 tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); 98 } 99 if (ipv4_addr) { 100 const char *str_rv = NULL; 101 char addr_str[TOR_ADDR_BUF_LEN]; 102 memset(addr_str, 0, sizeof(addr_str)); 103 104 str_rv = tor_addr_to_str(addr_str, ipv4_addr, sizeof(addr_str), 0); 105 if (str_rv) { 106 rv = strlcat(buf, addr_str, NODE_DESC_BUF_LEN); 107 tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); 108 valid_ipv4 = true; 109 } 110 } 111 /* Both addresses are valid */ 112 if (valid_ipv4 && has_ipv6) { 113 rv = strlcat(buf, " and ", NODE_DESC_BUF_LEN); 114 tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); 115 } 116 if (has_ipv6) { 117 const char *str_rv = NULL; 118 char addr_str[TOR_ADDR_BUF_LEN]; 119 memset(addr_str, 0, sizeof(addr_str)); 120 121 str_rv = tor_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str), 1); 122 if (str_rv) { 123 rv = strlcat(buf, addr_str, NODE_DESC_BUF_LEN); 124 tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); 125 } 126 } 127 128 return buf; 129 } 130 131 /** Return a human-readable description of the routerinfo_t <b>ri</b>. 132 * 133 * This function is not thread-safe. Each call to this function invalidates 134 * previous values returned by this function. 135 */ 136 const char * 137 router_describe(const routerinfo_t *ri) 138 { 139 static char buf[NODE_DESC_BUF_LEN]; 140 141 if (!ri) 142 return "<null>"; 143 144 const ed25519_public_key_t *ed25519_id = routerinfo_get_ed25519_id(ri); 145 146 return format_node_description(buf, 147 ri->cache_info.identity_digest, 148 ed25519_id, 149 ri->nickname, 150 &ri->ipv4_addr, 151 &ri->ipv6_addr); 152 } 153 154 /** Return a human-readable description of the node_t <b>node</b>. 155 * 156 * This function is not thread-safe. Each call to this function invalidates 157 * previous values returned by this function. 158 */ 159 const char * 160 node_describe(const node_t *node) 161 { 162 static char buf[NODE_DESC_BUF_LEN]; 163 const char *nickname = NULL; 164 const tor_addr_t *ipv6_addr = NULL, *ipv4_addr = NULL; 165 166 if (!node) 167 return "<null>"; 168 169 if (node->rs) { 170 nickname = node->rs->nickname; 171 ipv4_addr = &node->rs->ipv4_addr; 172 ipv6_addr = &node->rs->ipv6_addr; 173 /* Support consensus versions less than 28, when IPv6 addresses were in 174 * microdescs. This code can be removed when 0.2.9 is no longer supported, 175 * and the MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC macro is removed. */ 176 if (node->md && tor_addr_is_null(ipv6_addr)) { 177 ipv6_addr = &node->md->ipv6_addr; 178 } 179 } else if (node->ri) { 180 nickname = node->ri->nickname; 181 ipv4_addr = &node->ri->ipv4_addr; 182 ipv6_addr = &node->ri->ipv6_addr; 183 } else { 184 return "<null rs and ri>"; 185 } 186 187 const ed25519_public_key_t *ed25519_id = node_get_ed25519_id(node); 188 189 return format_node_description(buf, 190 node->identity, 191 ed25519_id, 192 nickname, 193 ipv4_addr, 194 ipv6_addr); 195 } 196 197 /** Return a human-readable description of the routerstatus_t <b>rs</b>. 198 * 199 * This function is not thread-safe. Each call to this function invalidates 200 * previous values returned by this function. 201 */ 202 const char * 203 routerstatus_describe(const routerstatus_t *rs) 204 { 205 static char buf[NODE_DESC_BUF_LEN]; 206 207 if (!rs) 208 return "<null>"; 209 210 return format_node_description(buf, 211 rs->identity_digest, 212 NULL, 213 rs->nickname, 214 &rs->ipv4_addr, 215 &rs->ipv6_addr); 216 } 217 218 /** Return a human-readable description of the extend_info_t <b>ei</b>. 219 * 220 * This function is not thread-safe. Each call to this function invalidates 221 * previous values returned by this function. 222 */ 223 const char * 224 extend_info_describe(const extend_info_t *ei) 225 { 226 static char buf[NODE_DESC_BUF_LEN]; 227 228 if (!ei) 229 return "<null>"; 230 231 const tor_addr_port_t *ap4 = extend_info_get_orport(ei, AF_INET); 232 const tor_addr_port_t *ap6 = extend_info_get_orport(ei, AF_INET6); 233 const tor_addr_t *addr4 = ap4 ? &ap4->addr : NULL; 234 const tor_addr_t *addr6 = ap6 ? &ap6->addr : NULL; 235 236 const ed25519_public_key_t *ed25519_id = &ei->ed_identity; 237 if (ed25519_public_key_is_zero(ed25519_id)) 238 ed25519_id = NULL; 239 240 return format_node_description(buf, 241 ei->identity_digest, 242 ed25519_id, 243 ei->nickname, 244 addr4, 245 addr6); 246 } 247 248 /** Set <b>buf</b> (which must have MAX_VERBOSE_NICKNAME_LEN+1 bytes) to the 249 * verbose representation of the identity of <b>router</b>. The format is: 250 * A dollar sign. 251 * The upper-case hexadecimal encoding of the SHA1 hash of router's identity. 252 * A "=" if the router is named (no longer implemented); a "~" if it is not. 253 * The router's nickname. 254 **/ 255 void 256 router_get_verbose_nickname(char *buf, const routerinfo_t *router) 257 { 258 size_t rv = 0; 259 260 if (!buf) 261 return; 262 263 memset(buf, 0, MAX_VERBOSE_NICKNAME_LEN+1); 264 265 if (!router) { 266 /* strlcpy() returns the length of the source string it attempted to copy, 267 * ignoring any required truncation due to the buffer length. */ 268 rv = strlcpy(buf, "<null>", MAX_VERBOSE_NICKNAME_LEN+1); 269 tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1); 270 return; 271 } 272 273 /* strlcat() returns the length of the concatenated string it attempted to 274 * create, ignoring any required truncation due to the buffer length. */ 275 rv = strlcat(buf, "$", MAX_VERBOSE_NICKNAME_LEN+1); 276 tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1); 277 278 { 279 char hex_digest[HEX_DIGEST_LEN+1]; 280 memset(hex_digest, 0, sizeof(hex_digest)); 281 282 base16_encode(hex_digest, sizeof(hex_digest), 283 router->cache_info.identity_digest, DIGEST_LEN); 284 rv = strlcat(buf, hex_digest, MAX_VERBOSE_NICKNAME_LEN+1); 285 tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1); 286 } 287 288 rv = strlcat(buf, "~", MAX_VERBOSE_NICKNAME_LEN+1); 289 tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1); 290 291 rv = strlcat(buf, router->nickname, MAX_VERBOSE_NICKNAME_LEN+1); 292 tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1); 293 }