📄 control.c
字号:
} else if (!strcmp(question, "desc/all-recent")) {
routerlist_t *routerlist = router_get_routerlist();
smartlist_t *sl = smartlist_create();
if (routerlist && routerlist->routers) {
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, ri,
{
const char *body = signed_descriptor_get_body(&ri->cache_info);
if (body)
smartlist_add(sl,
tor_strndup(body, ri->cache_info.signed_descriptor_len));
});
}
*answer = smartlist_join_strings(sl, "", 0, NULL);
SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
smartlist_free(sl);
} else if (!strcmp(question, "desc/all-recent-extrainfo-hack")) {
/* XXXX Remove this once Torstat asks for extrainfos. */
routerlist_t *routerlist = router_get_routerlist();
smartlist_t *sl = smartlist_create();
if (routerlist && routerlist->routers) {
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, ri,
{
const char *body = signed_descriptor_get_body(&ri->cache_info);
signed_descriptor_t *ei = extrainfo_get_by_descriptor_digest(
ri->cache_info.extra_info_digest);
if (ei && body) {
smartlist_add(sl, munge_extrainfo_into_routerinfo(body,
&ri->cache_info, ei));
} else if (body) {
smartlist_add(sl,
tor_strndup(body, ri->cache_info.signed_descriptor_len));
}
});
}
*answer = smartlist_join_strings(sl, "", 0, NULL);
SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
smartlist_free(sl);
} else if (!strcmpstart(question, "desc-annotations/id/")) {
routerinfo_t *ri = router_get_by_hexdigest(question+
strlen("desc-annotations/id/"));
if (ri) {
const char *annotations =
signed_descriptor_get_annotations(&ri->cache_info);
if (annotations)
*answer = tor_strndup(annotations,
ri->cache_info.annotations_len);
}
} else if (!strcmpstart(question, "dir/server/")) {
size_t answer_len = 0, url_len = strlen(question)+2;
char *url = tor_malloc(url_len);
smartlist_t *descs = smartlist_create();
const char *msg;
int res;
char *cp;
tor_snprintf(url, url_len, "/tor/%s", question+4);
res = dirserv_get_routerdescs(descs, url, &msg);
if (res) {
log_warn(LD_CONTROL, "getinfo '%s': %s", question, msg);
smartlist_free(descs);
return -1;
}
SMARTLIST_FOREACH(descs, signed_descriptor_t *, sd,
answer_len += sd->signed_descriptor_len);
cp = *answer = tor_malloc(answer_len+1);
SMARTLIST_FOREACH(descs, signed_descriptor_t *, sd,
{
memcpy(cp, signed_descriptor_get_body(sd),
sd->signed_descriptor_len);
cp += sd->signed_descriptor_len;
});
*cp = '\0';
tor_free(url);
smartlist_free(descs);
} else if (!strcmpstart(question, "dir/status/")) {
if (directory_permits_controller_requests(get_options())) {
size_t len=0;
char *cp;
smartlist_t *status_list = smartlist_create();
dirserv_get_networkstatus_v2(status_list,
question+strlen("dir/status/"));
SMARTLIST_FOREACH(status_list, cached_dir_t *, d, len += d->dir_len);
cp = *answer = tor_malloc(len+1);
SMARTLIST_FOREACH(status_list, cached_dir_t *, d, {
memcpy(cp, d->dir, d->dir_len);
cp += d->dir_len;
});
*cp = '\0';
smartlist_free(status_list);
} else {
smartlist_t *fp_list = smartlist_create();
smartlist_t *status_list = smartlist_create();
dirserv_get_networkstatus_v2_fingerprints(
fp_list, question+strlen("dir/status/"));
SMARTLIST_FOREACH(fp_list, const char *, fp, {
char *s;
char *fname = networkstatus_get_cache_filename(fp);
s = read_file_to_str(fname, 0, NULL);
if (s)
smartlist_add(status_list, s);
tor_free(fname);
});
SMARTLIST_FOREACH(fp_list, char *, fp, tor_free(fp));
smartlist_free(fp_list);
*answer = smartlist_join_strings(status_list, "", 0, NULL);
SMARTLIST_FOREACH(status_list, char *, s, tor_free(s));
smartlist_free(status_list);
}
} else if (!strcmp(question, "network-status")) {
routerlist_t *routerlist = router_get_routerlist();
int verbose = control_conn->use_long_names;
if (!routerlist || !routerlist->routers ||
list_server_status_v1(routerlist->routers, answer,
verbose ? 2 : 1) < 0) {
return -1;
}
} else if (!strcmpstart(question, "extra-info/digest/")) {
question += strlen("extra-info/digest/");
if (strlen(question) == HEX_DIGEST_LEN) {
char d[DIGEST_LEN];
signed_descriptor_t *sd = NULL;
if (base16_decode(d, sizeof(d), question, strlen(question))==0) {
/* XXXX this test should move into extrainfo_get_by_descriptor_digest,
* but I don't want to risk affecting other parts of the code,
* especially since the rules for using our own extrainfo (including
* when it might be freed) are different from those for using one
* we have downloaded. */
if (router_extrainfo_digest_is_me(d))
sd = &(router_get_my_extrainfo()->cache_info);
else
sd = extrainfo_get_by_descriptor_digest(d);
}
if (sd) {
const char *body = signed_descriptor_get_body(sd);
if (body)
*answer = tor_strndup(body, sd->signed_descriptor_len);
}
}
}
return 0;
}
/** Implementation helper for GETINFO: knows how to generate summaries of the
* current states of things we send events about. */
static int
getinfo_helper_events(control_connection_t *control_conn,
const char *question, char **answer)
{
if (!strcmp(question, "circuit-status")) {
circuit_t *circ;
smartlist_t *status = smartlist_create();
for (circ = _circuit_get_global_list(); circ; circ = circ->next) {
char *s, *path;
size_t slen;
const char *state;
if (! CIRCUIT_IS_ORIGIN(circ) || circ->marked_for_close)
continue;
if (control_conn->use_long_names)
path = circuit_list_path_for_controller(TO_ORIGIN_CIRCUIT(circ));
else
path = circuit_list_path(TO_ORIGIN_CIRCUIT(circ),0);
if (circ->state == CIRCUIT_STATE_OPEN)
state = "BUILT";
else if (strlen(path))
state = "EXTENDED";
else
state = "LAUNCHED";
slen = strlen(path)+strlen(state)+20;
s = tor_malloc(slen+1);
tor_snprintf(s, slen, "%lu %s%s%s",
(unsigned long)TO_ORIGIN_CIRCUIT(circ)->global_identifier,
state, *path ? " " : "", path);
smartlist_add(status, s);
tor_free(path);
}
*answer = smartlist_join_strings(status, "\r\n", 0, NULL);
SMARTLIST_FOREACH(status, char *, cp, tor_free(cp));
smartlist_free(status);
} else if (!strcmp(question, "stream-status")) {
smartlist_t *conns = get_connection_array();
smartlist_t *status = smartlist_create();
char buf[256];
SMARTLIST_FOREACH(conns, connection_t *, base_conn,
{
const char *state;
edge_connection_t *conn;
char *s;
size_t slen;
circuit_t *circ;
origin_circuit_t *origin_circ = NULL;
if (base_conn->type != CONN_TYPE_AP ||
base_conn->marked_for_close ||
base_conn->state == AP_CONN_STATE_SOCKS_WAIT ||
base_conn->state == AP_CONN_STATE_NATD_WAIT)
continue;
conn = TO_EDGE_CONN(base_conn);
switch (conn->_base.state)
{
case AP_CONN_STATE_CONTROLLER_WAIT:
case AP_CONN_STATE_CIRCUIT_WAIT:
if (conn->socks_request &&
SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command))
state = "NEWRESOLVE";
else
state = "NEW";
break;
case AP_CONN_STATE_RENDDESC_WAIT:
case AP_CONN_STATE_CONNECT_WAIT:
state = "SENTCONNECT"; break;
case AP_CONN_STATE_RESOLVE_WAIT:
state = "SENTRESOLVE"; break;
case AP_CONN_STATE_OPEN:
state = "SUCCEEDED"; break;
default:
log_warn(LD_BUG, "Asked for stream in unknown state %d",
conn->_base.state);
continue;
}
circ = circuit_get_by_edge_conn(conn);
if (circ && CIRCUIT_IS_ORIGIN(circ))
origin_circ = TO_ORIGIN_CIRCUIT(circ);
write_stream_target_to_buf(conn, buf, sizeof(buf));
slen = strlen(buf)+strlen(state)+32;
s = tor_malloc(slen+1);
tor_snprintf(s, slen, "%lu %s %lu %s",
(unsigned long) conn->global_identifier,state,
origin_circ?
(unsigned long)origin_circ->global_identifier : 0ul,
buf);
smartlist_add(status, s);
});
*answer = smartlist_join_strings(status, "\r\n", 0, NULL);
SMARTLIST_FOREACH(status, char *, cp, tor_free(cp));
smartlist_free(status);
} else if (!strcmp(question, "orconn-status")) {
smartlist_t *conns = get_connection_array();
smartlist_t *status = smartlist_create();
SMARTLIST_FOREACH(conns, connection_t *, base_conn,
{
const char *state;
char *s;
char name[128];
size_t slen;
or_connection_t *conn;
if (base_conn->type != CONN_TYPE_OR || base_conn->marked_for_close)
continue;
conn = TO_OR_CONN(base_conn);
if (conn->_base.state == OR_CONN_STATE_OPEN)
state = "CONNECTED";
else if (conn->nickname)
state = "LAUNCHED";
else
state = "NEW";
orconn_target_get_name(control_conn->use_long_names, name, sizeof(name),
conn);
slen = strlen(name)+strlen(state)+2;
s = tor_malloc(slen+1);
tor_snprintf(s, slen, "%s %s", name, state);
smartlist_add(status, s);
});
*answer = smartlist_join_strings(status, "\r\n", 0, NULL);
SMARTLIST_FOREACH(status, char *, cp, tor_free(cp));
smartlist_free(status);
} else if (!strcmpstart(question, "addr-mappings/") ||
!strcmpstart(question, "address-mappings/")) {
/* XXXX021 Warn about deprecated addr-mappings variant. */
time_t min_e, max_e;
smartlist_t *mappings;
int want_expiry = !strcmpstart(question, "address-mappings/");
question += strlen(want_expiry ? "address-mappings/"
: "addr-mappings/");
if (!strcmp(question, "all")) {
min_e = 0; max_e = TIME_MAX;
} else if (!strcmp(question, "cache")) {
min_e = 2; max_e = TIME_MAX;
} else if (!strcmp(question, "config")) {
min_e = 0; max_e = 0;
} else if (!strcmp(question, "control")) {
min_e = 1; max_e = 1;
} else {
return 0;
}
mappings = smartlist_create();
addressmap_get_mappings(mappings, min_e, max_e, want_expiry);
*answer = smartlist_join_strings(mappings, "\r\n", 0, NULL);
SMARTLIST_FOREACH(mappings, char *, cp, tor_free(cp));
smartlist_free(mappings);
} else if (!strcmpstart(question, "status/")) {
/* Note that status/ is not a catch-all for events; there's only supposed
* to be a status GETINFO if there's a corresponding STATUS event. */
if (!strcmp(question, "status/circuit-established")) {
*answer = tor_strdup(has_completed_circuit ? "1" : "0");
} else if (!strcmp(question, "status/enough-dir-info")) {
*answer = tor_strdup(router_have_minimum_dir_info() ? "1" : "0");
} else if (!strcmp(question, "status/good-server-descriptor")) {
*answer = tor_strdup(directories_have_accepted_server_descriptor()
? "1" : "0");
} else if (!strcmp(question, "status/reachability-succeeded/or")) {
*answer = tor_strdup(check_whether_orport_reachable() ? "1" : "0");
} else if (!strcmp(question, "status/reachability-succeeded/dir")) {
*answer = tor_strdup(check_whether_dirport_reachable() ? "1" : "0");
} else if (!strcmp(question, "status/reachability-succeeded")) {
*answer = tor_malloc(16);
tor_snprintf(*answer, 16, "OR=%d DIR=%d",
check_whether_orport_reachable() ? 1 : 0,
check_whether_dirport_reachable() ? 1 : 0);
} else if (!strcmpstart(question, "status/version/")) {
int is_server = server_mode(get_options());
networkstatus_t *c = networkstatus_get_latest_consensus();
version_status_t status;
const char *recommended;
if (c) {
recommended = is_server ? c->server_versions : c->client_versions;
status = tor_version_is_obsolete(VERSION, recommended);
} else {
recommended = "?";
status = VS_UNKNOWN;
}
if (!strcmp(question, "status/version/recommended")) {
*answer = tor_strdup(recommended);
return 0;
}
if (!strcmp(question, "status/version/current")) {
switch (status)
{
case VS_RECOMMENDED: *answer = tor_strdup("recommended"); break;
case VS_OLD: *answer = tor_strdup("obsolete"); break;
case VS_NEW: *answer = tor_strdup("new"); break;
case VS_NEW_IN_SERIES: *answer = tor_strdup("new in series"); break;
case VS_UNRECOMMENDED: *answer = tor_strdup("unrecommended"); break;
case VS_EMPTY: *answer = tor_strdup("none recommended"); break;
case VS_UNKNOWN: *answer = tor_strdup("unknown"); break;
default: tor_fragile_assert();
}
} else if (!strcmp(question, "status/version/num-versioning") ||
!strcmp(question, "status/version/num-concurring")) {
char s[33];
tor_snprintf(s, sizeof(s), "%d", get_n_authorities(V3_AUTHORITY));
*answer = tor_strdup(s);
log_warn(LD_GENERAL, "%s is deprecated; it no longer gives useful "
"information", question);
}
} else {
return 0;
}
}
return 0;
}
/** Callback function for GETINFO: on a given control connection, try to
* answer the question <b>q</b> and store the newly-allocated answer in
* *<b>a</b>. If there's no answer, or an error occurs, just don't set
* <b>a</b>. Return 0.
*/
typedef int (*getinfo_helper_t)(control_connection_t *,
const char *q, char **a);
/** A single item for the GETINFO question-to-answer-function table. */
typedef struct getinfo_item_t {
const char *varname; /**< The value (or prefix) of the question. */
getinfo_helper_t fn; /**< The function that knows the answer:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -