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 : }
|