control_getinfo.c (66868B)
1 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 2 * Copyright (c) 2007-2021, The Tor Project, Inc. */ 3 /* See LICENSE for licensing information */ 4 5 /** 6 * \file control_getinfo.c 7 * \brief Implementation for miscellaneous controller getinfo commands. 8 */ 9 10 #define CONTROL_EVENTS_PRIVATE 11 #define CONTROL_MODULE_PRIVATE 12 #define CONTROL_GETINFO_PRIVATE 13 14 #include "core/or/or.h" 15 #include "app/config/config.h" 16 #include "core/mainloop/connection.h" 17 #include "core/mainloop/mainloop.h" 18 #include "core/or/circuitlist.h" 19 #include "core/or/connection_edge.h" 20 #include "core/or/connection_or.h" 21 #include "core/or/policies.h" 22 #include "core/or/versions.h" 23 #include "feature/client/addressmap.h" 24 #include "feature/client/bridges.h" 25 #include "feature/client/entrynodes.h" 26 #include "feature/control/control.h" 27 #include "feature/control/control_cmd.h" 28 #include "feature/control/control_events.h" 29 #include "feature/control/control_fmt.h" 30 #include "feature/control/control_getinfo.h" 31 #include "feature/control/control_proto.h" 32 #include "feature/control/getinfo_geoip.h" 33 #include "feature/dircache/dirserv.h" 34 #include "feature/dirclient/dirclient.h" 35 #include "feature/dirclient/dlstatus.h" 36 #include "feature/dircommon/directory.h" 37 #include "feature/hibernate/hibernate.h" 38 #include "feature/hs/hs_cache.h" 39 #include "feature/hs_common/shared_random_client.h" 40 #include "feature/nodelist/authcert.h" 41 #include "feature/nodelist/microdesc.h" 42 #include "feature/nodelist/networkstatus.h" 43 #include "feature/nodelist/nodelist.h" 44 #include "feature/nodelist/routerinfo.h" 45 #include "feature/nodelist/routerlist.h" 46 #include "feature/relay/relay_find_addr.h" 47 #include "feature/relay/router.h" 48 #include "feature/relay/routermode.h" 49 #include "feature/relay/selftest.h" 50 #include "feature/stats/geoip_stats.h" 51 #include "feature/stats/predict_ports.h" 52 #include "feature/stats/rephist.h" 53 #include "lib/version/torversion.h" 54 #include "lib/encoding/kvline.h" 55 56 #include "core/or/entry_connection_st.h" 57 #include "core/or/or_connection_st.h" 58 #include "core/or/origin_circuit_st.h" 59 #include "core/or/socks_request_st.h" 60 #include "feature/control/control_connection_st.h" 61 #include "feature/control/control_cmd_args_st.h" 62 #include "feature/dircache/cached_dir_st.h" 63 #include "feature/nodelist/extrainfo_st.h" 64 #include "feature/nodelist/microdesc_st.h" 65 #include "feature/nodelist/networkstatus_st.h" 66 #include "feature/nodelist/node_st.h" 67 #include "feature/nodelist/routerinfo_st.h" 68 #include "feature/nodelist/routerlist_st.h" 69 70 #ifdef HAVE_UNISTD_H 71 #include <unistd.h> 72 #endif 73 74 #ifndef _WIN32 75 #include <pwd.h> 76 #endif 77 78 static char *list_getinfo_options(void); 79 static char *download_status_to_string(const download_status_t *dl); 80 81 /** Implementation helper for GETINFO: knows the answers for various 82 * trivial-to-implement questions. */ 83 static int 84 getinfo_helper_misc(control_connection_t *conn, const char *question, 85 char **answer, const char **errmsg) 86 { 87 (void) conn; 88 if (!strcmp(question, "version")) { 89 *answer = tor_strdup(get_version()); 90 } else if (!strcmp(question, "bw-event-cache")) { 91 *answer = get_bw_samples(); 92 } else if (!strcmp(question, "config-file")) { 93 const char *a = get_torrc_fname(0); 94 if (a) 95 *answer = tor_strdup(a); 96 } else if (!strcmp(question, "config-defaults-file")) { 97 const char *a = get_torrc_fname(1); 98 if (a) 99 *answer = tor_strdup(a); 100 } else if (!strcmp(question, "config-text")) { 101 *answer = options_dump(get_options(), OPTIONS_DUMP_MINIMAL); 102 } else if (!strcmp(question, "config-can-saveconf")) { 103 *answer = tor_strdup(get_options()->IncludeUsed ? "0" : "1"); 104 } else if (!strcmp(question, "info/names")) { 105 *answer = list_getinfo_options(); 106 } else if (!strcmp(question, "dormant")) { 107 int dormant = rep_hist_circbuilding_dormant(time(NULL)); 108 *answer = tor_strdup(dormant ? "1" : "0"); 109 } else if (!strcmp(question, "events/names")) { 110 int i; 111 smartlist_t *event_names = smartlist_new(); 112 113 for (i = 0; control_event_table[i].event_name != NULL; ++i) { 114 smartlist_add(event_names, (char *)control_event_table[i].event_name); 115 } 116 117 *answer = smartlist_join_strings(event_names, " ", 0, NULL); 118 119 smartlist_free(event_names); 120 } else if (!strcmp(question, "signal/names")) { 121 smartlist_t *signal_names = smartlist_new(); 122 int j; 123 for (j = 0; signal_table[j].signal_name != NULL; ++j) { 124 smartlist_add(signal_names, (char*)signal_table[j].signal_name); 125 } 126 127 *answer = smartlist_join_strings(signal_names, " ", 0, NULL); 128 129 smartlist_free(signal_names); 130 } else if (!strcmp(question, "features/names")) { 131 *answer = tor_strdup("VERBOSE_NAMES EXTENDED_EVENTS"); 132 } else if (!strcmp(question, "address") || !strcmp(question, "address/v4")) { 133 tor_addr_t addr; 134 if (!relay_find_addr_to_publish(get_options(), AF_INET, 135 RELAY_FIND_ADDR_CACHE_ONLY, &addr)) { 136 *errmsg = "Address unknown"; 137 return -1; 138 } 139 *answer = tor_addr_to_str_dup(&addr); 140 tor_assert_nonfatal(*answer); 141 } else if (!strcmp(question, "address/v6")) { 142 tor_addr_t addr; 143 if (!relay_find_addr_to_publish(get_options(), AF_INET6, 144 RELAY_FIND_ADDR_CACHE_ONLY, &addr)) { 145 *errmsg = "Address unknown"; 146 return -1; 147 } 148 *answer = tor_addr_to_str_dup(&addr); 149 tor_assert_nonfatal(*answer); 150 } else if (!strcmp(question, "traffic/read")) { 151 tor_asprintf(answer, "%"PRIu64, (get_bytes_read())); 152 } else if (!strcmp(question, "traffic/written")) { 153 tor_asprintf(answer, "%"PRIu64, (get_bytes_written())); 154 } else if (!strcmp(question, "uptime")) { 155 long uptime_secs = get_uptime(); 156 tor_asprintf(answer, "%ld", uptime_secs); 157 } else if (!strcmp(question, "process/pid")) { 158 int myPid = -1; 159 160 #ifdef _WIN32 161 myPid = _getpid(); 162 #else 163 myPid = getpid(); 164 #endif 165 166 tor_asprintf(answer, "%d", myPid); 167 } else if (!strcmp(question, "process/uid")) { 168 #ifdef _WIN32 169 *answer = tor_strdup("-1"); 170 #else 171 int myUid = geteuid(); 172 tor_asprintf(answer, "%d", myUid); 173 #endif /* defined(_WIN32) */ 174 } else if (!strcmp(question, "process/user")) { 175 #ifdef _WIN32 176 *answer = tor_strdup(""); 177 #else 178 int myUid = geteuid(); 179 const struct passwd *myPwEntry = tor_getpwuid(myUid); 180 181 if (myPwEntry) { 182 *answer = tor_strdup(myPwEntry->pw_name); 183 } else { 184 *answer = tor_strdup(""); 185 } 186 #endif /* defined(_WIN32) */ 187 } else if (!strcmp(question, "process/descriptor-limit")) { 188 int max_fds = get_max_sockets(); 189 tor_asprintf(answer, "%d", max_fds); 190 } else if (!strcmp(question, "limits/max-mem-in-queues")) { 191 tor_asprintf(answer, "%"PRIu64, 192 (get_options()->MaxMemInQueues)); 193 } else if (!strcmp(question, "fingerprint")) { 194 crypto_pk_t *server_key; 195 if (!server_mode(get_options())) { 196 *errmsg = "Not running in server mode"; 197 return -1; 198 } 199 server_key = get_server_identity_key(); 200 *answer = tor_malloc(HEX_DIGEST_LEN+1); 201 crypto_pk_get_fingerprint(server_key, *answer, 0); 202 } 203 return 0; 204 } 205 206 /** Awful hack: return a newly allocated string based on a routerinfo and 207 * (possibly) an extrainfo, sticking the read-history and write-history from 208 * <b>ei</b> into the resulting string. The thing you get back won't 209 * necessarily have a valid signature. 210 * 211 * New code should never use this; it's for backward compatibility. 212 * 213 * NOTE: <b>ri_body</b> is as returned by signed_descriptor_get_body: it might 214 * not be NUL-terminated. */ 215 static char * 216 munge_extrainfo_into_routerinfo(const char *ri_body, 217 const signed_descriptor_t *ri, 218 const signed_descriptor_t *ei) 219 { 220 char *out = NULL, *outp; 221 int i; 222 const char *router_sig; 223 const char *ei_body = signed_descriptor_get_body(ei); 224 size_t ri_len = ri->signed_descriptor_len; 225 size_t ei_len = ei->signed_descriptor_len; 226 if (!ei_body) 227 goto bail; 228 229 outp = out = tor_malloc(ri_len+ei_len+1); 230 if (!(router_sig = tor_memstr(ri_body, ri_len, "\nrouter-signature"))) 231 goto bail; 232 ++router_sig; 233 memcpy(out, ri_body, router_sig-ri_body); 234 outp += router_sig-ri_body; 235 236 for (i=0; i < 2; ++i) { 237 const char *kwd = i ? "\nwrite-history " : "\nread-history "; 238 const char *cp, *eol; 239 if (!(cp = tor_memstr(ei_body, ei_len, kwd))) 240 continue; 241 ++cp; 242 if (!(eol = memchr(cp, '\n', ei_len - (cp-ei_body)))) 243 continue; 244 memcpy(outp, cp, eol-cp+1); 245 outp += eol-cp+1; 246 } 247 memcpy(outp, router_sig, ri_len - (router_sig-ri_body)); 248 *outp++ = '\0'; 249 tor_assert(outp-out < (int)(ri_len+ei_len+1)); 250 251 return out; 252 bail: 253 tor_free(out); 254 return tor_strndup(ri_body, ri->signed_descriptor_len); 255 } 256 257 /** Implementation helper for GETINFO: answers requests for information about 258 * which ports are bound. */ 259 static int 260 getinfo_helper_listeners(control_connection_t *control_conn, 261 const char *question, 262 char **answer, const char **errmsg) 263 { 264 int type; 265 smartlist_t *res; 266 267 (void)control_conn; 268 (void)errmsg; 269 270 if (!strcmp(question, "net/listeners/or")) 271 type = CONN_TYPE_OR_LISTENER; 272 else if (!strcmp(question, "net/listeners/extor")) 273 type = CONN_TYPE_EXT_OR_LISTENER; 274 else if (!strcmp(question, "net/listeners/dir")) 275 type = CONN_TYPE_DIR_LISTENER; 276 else if (!strcmp(question, "net/listeners/socks")) 277 type = CONN_TYPE_AP_LISTENER; 278 else if (!strcmp(question, "net/listeners/trans")) 279 type = CONN_TYPE_AP_TRANS_LISTENER; 280 else if (!strcmp(question, "net/listeners/natd")) 281 type = CONN_TYPE_AP_NATD_LISTENER; 282 else if (!strcmp(question, "net/listeners/httptunnel")) 283 type = CONN_TYPE_AP_HTTP_CONNECT_LISTENER; 284 else if (!strcmp(question, "net/listeners/dns")) 285 type = CONN_TYPE_AP_DNS_LISTENER; 286 else if (!strcmp(question, "net/listeners/control")) 287 type = CONN_TYPE_CONTROL_LISTENER; 288 else if (!strcmp(question, "net/listeners/metrics")) 289 type = CONN_TYPE_METRICS_LISTENER; 290 else 291 return 0; /* unknown key */ 292 293 res = smartlist_new(); 294 SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) { 295 struct sockaddr_storage ss; 296 socklen_t ss_len = sizeof(ss); 297 298 if (conn->type != type || conn->marked_for_close || !SOCKET_OK(conn->s)) 299 continue; 300 301 if (getsockname(conn->s, (struct sockaddr *)&ss, &ss_len) < 0) { 302 smartlist_add_asprintf(res, "%s:%d", conn->address, (int)conn->port); 303 } else { 304 char *tmp = tor_sockaddr_to_str((struct sockaddr *)&ss); 305 smartlist_add(res, esc_for_log(tmp)); 306 tor_free(tmp); 307 } 308 309 } SMARTLIST_FOREACH_END(conn); 310 311 *answer = smartlist_join_strings(res, " ", 0, NULL); 312 313 SMARTLIST_FOREACH(res, char *, cp, tor_free(cp)); 314 smartlist_free(res); 315 return 0; 316 } 317 318 /** Implementation helper for GETINFO: answers requests for information about 319 * the current time in both local and UTC forms. */ 320 STATIC int 321 getinfo_helper_current_time(control_connection_t *control_conn, 322 const char *question, 323 char **answer, const char **errmsg) 324 { 325 (void)control_conn; 326 (void)errmsg; 327 328 struct timeval now; 329 tor_gettimeofday(&now); 330 char timebuf[ISO_TIME_LEN+1]; 331 332 if (!strcmp(question, "current-time/local")) 333 format_local_iso_time_nospace(timebuf, (time_t)now.tv_sec); 334 else if (!strcmp(question, "current-time/utc")) 335 format_iso_time_nospace(timebuf, (time_t)now.tv_sec); 336 else 337 return 0; 338 339 *answer = tor_strdup(timebuf); 340 return 0; 341 } 342 343 /** GETINFO helper for dumping different consensus flavors 344 * returns: 0 on success -1 on error. */ 345 STATIC int 346 getinfo_helper_current_consensus(consensus_flavor_t flavor, 347 char** answer, 348 const char** errmsg) 349 { 350 const char *flavor_name = networkstatus_get_flavor_name(flavor); 351 if (BUG(!strcmp(flavor_name, "??"))) { 352 *errmsg = "Internal error: unrecognized flavor name."; 353 return -1; 354 } 355 tor_mmap_t *mapped = networkstatus_map_cached_consensus(flavor_name); 356 if (mapped) { 357 *answer = tor_memdup_nulterm(mapped->data, mapped->size); 358 tor_munmap_file(mapped); 359 } 360 if (!*answer) { /* Maybe it's in the cache? */ 361 if (we_want_to_fetch_flavor(get_options(), flavor)) { 362 const cached_dir_t *consensus = dirserv_get_consensus(flavor_name); 363 if (consensus) { 364 *answer = tor_strdup(consensus->dir); 365 } 366 } 367 } 368 if (!*answer) { /* generate an error */ 369 *errmsg = "Could not open cached consensus. " 370 "Make sure FetchUselessDescriptors is set to 1."; 371 return -1; 372 } 373 return 0; 374 } 375 376 /** Helper for getinfo_helper_dir. 377 * 378 * Add a signed_descriptor_t to <b>descs_out</b> for each router matching 379 * <b>key</b>. The key should be either 380 * - "/tor/server/authority" for our own routerinfo; 381 * - "/tor/server/all" for all the routerinfos we have, concatenated; 382 * - "/tor/server/fp/FP" where FP is a plus-separated sequence of 383 * hex identity digests; or 384 * - "/tor/server/d/D" where D is a plus-separated sequence 385 * of server descriptor digests, in hex. 386 * 387 * Return 0 if we found some matching descriptors, or -1 if we do not 388 * have any descriptors, no matching descriptors, or if we did not 389 * recognize the key (URL). 390 * If -1 is returned *<b>msg</b> will be set to an appropriate error 391 * message. 392 */ 393 static int 394 controller_get_routerdescs(smartlist_t *descs_out, const char *key, 395 const char **msg) 396 { 397 *msg = NULL; 398 399 if (!strcmp(key, "/tor/server/all")) { 400 routerlist_t *rl = router_get_routerlist(); 401 SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r, 402 smartlist_add(descs_out, &(r->cache_info))); 403 } else if (!strcmp(key, "/tor/server/authority")) { 404 const routerinfo_t *ri = router_get_my_routerinfo(); 405 if (ri) 406 smartlist_add(descs_out, (void*) &(ri->cache_info)); 407 } else if (!strcmpstart(key, "/tor/server/d/")) { 408 smartlist_t *digests = smartlist_new(); 409 key += strlen("/tor/server/d/"); 410 dir_split_resource_into_fingerprints(key, digests, NULL, 411 DSR_HEX|DSR_SORT_UNIQ); 412 SMARTLIST_FOREACH(digests, const char *, d, 413 { 414 signed_descriptor_t *sd = router_get_by_descriptor_digest(d); 415 if (sd) 416 smartlist_add(descs_out,sd); 417 }); 418 SMARTLIST_FOREACH(digests, char *, d, tor_free(d)); 419 smartlist_free(digests); 420 } else if (!strcmpstart(key, "/tor/server/fp/")) { 421 smartlist_t *digests = smartlist_new(); 422 time_t cutoff = time(NULL) - ROUTER_MAX_AGE_TO_PUBLISH; 423 key += strlen("/tor/server/fp/"); 424 dir_split_resource_into_fingerprints(key, digests, NULL, 425 DSR_HEX|DSR_SORT_UNIQ); 426 SMARTLIST_FOREACH_BEGIN(digests, const char *, d) { 427 if (router_digest_is_me(d)) { 428 /* calling router_get_my_routerinfo() to make sure it exists */ 429 const routerinfo_t *ri = router_get_my_routerinfo(); 430 if (ri) 431 smartlist_add(descs_out, (void*) &(ri->cache_info)); 432 } else { 433 const routerinfo_t *ri = router_get_by_id_digest(d); 434 /* Don't actually serve a descriptor that everyone will think is 435 * expired. This is an (ugly) workaround to keep buggy 0.1.1.10 436 * Tors from downloading descriptors that they will throw away. 437 */ 438 if (ri && ri->cache_info.published_on > cutoff) 439 smartlist_add(descs_out, (void*) &(ri->cache_info)); 440 } 441 } SMARTLIST_FOREACH_END(d); 442 SMARTLIST_FOREACH(digests, char *, d, tor_free(d)); 443 smartlist_free(digests); 444 } else { 445 *msg = "Key not recognized"; 446 return -1; 447 } 448 449 if (!smartlist_len(descs_out)) { 450 *msg = "Servers unavailable"; 451 return -1; 452 } 453 return 0; 454 } 455 456 /** Implementation helper for GETINFO: knows the answers for questions about 457 * directory information. */ 458 STATIC int 459 getinfo_helper_dir(control_connection_t *control_conn, 460 const char *question, char **answer, 461 const char **errmsg) 462 { 463 (void) control_conn; 464 if (!strcmpstart(question, "desc/id/")) { 465 const routerinfo_t *ri = NULL; 466 const node_t *node = node_get_by_hex_id(question+strlen("desc/id/"), 0); 467 if (node) 468 ri = node->ri; 469 if (ri) { 470 const char *body = signed_descriptor_get_body(&ri->cache_info); 471 if (body) 472 *answer = tor_strndup(body, ri->cache_info.signed_descriptor_len); 473 } else if (! we_fetch_router_descriptors(get_options())) { 474 /* Descriptors won't be available, provide proper error */ 475 *errmsg = "We fetch microdescriptors, not router " 476 "descriptors. You'll need to use md/id/* " 477 "instead of desc/id/*."; 478 return 0; 479 } 480 } else if (!strcmpstart(question, "desc/name/")) { 481 const routerinfo_t *ri = NULL; 482 /* XXX Setting 'warn_if_unnamed' here is a bit silly -- the 483 * warning goes to the user, not to the controller. */ 484 const node_t *node = 485 node_get_by_nickname(question+strlen("desc/name/"), 0); 486 if (node) 487 ri = node->ri; 488 if (ri) { 489 const char *body = signed_descriptor_get_body(&ri->cache_info); 490 if (body) 491 *answer = tor_strndup(body, ri->cache_info.signed_descriptor_len); 492 } else if (! we_fetch_router_descriptors(get_options())) { 493 /* Descriptors won't be available, provide proper error */ 494 *errmsg = "We fetch microdescriptors, not router " 495 "descriptors. You'll need to use md/name/* " 496 "instead of desc/name/*."; 497 return 0; 498 } 499 } else if (!strcmp(question, "desc/download-enabled")) { 500 int r = we_fetch_router_descriptors(get_options()); 501 tor_asprintf(answer, "%d", !!r); 502 } else if (!strcmp(question, "desc/all-recent")) { 503 routerlist_t *routerlist = router_get_routerlist(); 504 smartlist_t *sl = smartlist_new(); 505 if (routerlist && routerlist->routers) { 506 SMARTLIST_FOREACH(routerlist->routers, const routerinfo_t *, ri, 507 { 508 const char *body = signed_descriptor_get_body(&ri->cache_info); 509 if (body) 510 smartlist_add(sl, 511 tor_strndup(body, ri->cache_info.signed_descriptor_len)); 512 }); 513 } 514 *answer = smartlist_join_strings(sl, "", 0, NULL); 515 SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); 516 smartlist_free(sl); 517 } else if (!strcmp(question, "desc/all-recent-extrainfo-hack")) { 518 /* XXXX Remove this once Torstat asks for extrainfos. */ 519 routerlist_t *routerlist = router_get_routerlist(); 520 smartlist_t *sl = smartlist_new(); 521 if (routerlist && routerlist->routers) { 522 SMARTLIST_FOREACH_BEGIN(routerlist->routers, const routerinfo_t *, ri) { 523 const char *body = signed_descriptor_get_body(&ri->cache_info); 524 signed_descriptor_t *ei = extrainfo_get_by_descriptor_digest( 525 ri->cache_info.extra_info_digest); 526 if (ei && body) { 527 smartlist_add(sl, munge_extrainfo_into_routerinfo(body, 528 &ri->cache_info, ei)); 529 } else if (body) { 530 smartlist_add(sl, 531 tor_strndup(body, ri->cache_info.signed_descriptor_len)); 532 } 533 } SMARTLIST_FOREACH_END(ri); 534 } 535 *answer = smartlist_join_strings(sl, "", 0, NULL); 536 SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); 537 smartlist_free(sl); 538 } else if (!strcmpstart(question, "hs/client/desc/id/")) { 539 hostname_type_t addr_type; 540 541 question += strlen("hs/client/desc/id/"); 542 if (hs_address_is_valid(question)) { 543 addr_type = ONION_V3_HOSTNAME; 544 } else { 545 *errmsg = "Invalid address"; 546 return -1; 547 } 548 549 if (addr_type == ONION_V3_HOSTNAME) { 550 ed25519_public_key_t service_pk; 551 const char *desc; 552 553 /* The check before this if/else makes sure of this. */ 554 tor_assert(addr_type == ONION_V3_HOSTNAME); 555 556 if (hs_parse_address(question, &service_pk, NULL, NULL) < 0) { 557 *errmsg = "Invalid v3 address"; 558 return -1; 559 } 560 561 desc = hs_cache_lookup_encoded_as_client(&service_pk); 562 if (desc) { 563 *answer = tor_strdup(desc); 564 } else { 565 *errmsg = "Not found in cache"; 566 return -1; 567 } 568 } 569 } else if (!strcmpstart(question, "hs/service/desc/id/")) { 570 hostname_type_t addr_type; 571 572 question += strlen("hs/service/desc/id/"); 573 if (hs_address_is_valid(question)) { 574 addr_type = ONION_V3_HOSTNAME; 575 } else { 576 *errmsg = "Invalid address"; 577 return -1; 578 } 579 580 if (addr_type == ONION_V3_HOSTNAME) { 581 ed25519_public_key_t service_pk; 582 char *desc; 583 584 /* The check before this if/else makes sure of this. */ 585 tor_assert(addr_type == ONION_V3_HOSTNAME); 586 587 if (hs_parse_address(question, &service_pk, NULL, NULL) < 0) { 588 *errmsg = "Invalid v3 address"; 589 return -1; 590 } 591 592 desc = hs_service_lookup_current_desc(&service_pk); 593 if (desc) { 594 /* Newly allocated string, we have ownership. */ 595 *answer = desc; 596 } else { 597 *errmsg = "Not found in cache"; 598 return -1; 599 } 600 } 601 } else if (!strcmp(question, "md/all")) { 602 const smartlist_t *nodes = nodelist_get_list(); 603 tor_assert(nodes); 604 605 if (smartlist_len(nodes) == 0) { 606 *answer = tor_strdup(""); 607 return 0; 608 } 609 610 smartlist_t *microdescs = smartlist_new(); 611 612 SMARTLIST_FOREACH_BEGIN(nodes, node_t *, n) { 613 if (n->md && n->md->body) { 614 char *copy = tor_strndup(n->md->body, n->md->bodylen); 615 smartlist_add(microdescs, copy); 616 } 617 } SMARTLIST_FOREACH_END(n); 618 619 *answer = smartlist_join_strings(microdescs, "", 0, NULL); 620 SMARTLIST_FOREACH(microdescs, char *, md, tor_free(md)); 621 smartlist_free(microdescs); 622 } else if (!strcmpstart(question, "md/id/")) { 623 const node_t *node = node_get_by_hex_id(question+strlen("md/id/"), 0); 624 const microdesc_t *md = NULL; 625 if (node) md = node->md; 626 if (md && md->body) { 627 *answer = tor_strndup(md->body, md->bodylen); 628 } 629 } else if (!strcmpstart(question, "md/name/")) { 630 /* XXX Setting 'warn_if_unnamed' here is a bit silly -- the 631 * warning goes to the user, not to the controller. */ 632 const node_t *node = node_get_by_nickname(question+strlen("md/name/"), 0); 633 /* XXXX duplicated code */ 634 const microdesc_t *md = NULL; 635 if (node) md = node->md; 636 if (md && md->body) { 637 *answer = tor_strndup(md->body, md->bodylen); 638 } 639 } else if (!strcmp(question, "md/download-enabled")) { 640 int r = we_fetch_microdescriptors(get_options()); 641 tor_asprintf(answer, "%d", !!r); 642 } else if (!strcmpstart(question, "desc-annotations/id/")) { 643 const routerinfo_t *ri = NULL; 644 const node_t *node = 645 node_get_by_hex_id(question+strlen("desc-annotations/id/"), 0); 646 if (node) 647 ri = node->ri; 648 if (ri) { 649 const char *annotations = 650 signed_descriptor_get_annotations(&ri->cache_info); 651 if (annotations) 652 *answer = tor_strndup(annotations, 653 ri->cache_info.annotations_len); 654 } 655 } else if (!strcmpstart(question, "dir/server/")) { 656 size_t answer_len = 0; 657 char *url = NULL; 658 smartlist_t *descs = smartlist_new(); 659 const char *msg; 660 int res; 661 char *cp; 662 tor_asprintf(&url, "/tor/%s", question+4); 663 res = controller_get_routerdescs(descs, url, &msg); 664 if (res) { 665 log_warn(LD_CONTROL, "getinfo '%s': %s", question, msg); 666 smartlist_free(descs); 667 tor_free(url); 668 *errmsg = msg; 669 return -1; 670 } 671 SMARTLIST_FOREACH(descs, signed_descriptor_t *, sd, 672 answer_len += sd->signed_descriptor_len); 673 cp = *answer = tor_malloc(answer_len+1); 674 SMARTLIST_FOREACH(descs, signed_descriptor_t *, sd, 675 { 676 memcpy(cp, signed_descriptor_get_body(sd), 677 sd->signed_descriptor_len); 678 cp += sd->signed_descriptor_len; 679 }); 680 *cp = '\0'; 681 tor_free(url); 682 smartlist_free(descs); 683 } else if (!strcmpstart(question, "dir/status/")) { 684 *answer = tor_strdup(""); 685 } else if (!strcmp(question, "dir/status-vote/current/consensus")) { 686 int consensus_result = getinfo_helper_current_consensus(FLAV_NS, 687 answer, errmsg); 688 if (consensus_result < 0) { 689 return -1; 690 } 691 } else if (!strcmp(question, 692 "dir/status-vote/current/consensus-microdesc")) { 693 int consensus_result = getinfo_helper_current_consensus(FLAV_MICRODESC, 694 answer, errmsg); 695 if (consensus_result < 0) { 696 return -1; 697 } 698 } else if (!strcmpstart(question, "extra-info/digest/")) { 699 question += strlen("extra-info/digest/"); 700 if (strlen(question) == HEX_DIGEST_LEN) { 701 char d[DIGEST_LEN]; 702 signed_descriptor_t *sd = NULL; 703 if (base16_decode(d, sizeof(d), question, strlen(question)) 704 == sizeof(d)) { 705 /* XXXX this test should move into extrainfo_get_by_descriptor_digest, 706 * but I don't want to risk affecting other parts of the code, 707 * especially since the rules for using our own extrainfo (including 708 * when it might be freed) are different from those for using one 709 * we have downloaded. */ 710 if (router_extrainfo_digest_is_me(d)) 711 sd = &(router_get_my_extrainfo()->cache_info); 712 else 713 sd = extrainfo_get_by_descriptor_digest(d); 714 } 715 if (sd) { 716 const char *body = signed_descriptor_get_body(sd); 717 if (body) 718 *answer = tor_strndup(body, sd->signed_descriptor_len); 719 } 720 } 721 } 722 723 return 0; 724 } 725 726 /** Given a smartlist of 20-byte digests, return a newly allocated string 727 * containing each of those digests in order, formatted in HEX, and terminated 728 * with a newline. */ 729 static char * 730 digest_list_to_string(const smartlist_t *sl) 731 { 732 int len; 733 char *result, *s; 734 735 /* Allow for newlines, and a \0 at the end */ 736 len = smartlist_len(sl) * (HEX_DIGEST_LEN + 1) + 1; 737 result = tor_malloc_zero(len); 738 739 s = result; 740 SMARTLIST_FOREACH_BEGIN(sl, const char *, digest) { 741 base16_encode(s, HEX_DIGEST_LEN + 1, digest, DIGEST_LEN); 742 s[HEX_DIGEST_LEN] = '\n'; 743 s += HEX_DIGEST_LEN + 1; 744 } SMARTLIST_FOREACH_END(digest); 745 *s = '\0'; 746 747 return result; 748 } 749 750 /** Turn a download_status_t into a human-readable description in a newly 751 * allocated string. The format is specified in control-spec.txt, under 752 * the documentation for "GETINFO download/..." . */ 753 static char * 754 download_status_to_string(const download_status_t *dl) 755 { 756 char *rv = NULL; 757 char tbuf[ISO_TIME_LEN+1]; 758 const char *schedule_str, *want_authority_str; 759 const char *increment_on_str, *backoff_str; 760 761 if (dl) { 762 /* Get some substrings of the eventual output ready */ 763 format_iso_time(tbuf, download_status_get_next_attempt_at(dl)); 764 765 switch (dl->schedule) { 766 case DL_SCHED_GENERIC: 767 schedule_str = "DL_SCHED_GENERIC"; 768 break; 769 case DL_SCHED_CONSENSUS: 770 schedule_str = "DL_SCHED_CONSENSUS"; 771 break; 772 case DL_SCHED_BRIDGE: 773 schedule_str = "DL_SCHED_BRIDGE"; 774 break; 775 default: 776 schedule_str = "unknown"; 777 break; 778 } 779 780 switch (dl->want_authority) { 781 case DL_WANT_ANY_DIRSERVER: 782 want_authority_str = "DL_WANT_ANY_DIRSERVER"; 783 break; 784 case DL_WANT_AUTHORITY: 785 want_authority_str = "DL_WANT_AUTHORITY"; 786 break; 787 default: 788 want_authority_str = "unknown"; 789 break; 790 } 791 792 switch (dl->increment_on) { 793 case DL_SCHED_INCREMENT_FAILURE: 794 increment_on_str = "DL_SCHED_INCREMENT_FAILURE"; 795 break; 796 case DL_SCHED_INCREMENT_ATTEMPT: 797 increment_on_str = "DL_SCHED_INCREMENT_ATTEMPT"; 798 break; 799 default: 800 increment_on_str = "unknown"; 801 break; 802 } 803 804 backoff_str = "DL_SCHED_RANDOM_EXPONENTIAL"; 805 806 /* Now assemble them */ 807 tor_asprintf(&rv, 808 "next-attempt-at %s\n" 809 "n-download-failures %u\n" 810 "n-download-attempts %u\n" 811 "schedule %s\n" 812 "want-authority %s\n" 813 "increment-on %s\n" 814 "backoff %s\n" 815 "last-backoff-position %u\n" 816 "last-delay-used %d\n", 817 tbuf, 818 dl->n_download_failures, 819 dl->n_download_attempts, 820 schedule_str, 821 want_authority_str, 822 increment_on_str, 823 backoff_str, 824 dl->last_backoff_position, 825 dl->last_delay_used); 826 } 827 828 return rv; 829 } 830 831 /** Handle the consensus download cases for getinfo_helper_downloads() */ 832 STATIC void 833 getinfo_helper_downloads_networkstatus(const char *flavor, 834 download_status_t **dl_to_emit, 835 const char **errmsg) 836 { 837 /* 838 * We get the one for the current bootstrapped status by default, or 839 * take an extra /bootstrap or /running suffix 840 */ 841 if (strcmp(flavor, "ns") == 0) { 842 *dl_to_emit = networkstatus_get_dl_status_by_flavor(FLAV_NS); 843 } else if (strcmp(flavor, "ns/bootstrap") == 0) { 844 *dl_to_emit = networkstatus_get_dl_status_by_flavor_bootstrap(FLAV_NS); 845 } else if (strcmp(flavor, "ns/running") == 0 ) { 846 *dl_to_emit = networkstatus_get_dl_status_by_flavor_running(FLAV_NS); 847 } else if (strcmp(flavor, "microdesc") == 0) { 848 *dl_to_emit = networkstatus_get_dl_status_by_flavor(FLAV_MICRODESC); 849 } else if (strcmp(flavor, "microdesc/bootstrap") == 0) { 850 *dl_to_emit = 851 networkstatus_get_dl_status_by_flavor_bootstrap(FLAV_MICRODESC); 852 } else if (strcmp(flavor, "microdesc/running") == 0) { 853 *dl_to_emit = 854 networkstatus_get_dl_status_by_flavor_running(FLAV_MICRODESC); 855 } else { 856 *errmsg = "Unknown flavor"; 857 } 858 } 859 860 /** Handle the cert download cases for getinfo_helper_downloads() */ 861 STATIC void 862 getinfo_helper_downloads_cert(const char *fp_sk_req, 863 download_status_t **dl_to_emit, 864 smartlist_t **digest_list, 865 const char **errmsg) 866 { 867 const char *sk_req; 868 char id_digest[DIGEST_LEN]; 869 char sk_digest[DIGEST_LEN]; 870 871 /* 872 * We have to handle four cases; fp_sk_req is the request with 873 * a prefix of "downloads/cert/" snipped off. 874 * 875 * Case 1: fp_sk_req = "fps" 876 * - We should emit a digest_list with a list of all the identity 877 * fingerprints that can be queried for certificate download status; 878 * get it by calling list_authority_ids_with_downloads(). 879 * 880 * Case 2: fp_sk_req = "fp/<fp>" for some fingerprint fp 881 * - We want the default certificate for this identity fingerprint's 882 * download status; this is the download we get from URLs starting 883 * in /fp/ on the directory server. We can get it with 884 * id_only_download_status_for_authority_id(). 885 * 886 * Case 3: fp_sk_req = "fp/<fp>/sks" for some fingerprint fp 887 * - We want a list of all signing key digests for this identity 888 * fingerprint which can be queried for certificate download status. 889 * Get it with list_sk_digests_for_authority_id(). 890 * 891 * Case 4: fp_sk_req = "fp/<fp>/<sk>" for some fingerprint fp and 892 * signing key digest sk 893 * - We want the download status for the certificate for this specific 894 * signing key and fingerprint. These correspond to the ones we get 895 * from URLs starting in /fp-sk/ on the directory server. Get it with 896 * list_sk_digests_for_authority_id(). 897 */ 898 899 if (strcmp(fp_sk_req, "fps") == 0) { 900 *digest_list = list_authority_ids_with_downloads(); 901 if (!(*digest_list)) { 902 *errmsg = "Failed to get list of authority identity digests (!)"; 903 } 904 } else if (!strcmpstart(fp_sk_req, "fp/")) { 905 fp_sk_req += strlen("fp/"); 906 /* Okay, look for another / to tell the fp from fp-sk cases */ 907 sk_req = strchr(fp_sk_req, '/'); 908 if (sk_req) { 909 /* okay, split it here and try to parse <fp> */ 910 if (base16_decode(id_digest, DIGEST_LEN, 911 fp_sk_req, sk_req - fp_sk_req) == DIGEST_LEN) { 912 /* Skip past the '/' */ 913 ++sk_req; 914 if (strcmp(sk_req, "sks") == 0) { 915 /* We're asking for the list of signing key fingerprints */ 916 *digest_list = list_sk_digests_for_authority_id(id_digest); 917 if (!(*digest_list)) { 918 *errmsg = "Failed to get list of signing key digests for this " 919 "authority identity digest"; 920 } 921 } else { 922 /* We've got a signing key digest */ 923 if (base16_decode(sk_digest, DIGEST_LEN, 924 sk_req, strlen(sk_req)) == DIGEST_LEN) { 925 *dl_to_emit = 926 download_status_for_authority_id_and_sk(id_digest, sk_digest); 927 if (!(*dl_to_emit)) { 928 *errmsg = "Failed to get download status for this identity/" 929 "signing key digest pair"; 930 } 931 } else { 932 *errmsg = "That didn't look like a signing key digest"; 933 } 934 } 935 } else { 936 *errmsg = "That didn't look like an identity digest"; 937 } 938 } else { 939 /* We're either in downloads/certs/fp/<fp>, or we can't parse <fp> */ 940 if (strlen(fp_sk_req) == HEX_DIGEST_LEN) { 941 if (base16_decode(id_digest, DIGEST_LEN, 942 fp_sk_req, strlen(fp_sk_req)) == DIGEST_LEN) { 943 *dl_to_emit = id_only_download_status_for_authority_id(id_digest); 944 if (!(*dl_to_emit)) { 945 *errmsg = "Failed to get download status for this authority " 946 "identity digest"; 947 } 948 } else { 949 *errmsg = "That didn't look like a digest"; 950 } 951 } else { 952 *errmsg = "That didn't look like a digest"; 953 } 954 } 955 } else { 956 *errmsg = "Unknown certificate download status query"; 957 } 958 } 959 960 /** Handle the routerdesc download cases for getinfo_helper_downloads() */ 961 STATIC void 962 getinfo_helper_downloads_desc(const char *desc_req, 963 download_status_t **dl_to_emit, 964 smartlist_t **digest_list, 965 const char **errmsg) 966 { 967 char desc_digest[DIGEST_LEN]; 968 /* 969 * Two cases to handle here: 970 * 971 * Case 1: desc_req = "descs" 972 * - Emit a list of all router descriptor digests, which we get by 973 * calling router_get_descriptor_digests(); this can return NULL 974 * if we have no current ns-flavor consensus. 975 * 976 * Case 2: desc_req = <fp> 977 * - Check on the specified fingerprint and emit its download_status_t 978 * using router_get_dl_status_by_descriptor_digest(). 979 */ 980 981 if (strcmp(desc_req, "descs") == 0) { 982 *digest_list = router_get_descriptor_digests(); 983 if (!(*digest_list)) { 984 *errmsg = "We don't seem to have a networkstatus-flavored consensus"; 985 } 986 /* 987 * Microdescs don't use the download_status_t mechanism, so we don't 988 * answer queries about their downloads here; see microdesc.c. 989 */ 990 } else if (strlen(desc_req) == HEX_DIGEST_LEN) { 991 if (base16_decode(desc_digest, DIGEST_LEN, 992 desc_req, strlen(desc_req)) == DIGEST_LEN) { 993 /* Okay we got a digest-shaped thing; try asking for it */ 994 *dl_to_emit = router_get_dl_status_by_descriptor_digest(desc_digest); 995 if (!(*dl_to_emit)) { 996 *errmsg = "No such descriptor digest found"; 997 } 998 } else { 999 *errmsg = "That didn't look like a digest"; 1000 } 1001 } else { 1002 *errmsg = "Unknown router descriptor download status query"; 1003 } 1004 } 1005 1006 /** Handle the bridge download cases for getinfo_helper_downloads() */ 1007 STATIC void 1008 getinfo_helper_downloads_bridge(const char *bridge_req, 1009 download_status_t **dl_to_emit, 1010 smartlist_t **digest_list, 1011 const char **errmsg) 1012 { 1013 char bridge_digest[DIGEST_LEN]; 1014 /* 1015 * Two cases to handle here: 1016 * 1017 * Case 1: bridge_req = "bridges" 1018 * - Emit a list of all bridge identity digests, which we get by 1019 * calling list_bridge_identities(); this can return NULL if we are 1020 * not using bridges. 1021 * 1022 * Case 2: bridge_req = <fp> 1023 * - Check on the specified fingerprint and emit its download_status_t 1024 * using get_bridge_dl_status_by_id(). 1025 */ 1026 1027 if (strcmp(bridge_req, "bridges") == 0) { 1028 *digest_list = list_bridge_identities(); 1029 if (!(*digest_list)) { 1030 *errmsg = "We don't seem to be using bridges"; 1031 } 1032 } else if (strlen(bridge_req) == HEX_DIGEST_LEN) { 1033 if (base16_decode(bridge_digest, DIGEST_LEN, 1034 bridge_req, strlen(bridge_req)) == DIGEST_LEN) { 1035 /* Okay we got a digest-shaped thing; try asking for it */ 1036 *dl_to_emit = get_bridge_dl_status_by_id(bridge_digest); 1037 if (!(*dl_to_emit)) { 1038 *errmsg = "No such bridge identity digest found"; 1039 } 1040 } else { 1041 *errmsg = "That didn't look like a digest"; 1042 } 1043 } else { 1044 *errmsg = "Unknown bridge descriptor download status query"; 1045 } 1046 } 1047 1048 /** Implementation helper for GETINFO: knows the answers for questions about 1049 * download status information. */ 1050 STATIC int 1051 getinfo_helper_downloads(control_connection_t *control_conn, 1052 const char *question, char **answer, 1053 const char **errmsg) 1054 { 1055 download_status_t *dl_to_emit = NULL; 1056 smartlist_t *digest_list = NULL; 1057 1058 /* Assert args are sane */ 1059 tor_assert(control_conn != NULL); 1060 tor_assert(question != NULL); 1061 tor_assert(answer != NULL); 1062 tor_assert(errmsg != NULL); 1063 1064 /* We check for this later to see if we should supply a default */ 1065 *errmsg = NULL; 1066 1067 /* Are we after networkstatus downloads? */ 1068 if (!strcmpstart(question, "downloads/networkstatus/")) { 1069 getinfo_helper_downloads_networkstatus( 1070 question + strlen("downloads/networkstatus/"), 1071 &dl_to_emit, errmsg); 1072 /* Certificates? */ 1073 } else if (!strcmpstart(question, "downloads/cert/")) { 1074 getinfo_helper_downloads_cert( 1075 question + strlen("downloads/cert/"), 1076 &dl_to_emit, &digest_list, errmsg); 1077 /* Router descriptors? */ 1078 } else if (!strcmpstart(question, "downloads/desc/")) { 1079 getinfo_helper_downloads_desc( 1080 question + strlen("downloads/desc/"), 1081 &dl_to_emit, &digest_list, errmsg); 1082 /* Bridge descriptors? */ 1083 } else if (!strcmpstart(question, "downloads/bridge/")) { 1084 getinfo_helper_downloads_bridge( 1085 question + strlen("downloads/bridge/"), 1086 &dl_to_emit, &digest_list, errmsg); 1087 } else { 1088 *errmsg = "Unknown download status query"; 1089 } 1090 1091 if (dl_to_emit) { 1092 *answer = download_status_to_string(dl_to_emit); 1093 1094 return 0; 1095 } else if (digest_list) { 1096 *answer = digest_list_to_string(digest_list); 1097 SMARTLIST_FOREACH(digest_list, void *, s, tor_free(s)); 1098 smartlist_free(digest_list); 1099 1100 return 0; 1101 } else { 1102 if (!(*errmsg)) { 1103 *errmsg = "Unknown error"; 1104 } 1105 1106 return -1; 1107 } 1108 } 1109 1110 /** Implementation helper for GETINFO: knows how to generate summaries of the 1111 * current states of things we send events about. */ 1112 static int 1113 getinfo_helper_events(control_connection_t *control_conn, 1114 const char *question, char **answer, 1115 const char **errmsg) 1116 { 1117 const or_options_t *options = get_options(); 1118 (void) control_conn; 1119 if (!strcmp(question, "circuit-status")) { 1120 smartlist_t *status = smartlist_new(); 1121 SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ_) { 1122 origin_circuit_t *circ; 1123 char *circdesc; 1124 const char *state; 1125 if (! CIRCUIT_IS_ORIGIN(circ_) || circ_->marked_for_close) 1126 continue; 1127 circ = TO_ORIGIN_CIRCUIT(circ_); 1128 1129 if (circ->base_.state == CIRCUIT_STATE_OPEN) 1130 state = "BUILT"; 1131 else if (circ->base_.state == CIRCUIT_STATE_GUARD_WAIT) 1132 state = "GUARD_WAIT"; 1133 else if (circ->cpath) 1134 state = "EXTENDED"; 1135 else 1136 state = "LAUNCHED"; 1137 1138 circdesc = circuit_describe_status_for_controller(circ); 1139 1140 smartlist_add_asprintf(status, "%lu %s%s%s", 1141 (unsigned long)circ->global_identifier, 1142 state, *circdesc ? " " : "", circdesc); 1143 tor_free(circdesc); 1144 } 1145 SMARTLIST_FOREACH_END(circ_); 1146 *answer = smartlist_join_strings(status, "\r\n", 0, NULL); 1147 SMARTLIST_FOREACH(status, char *, cp, tor_free(cp)); 1148 smartlist_free(status); 1149 } else if (!strcmp(question, "stream-status")) { 1150 smartlist_t *conns = get_connection_array(); 1151 smartlist_t *status = smartlist_new(); 1152 char buf[256]; 1153 SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) { 1154 const char *state; 1155 entry_connection_t *conn; 1156 circuit_t *circ; 1157 origin_circuit_t *origin_circ = NULL; 1158 if (base_conn->type != CONN_TYPE_AP || 1159 base_conn->marked_for_close || 1160 base_conn->state == AP_CONN_STATE_SOCKS_WAIT || 1161 base_conn->state == AP_CONN_STATE_NATD_WAIT) 1162 continue; 1163 conn = TO_ENTRY_CONN(base_conn); 1164 switch (base_conn->state) 1165 { 1166 case AP_CONN_STATE_CONTROLLER_WAIT: 1167 case AP_CONN_STATE_CIRCUIT_WAIT: 1168 if (conn->socks_request && 1169 SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) 1170 state = "NEWRESOLVE"; 1171 else 1172 state = "NEW"; 1173 break; 1174 case AP_CONN_STATE_RENDDESC_WAIT: 1175 case AP_CONN_STATE_CONNECT_WAIT: 1176 state = "SENTCONNECT"; break; 1177 case AP_CONN_STATE_RESOLVE_WAIT: 1178 state = "SENTRESOLVE"; break; 1179 case AP_CONN_STATE_OPEN: 1180 state = "SUCCEEDED"; break; 1181 default: 1182 log_warn(LD_BUG, "Asked for stream in unknown state %d", 1183 base_conn->state); 1184 continue; 1185 } 1186 circ = circuit_get_by_edge_conn(ENTRY_TO_EDGE_CONN(conn)); 1187 if (circ && CIRCUIT_IS_ORIGIN(circ)) 1188 origin_circ = TO_ORIGIN_CIRCUIT(circ); 1189 write_stream_target_to_buf(conn, buf, sizeof(buf)); 1190 smartlist_add_asprintf(status, "%lu %s %lu %s", 1191 (unsigned long) base_conn->global_identifier,state, 1192 origin_circ? 1193 (unsigned long)origin_circ->global_identifier : 0ul, 1194 buf); 1195 } SMARTLIST_FOREACH_END(base_conn); 1196 *answer = smartlist_join_strings(status, "\r\n", 0, NULL); 1197 SMARTLIST_FOREACH(status, char *, cp, tor_free(cp)); 1198 smartlist_free(status); 1199 } else if (!strcmp(question, "orconn-status")) { 1200 smartlist_t *conns = get_connection_array(); 1201 smartlist_t *status = smartlist_new(); 1202 SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) { 1203 const char *state; 1204 char name[128]; 1205 or_connection_t *conn; 1206 if (base_conn->type != CONN_TYPE_OR || base_conn->marked_for_close) 1207 continue; 1208 conn = TO_OR_CONN(base_conn); 1209 if (conn->base_.state == OR_CONN_STATE_OPEN) 1210 state = "CONNECTED"; 1211 else if (conn->nickname) 1212 state = "LAUNCHED"; 1213 else 1214 state = "NEW"; 1215 orconn_target_get_name(name, sizeof(name), conn); 1216 smartlist_add_asprintf(status, "%s %s", name, state); 1217 } SMARTLIST_FOREACH_END(base_conn); 1218 *answer = smartlist_join_strings(status, "\r\n", 0, NULL); 1219 SMARTLIST_FOREACH(status, char *, cp, tor_free(cp)); 1220 smartlist_free(status); 1221 } else if (!strcmpstart(question, "address-mappings/")) { 1222 time_t min_e, max_e; 1223 smartlist_t *mappings; 1224 question += strlen("address-mappings/"); 1225 if (!strcmp(question, "all")) { 1226 min_e = 0; max_e = TIME_MAX; 1227 } else if (!strcmp(question, "cache")) { 1228 min_e = 2; max_e = TIME_MAX; 1229 } else if (!strcmp(question, "config")) { 1230 min_e = 0; max_e = 0; 1231 } else if (!strcmp(question, "control")) { 1232 min_e = 1; max_e = 1; 1233 } else { 1234 return 0; 1235 } 1236 mappings = smartlist_new(); 1237 addressmap_get_mappings(mappings, min_e, max_e, 1); 1238 *answer = smartlist_join_strings(mappings, "\r\n", 0, NULL); 1239 SMARTLIST_FOREACH(mappings, char *, cp, tor_free(cp)); 1240 smartlist_free(mappings); 1241 } else if (!strcmpstart(question, "status/")) { 1242 /* Note that status/ is not a catch-all for events; there's only supposed 1243 * to be a status GETINFO if there's a corresponding STATUS event. */ 1244 if (!strcmp(question, "status/circuit-established")) { 1245 *answer = tor_strdup(have_completed_a_circuit() ? "1" : "0"); 1246 } else if (!strcmp(question, "status/enough-dir-info")) { 1247 *answer = tor_strdup(router_have_minimum_dir_info() ? "1" : "0"); 1248 } else if (!strcmp(question, "status/good-server-descriptor") || 1249 !strcmp(question, "status/accepted-server-descriptor")) { 1250 /* They're equivalent for now, until we can figure out how to make 1251 * good-server-descriptor be what we want. See comment in 1252 * control-spec.txt. */ 1253 *answer = tor_strdup(directories_have_accepted_server_descriptor() 1254 ? "1" : "0"); 1255 } else if (!strcmp(question, "status/reachability-succeeded/or")) { 1256 *answer = tor_strdup( 1257 router_all_orports_seem_reachable(options) ? 1258 "1" : "0"); 1259 } else if (!strcmp(question, "status/reachability-succeeded/dir")) { 1260 *answer = tor_strdup("1"); /* obsolete since tor#2667) */ 1261 } else if (!strcmp(question, "status/reachability-succeeded")) { 1262 tor_asprintf( 1263 answer, "OR=%d DIR=%d", 1264 router_all_orports_seem_reachable(options) ? 1 : 0, 1265 1); 1266 } else if (!strcmp(question, "status/bootstrap-phase")) { 1267 *answer = control_event_boot_last_msg(); 1268 } else if (!strcmpstart(question, "status/version/")) { 1269 int is_server = server_mode(options); 1270 networkstatus_t *c = networkstatus_get_latest_consensus(); 1271 version_status_t status; 1272 const char *recommended; 1273 if (c) { 1274 recommended = is_server ? c->server_versions : c->client_versions; 1275 status = tor_version_is_obsolete(VERSION, recommended); 1276 } else { 1277 recommended = "?"; 1278 status = VS_UNKNOWN; 1279 } 1280 1281 if (!strcmp(question, "status/version/recommended")) { 1282 *answer = tor_strdup(recommended); 1283 return 0; 1284 } 1285 if (!strcmp(question, "status/version/current")) { 1286 switch (status) 1287 { 1288 case VS_RECOMMENDED: *answer = tor_strdup("recommended"); break; 1289 case VS_OLD: *answer = tor_strdup("obsolete"); break; 1290 case VS_NEW: *answer = tor_strdup("new"); break; 1291 case VS_NEW_IN_SERIES: *answer = tor_strdup("new in series"); break; 1292 case VS_UNRECOMMENDED: *answer = tor_strdup("unrecommended"); break; 1293 case VS_EMPTY: *answer = tor_strdup("none recommended"); break; 1294 case VS_UNKNOWN: *answer = tor_strdup("unknown"); break; 1295 default: tor_fragile_assert(); 1296 } 1297 } 1298 } else if (!strcmp(question, "status/clients-seen")) { 1299 char *bridge_stats = geoip_get_bridge_stats_controller(time(NULL)); 1300 if (!bridge_stats) { 1301 *errmsg = "No bridge-client stats available"; 1302 return -1; 1303 } 1304 *answer = bridge_stats; 1305 } else if (!strcmp(question, "status/fresh-relay-descs")) { 1306 if (!server_mode(options)) { 1307 *errmsg = "Only relays have descriptors"; 1308 return -1; 1309 } 1310 routerinfo_t *r; 1311 extrainfo_t *e; 1312 int result; 1313 if ((result = router_build_fresh_descriptor(&r, &e)) < 0) { 1314 switch (result) { 1315 case TOR_ROUTERINFO_ERROR_NO_EXT_ADDR: 1316 *errmsg = "Cannot get relay address while generating descriptor"; 1317 break; 1318 case TOR_ROUTERINFO_ERROR_DIGEST_FAILED: 1319 *errmsg = "Key digest failed"; 1320 break; 1321 case TOR_ROUTERINFO_ERROR_CANNOT_GENERATE: 1322 *errmsg = "Cannot generate router descriptor"; 1323 break; 1324 default: 1325 *errmsg = "Error generating descriptor"; 1326 break; 1327 } 1328 return -1; 1329 } 1330 size_t size = r->cache_info.signed_descriptor_len + 1; 1331 if (e) { 1332 size += e->cache_info.signed_descriptor_len + 1; 1333 } 1334 tor_assert(r->cache_info.signed_descriptor_len); 1335 char *descs = tor_malloc(size); 1336 char *cp = descs; 1337 memcpy(cp, signed_descriptor_get_body(&r->cache_info), 1338 r->cache_info.signed_descriptor_len); 1339 cp += r->cache_info.signed_descriptor_len - 1; 1340 if (e) { 1341 if (cp[0] == '\0') { 1342 cp[0] = '\n'; 1343 } else if (cp[0] != '\n') { 1344 cp[1] = '\n'; 1345 cp++; 1346 } 1347 memcpy(cp, signed_descriptor_get_body(&e->cache_info), 1348 e->cache_info.signed_descriptor_len); 1349 cp += e->cache_info.signed_descriptor_len - 1; 1350 } 1351 if (cp[0] == '\n') { 1352 cp[0] = '\0'; 1353 } else if (cp[0] != '\0') { 1354 cp[1] = '\0'; 1355 } 1356 *answer = descs; 1357 routerinfo_free(r); 1358 extrainfo_free(e); 1359 } else { 1360 return 0; 1361 } 1362 } 1363 return 0; 1364 } 1365 1366 /** Implementation helper for GETINFO: knows how to enumerate hidden services 1367 * created via the control port. */ 1368 STATIC int 1369 getinfo_helper_onions(control_connection_t *control_conn, 1370 const char *question, char **answer, 1371 const char **errmsg) 1372 { 1373 smartlist_t *onion_list = NULL; 1374 (void) errmsg; /* no errors from this method */ 1375 1376 if (control_conn && !strcmp(question, "onions/current")) { 1377 onion_list = control_conn->ephemeral_onion_services; 1378 } else if (!strcmp(question, "onions/detached")) { 1379 onion_list = get_detached_onion_services(); 1380 } else { 1381 return 0; 1382 } 1383 if (!onion_list || smartlist_len(onion_list) == 0) { 1384 if (answer) { 1385 *answer = tor_strdup(""); 1386 } 1387 } else { 1388 if (answer) { 1389 *answer = smartlist_join_strings(onion_list, "\r\n", 0, NULL); 1390 } 1391 } 1392 1393 return 0; 1394 } 1395 1396 /** Implementation helper for GETINFO: answers queries about network 1397 * liveness. */ 1398 static int 1399 getinfo_helper_liveness(control_connection_t *control_conn, 1400 const char *question, char **answer, 1401 const char **errmsg) 1402 { 1403 (void)control_conn; 1404 (void)errmsg; 1405 if (strcmp(question, "network-liveness") == 0) { 1406 if (get_cached_network_liveness()) { 1407 *answer = tor_strdup("up"); 1408 } else { 1409 *answer = tor_strdup("down"); 1410 } 1411 } 1412 1413 return 0; 1414 } 1415 1416 /** Implementation helper for GETINFO: answers queries about circuit onion 1417 * handshake rephist values */ 1418 STATIC int 1419 getinfo_helper_rephist(control_connection_t *control_conn, 1420 const char *question, char **answer, 1421 const char **errmsg) 1422 { 1423 (void) control_conn; 1424 (void) errmsg; 1425 int result; 1426 1427 if (!strcmp(question, "stats/ntor/assigned")) { 1428 result = 1429 rep_hist_get_circuit_handshake_assigned(ONION_HANDSHAKE_TYPE_NTOR); 1430 } else if (!strcmp(question, "stats/ntor/requested")) { 1431 result = 1432 rep_hist_get_circuit_handshake_requested(ONION_HANDSHAKE_TYPE_NTOR); 1433 } else if (!strcmp(question, "stats/tap/assigned")) { 1434 result = 1435 rep_hist_get_circuit_handshake_assigned(ONION_HANDSHAKE_TYPE_TAP); 1436 } else if (!strcmp(question, "stats/tap/requested")) { 1437 result = 1438 rep_hist_get_circuit_handshake_requested(ONION_HANDSHAKE_TYPE_TAP); 1439 } else { 1440 *errmsg = "Unrecognized handshake type"; 1441 return -1; 1442 } 1443 1444 tor_asprintf(answer, "%d", result); 1445 1446 return 0; 1447 } 1448 1449 /** Implementation helper for GETINFO: answers queries about shared random 1450 * value. */ 1451 static int 1452 getinfo_helper_sr(control_connection_t *control_conn, 1453 const char *question, char **answer, 1454 const char **errmsg) 1455 { 1456 (void) control_conn; 1457 (void) errmsg; 1458 1459 if (!strcmp(question, "sr/current")) { 1460 *answer = sr_get_current_for_control(); 1461 } else if (!strcmp(question, "sr/previous")) { 1462 *answer = sr_get_previous_for_control(); 1463 } 1464 /* Else statement here is unrecognized key so do nothing. */ 1465 1466 return 0; 1467 } 1468 1469 /** Callback function for GETINFO: on a given control connection, try to 1470 * answer the question <b>q</b> and store the newly-allocated answer in 1471 * *<b>a</b>. If an internal error occurs, return -1 and optionally set 1472 * *<b>error_out</b> to point to an error message to be delivered to the 1473 * controller. On success, _or if the key is not recognized_, return 0. Do not 1474 * set <b>a</b> if the key is not recognized but you may set <b>error_out</b> 1475 * to improve the error message. 1476 */ 1477 typedef int (*getinfo_helper_t)(control_connection_t *, 1478 const char *q, char **a, 1479 const char **error_out); 1480 1481 /** A single item for the GETINFO question-to-answer-function table. */ 1482 typedef struct getinfo_item_t { 1483 const char *varname; /**< The value (or prefix) of the question. */ 1484 getinfo_helper_t fn; /**< The function that knows the answer: NULL if 1485 * this entry is documentation-only. */ 1486 const char *desc; /**< Description of the variable. */ 1487 int is_prefix; /** Must varname match exactly, or must it be a prefix? */ 1488 } getinfo_item_t; 1489 1490 #define ITEM(name, fn, desc) { name, getinfo_helper_##fn, desc, 0 } 1491 #define PREFIX(name, fn, desc) { name, getinfo_helper_##fn, desc, 1 } 1492 #define DOC(name, desc) { name, NULL, desc, 0 } 1493 1494 /** Table mapping questions accepted by GETINFO to the functions that know how 1495 * to answer them. */ 1496 static const getinfo_item_t getinfo_items[] = { 1497 ITEM("version", misc, "The current version of Tor."), 1498 ITEM("bw-event-cache", misc, "Cached BW events for a short interval."), 1499 ITEM("config-file", misc, "Current location of the \"torrc\" file."), 1500 ITEM("config-defaults-file", misc, "Current location of the defaults file."), 1501 ITEM("config-text", misc, 1502 "Return the string that would be written by a saveconf command."), 1503 ITEM("config-can-saveconf", misc, 1504 "Is it possible to save the configuration to the \"torrc\" file?"), 1505 ITEM("accounting/bytes", accounting, 1506 "Number of bytes read/written so far in the accounting interval."), 1507 ITEM("accounting/bytes-left", accounting, 1508 "Number of bytes left to write/read so far in the accounting interval."), 1509 ITEM("accounting/enabled", accounting, "Is accounting currently enabled?"), 1510 ITEM("accounting/hibernating", accounting, "Are we hibernating or awake?"), 1511 ITEM("accounting/interval-start", accounting, 1512 "Time when the accounting period starts."), 1513 ITEM("accounting/interval-end", accounting, 1514 "Time when the accounting period ends."), 1515 ITEM("accounting/interval-wake", accounting, 1516 "Time to wake up in this accounting period."), 1517 ITEM("helper-nodes", entry_guards, NULL), /* deprecated */ 1518 ITEM("entry-guards", entry_guards, 1519 "Which nodes are we using as entry guards?"), 1520 ITEM("fingerprint", misc, NULL), 1521 PREFIX("config/", config, "Current configuration values."), 1522 DOC("config/names", 1523 "List of configuration options, types, and documentation."), 1524 DOC("config/defaults", 1525 "List of default values for configuration options. " 1526 "See also config/names"), 1527 PREFIX("current-time/", current_time, "Current time."), 1528 DOC("current-time/local", "Current time on the local system."), 1529 DOC("current-time/utc", "Current UTC time."), 1530 PREFIX("downloads/networkstatus/", downloads, 1531 "Download statuses for networkstatus objects"), 1532 DOC("downloads/networkstatus/ns", 1533 "Download status for current-mode networkstatus download"), 1534 DOC("downloads/networkstatus/ns/bootstrap", 1535 "Download status for bootstrap-time networkstatus download"), 1536 DOC("downloads/networkstatus/ns/running", 1537 "Download status for run-time networkstatus download"), 1538 DOC("downloads/networkstatus/microdesc", 1539 "Download status for current-mode microdesc download"), 1540 DOC("downloads/networkstatus/microdesc/bootstrap", 1541 "Download status for bootstrap-time microdesc download"), 1542 DOC("downloads/networkstatus/microdesc/running", 1543 "Download status for run-time microdesc download"), 1544 PREFIX("downloads/cert/", downloads, 1545 "Download statuses for certificates, by id fingerprint and " 1546 "signing key"), 1547 DOC("downloads/cert/fps", 1548 "List of authority fingerprints for which any download statuses " 1549 "exist"), 1550 DOC("downloads/cert/fp/<fp>", 1551 "Download status for <fp> with the default signing key; corresponds " 1552 "to /fp/ URLs on directory server."), 1553 DOC("downloads/cert/fp/<fp>/sks", 1554 "List of signing keys for which specific download statuses are " 1555 "available for this id fingerprint"), 1556 DOC("downloads/cert/fp/<fp>/<sk>", 1557 "Download status for <fp> with signing key <sk>; corresponds " 1558 "to /fp-sk/ URLs on directory server."), 1559 PREFIX("downloads/desc/", downloads, 1560 "Download statuses for router descriptors, by descriptor digest"), 1561 DOC("downloads/desc/descs", 1562 "Return a list of known router descriptor digests"), 1563 DOC("downloads/desc/<desc>", 1564 "Return a download status for a given descriptor digest"), 1565 PREFIX("downloads/bridge/", downloads, 1566 "Download statuses for bridge descriptors, by bridge identity " 1567 "digest"), 1568 DOC("downloads/bridge/bridges", 1569 "Return a list of configured bridge identity digests with download " 1570 "statuses"), 1571 DOC("downloads/bridge/<desc>", 1572 "Return a download status for a given bridge identity digest"), 1573 ITEM("info/names", misc, 1574 "List of GETINFO options, types, and documentation."), 1575 ITEM("events/names", misc, 1576 "Events that the controller can ask for with SETEVENTS."), 1577 ITEM("signal/names", misc, "Signal names recognized by the SIGNAL command"), 1578 ITEM("features/names", misc, "What arguments can USEFEATURE take?"), 1579 PREFIX("desc/id/", dir, "Router descriptors by ID."), 1580 PREFIX("desc/name/", dir, "Router descriptors by nickname."), 1581 ITEM("desc/all-recent", dir, 1582 "All non-expired, non-superseded router descriptors."), 1583 ITEM("desc/download-enabled", dir, 1584 "Do we try to download router descriptors?"), 1585 ITEM("desc/all-recent-extrainfo-hack", dir, NULL), /* Hack. */ 1586 ITEM("md/all", dir, "All known microdescriptors."), 1587 PREFIX("md/id/", dir, "Microdescriptors by ID"), 1588 PREFIX("md/name/", dir, "Microdescriptors by name"), 1589 ITEM("md/download-enabled", dir, 1590 "Do we try to download microdescriptors?"), 1591 PREFIX("extra-info/digest/", dir, "Extra-info documents by digest."), 1592 PREFIX("hs/client/desc/id", dir, 1593 "Hidden Service descriptor in client's cache by onion."), 1594 PREFIX("hs/service/desc/id/", dir, 1595 "Hidden Service descriptor in services's cache by onion."), 1596 PREFIX("net/listeners/", listeners, "Bound addresses by type"), 1597 ITEM("ns/all", networkstatus, 1598 "Brief summary of router status (v2 directory format)"), 1599 PREFIX("ns/id/", networkstatus, 1600 "Brief summary of router status by ID (v2 directory format)."), 1601 PREFIX("ns/name/", networkstatus, 1602 "Brief summary of router status by nickname (v2 directory format)."), 1603 PREFIX("ns/purpose/", networkstatus, 1604 "Brief summary of router status by purpose (v2 directory format)."), 1605 PREFIX("consensus/", networkstatus, 1606 "Information about and from the ns consensus."), 1607 ITEM("network-status", dir, 1608 "Brief summary of router status (v1 directory format)"), 1609 ITEM("network-liveness", liveness, 1610 "Current opinion on whether the network is live"), 1611 ITEM("circuit-status", events, "List of current circuits originating here."), 1612 ITEM("stream-status", events,"List of current streams."), 1613 ITEM("orconn-status", events, "A list of current OR connections."), 1614 ITEM("dormant", misc, 1615 "Is Tor dormant (not building circuits because it's idle)?"), 1616 PREFIX("address-mappings/", events, NULL), 1617 DOC("address-mappings/all", "Current address mappings."), 1618 DOC("address-mappings/cache", "Current cached DNS replies."), 1619 DOC("address-mappings/config", 1620 "Current address mappings from configuration."), 1621 DOC("address-mappings/control", "Current address mappings from controller."), 1622 PREFIX("status/", events, NULL), 1623 DOC("status/circuit-established", 1624 "Whether we think client functionality is working."), 1625 DOC("status/enough-dir-info", 1626 "Whether we have enough up-to-date directory information to build " 1627 "circuits."), 1628 DOC("status/bootstrap-phase", 1629 "The last bootstrap phase status event that Tor sent."), 1630 DOC("status/clients-seen", 1631 "Breakdown of client countries seen by a bridge."), 1632 DOC("status/fresh-relay-descs", 1633 "A fresh relay/ei descriptor pair for Tor's current state. Not stored."), 1634 DOC("status/version/recommended", "List of currently recommended versions."), 1635 DOC("status/version/current", "Status of the current version."), 1636 ITEM("address", misc, "IP address of this Tor host, if we can guess it."), 1637 ITEM("address/v4", misc, 1638 "IPv4 address of this Tor host, if we can guess it."), 1639 ITEM("address/v6", misc, 1640 "IPv6 address of this Tor host, if we can guess it."), 1641 ITEM("traffic/read", misc,"Bytes read since the process was started."), 1642 ITEM("traffic/written", misc, 1643 "Bytes written since the process was started."), 1644 ITEM("uptime", misc, "Uptime of the Tor daemon in seconds."), 1645 ITEM("process/pid", misc, "Process id belonging to the main tor process."), 1646 ITEM("process/uid", misc, "User id running the tor process."), 1647 ITEM("process/user", misc, 1648 "Username under which the tor process is running."), 1649 ITEM("process/descriptor-limit", misc, "File descriptor limit."), 1650 ITEM("limits/max-mem-in-queues", misc, "Actual limit on memory in queues"), 1651 PREFIX("desc-annotations/id/", dir, "Router annotations by hexdigest."), 1652 PREFIX("dir/server/", dir,"Router descriptors as retrieved from a DirPort."), 1653 PREFIX("dir/status/", dir, 1654 "v2 networkstatus docs as retrieved from a DirPort."), 1655 ITEM("dir/status-vote/current/consensus", dir, 1656 "v3 Networkstatus consensus as retrieved from a DirPort."), 1657 ITEM("dir/status-vote/current/consensus-microdesc", dir, 1658 "v3 Microdescriptor consensus as retrieved from a DirPort."), 1659 ITEM("exit-policy/default", policies, 1660 "The default value appended to the configured exit policy."), 1661 ITEM("exit-policy/reject-private/default", policies, 1662 "The default rules appended to the configured exit policy by" 1663 " ExitPolicyRejectPrivate."), 1664 ITEM("exit-policy/reject-private/relay", policies, 1665 "The relay-specific rules appended to the configured exit policy by" 1666 " ExitPolicyRejectPrivate and/or ExitPolicyRejectLocalInterfaces."), 1667 ITEM("exit-policy/full", policies, "The entire exit policy of onion router"), 1668 ITEM("exit-policy/ipv4", policies, "IPv4 parts of exit policy"), 1669 ITEM("exit-policy/ipv6", policies, "IPv6 parts of exit policy"), 1670 PREFIX("ip-to-country/", geoip, "Perform a GEOIP lookup"), 1671 ITEM("onions/current", onions, 1672 "Onion services owned by the current control connection."), 1673 ITEM("onions/detached", onions, 1674 "Onion services detached from the control connection."), 1675 ITEM("sr/current", sr, "Get current shared random value."), 1676 ITEM("sr/previous", sr, "Get previous shared random value."), 1677 PREFIX("stats/ntor/", rephist, "NTor circuit handshake stats."), 1678 ITEM("stats/ntor/assigned", rephist, 1679 "Assigned NTor circuit handshake stats."), 1680 ITEM("stats/ntor/requested", rephist, 1681 "Requested NTor circuit handshake stats."), 1682 PREFIX("stats/tap/", rephist, "TAP circuit handshake stats."), 1683 ITEM("stats/tap/assigned", rephist, 1684 "Assigned TAP circuit handshake stats."), 1685 ITEM("stats/tap/requested", rephist, 1686 "Requested TAP circuit handshake stats."), 1687 { NULL, NULL, NULL, 0 } 1688 }; 1689 1690 /** Allocate and return a list of recognized GETINFO options. */ 1691 static char * 1692 list_getinfo_options(void) 1693 { 1694 int i; 1695 smartlist_t *lines = smartlist_new(); 1696 char *ans; 1697 for (i = 0; getinfo_items[i].varname; ++i) { 1698 if (!getinfo_items[i].desc) 1699 continue; 1700 1701 smartlist_add_asprintf(lines, "%s%s -- %s\n", 1702 getinfo_items[i].varname, 1703 getinfo_items[i].is_prefix ? "*" : "", 1704 getinfo_items[i].desc); 1705 } 1706 smartlist_sort_strings(lines); 1707 1708 ans = smartlist_join_strings(lines, "", 0, NULL); 1709 SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp)); 1710 smartlist_free(lines); 1711 1712 return ans; 1713 } 1714 1715 /** Lookup the 'getinfo' entry <b>question</b>, and return 1716 * the answer in <b>*answer</b> (or NULL if key not recognized). 1717 * Return 0 if success or unrecognized, or -1 if recognized but 1718 * internal error. */ 1719 static int 1720 handle_getinfo_helper(control_connection_t *control_conn, 1721 const char *question, char **answer, 1722 const char **err_out) 1723 { 1724 int i; 1725 *answer = NULL; /* unrecognized key by default */ 1726 1727 for (i = 0; getinfo_items[i].varname; ++i) { 1728 int match; 1729 if (getinfo_items[i].is_prefix) 1730 match = !strcmpstart(question, getinfo_items[i].varname); 1731 else 1732 match = !strcmp(question, getinfo_items[i].varname); 1733 if (match) { 1734 tor_assert(getinfo_items[i].fn); 1735 return getinfo_items[i].fn(control_conn, question, answer, err_out); 1736 } 1737 } 1738 1739 return 0; /* unrecognized */ 1740 } 1741 1742 const control_cmd_syntax_t getinfo_syntax = { 1743 .max_args = UINT_MAX, 1744 }; 1745 1746 /** Called when we receive a GETINFO command. Try to fetch all requested 1747 * information, and reply with information or error message. */ 1748 int 1749 handle_control_getinfo(control_connection_t *conn, 1750 const control_cmd_args_t *args) 1751 { 1752 const smartlist_t *questions = args->args; 1753 smartlist_t *answers = smartlist_new(); 1754 smartlist_t *unrecognized = smartlist_new(); 1755 char *ans = NULL; 1756 1757 SMARTLIST_FOREACH_BEGIN(questions, const char *, q) { 1758 const char *errmsg = NULL; 1759 1760 if (handle_getinfo_helper(conn, q, &ans, &errmsg) < 0) { 1761 if (!errmsg) 1762 errmsg = "Internal error"; 1763 control_write_endreply(conn, 551, errmsg); 1764 goto done; 1765 } 1766 if (!ans) { 1767 if (errmsg) { 1768 /* use provided error message */ 1769 control_reply_add_str(unrecognized, 552, errmsg); 1770 } else { 1771 /* use default error message */ 1772 control_reply_add_printf(unrecognized, 552, 1773 "Unrecognized key \"%s\"", q); 1774 } 1775 } else { 1776 control_reply_add_one_kv(answers, 250, KV_RAW, q, ans); 1777 tor_free(ans); 1778 } 1779 } SMARTLIST_FOREACH_END(q); 1780 1781 control_reply_add_done(answers); 1782 1783 if (smartlist_len(unrecognized)) { 1784 control_write_reply_lines(conn, unrecognized); 1785 /* If there were any unrecognized queries, don't write real answers */ 1786 goto done; 1787 } 1788 1789 control_write_reply_lines(conn, answers); 1790 1791 done: 1792 control_reply_free(answers); 1793 control_reply_free(unrecognized); 1794 1795 return 0; 1796 }