LCOV - code coverage report
Current view: top level - feature/control - control_getinfo.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 253 839 30.2 %
Date: 2021-11-24 03:28:48 Functions: 12 22 54.5 %

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

Generated by: LCOV version 1.14