control_fmt.c (11303B)
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_fmt.c 7 * \brief Formatting functions for controller data. 8 */ 9 10 #include "core/or/or.h" 11 12 #include "core/mainloop/connection.h" 13 #include "core/or/circuitbuild.h" 14 #include "core/or/circuitlist.h" 15 #include "core/or/connection_edge.h" 16 #include "feature/control/control_fmt.h" 17 #include "feature/control/control_proto.h" 18 #include "feature/nodelist/nodelist.h" 19 20 #include "core/or/cpath_build_state_st.h" 21 #include "core/or/entry_connection_st.h" 22 #include "core/or/or_connection_st.h" 23 #include "core/or/origin_circuit_st.h" 24 #include "core/or/conflux_util.h" 25 #include "core/or/socks_request_st.h" 26 #include "feature/control/control_connection_st.h" 27 28 /** Given an AP connection <b>conn</b> and a <b>len</b>-character buffer 29 * <b>buf</b>, determine the address:port combination requested on 30 * <b>conn</b>, and write it to <b>buf</b>. Return 0 on success, -1 on 31 * failure. */ 32 int 33 write_stream_target_to_buf(entry_connection_t *conn, char *buf, size_t len) 34 { 35 char buf2[256]; 36 if (conn->chosen_exit_name) 37 if (tor_snprintf(buf2, sizeof(buf2), ".%s.exit", conn->chosen_exit_name)<0) 38 return -1; 39 if (!conn->socks_request) 40 return -1; 41 if (tor_snprintf(buf, len, "%s%s%s:%d", 42 conn->socks_request->address, 43 conn->chosen_exit_name ? buf2 : "", 44 !conn->chosen_exit_name && connection_edge_is_rendezvous_stream( 45 ENTRY_TO_EDGE_CONN(conn)) ? ".onion" : "", 46 conn->socks_request->port)<0) 47 return -1; 48 return 0; 49 } 50 51 /** Figure out the best name for the target router of an OR connection 52 * <b>conn</b>, and write it into the <b>len</b>-character buffer 53 * <b>name</b>. */ 54 void 55 orconn_target_get_name(char *name, size_t len, or_connection_t *conn) 56 { 57 const node_t *node = node_get_by_id(conn->identity_digest); 58 if (node) { 59 tor_assert(len > MAX_VERBOSE_NICKNAME_LEN); 60 node_get_verbose_nickname(node, name); 61 } else if (! tor_digest_is_zero(conn->identity_digest)) { 62 name[0] = '$'; 63 base16_encode(name+1, len-1, conn->identity_digest, 64 DIGEST_LEN); 65 } else { 66 tor_snprintf(name, len, "%s:%d", 67 conn->base_.address, conn->base_.port); 68 } 69 } 70 71 /** Allocate and return a description of <b>circ</b>'s current status, 72 * including its path (if any). */ 73 char * 74 circuit_describe_status_for_controller(origin_circuit_t *circ) 75 { 76 char *rv; 77 smartlist_t *descparts = smartlist_new(); 78 79 { 80 char *vpath = circuit_list_path_for_controller(circ); 81 if (*vpath) { 82 smartlist_add(descparts, vpath); 83 } else { 84 tor_free(vpath); /* empty path; don't put an extra space in the result */ 85 } 86 } 87 88 { 89 cpath_build_state_t *build_state = circ->build_state; 90 smartlist_t *flaglist = smartlist_new(); 91 char *flaglist_joined; 92 93 if (build_state->onehop_tunnel) 94 smartlist_add(flaglist, (void *)"ONEHOP_TUNNEL"); 95 if (build_state->is_internal) 96 smartlist_add(flaglist, (void *)"IS_INTERNAL"); 97 if (build_state->need_capacity) 98 smartlist_add(flaglist, (void *)"NEED_CAPACITY"); 99 if (build_state->need_uptime) 100 smartlist_add(flaglist, (void *)"NEED_UPTIME"); 101 102 /* Only emit a BUILD_FLAGS argument if it will have a non-empty value. */ 103 if (smartlist_len(flaglist)) { 104 flaglist_joined = smartlist_join_strings(flaglist, ",", 0, NULL); 105 106 smartlist_add_asprintf(descparts, "BUILD_FLAGS=%s", flaglist_joined); 107 108 tor_free(flaglist_joined); 109 } 110 111 smartlist_free(flaglist); 112 } 113 114 smartlist_add_asprintf(descparts, "PURPOSE=%s", 115 circuit_purpose_to_controller_string(circ->base_.purpose)); 116 117 { 118 const char *hs_state = 119 circuit_purpose_to_controller_hs_state_string(circ->base_.purpose); 120 121 if (hs_state != NULL) { 122 smartlist_add_asprintf(descparts, "HS_STATE=%s", hs_state); 123 } 124 } 125 126 if (circ->hs_ident != NULL) { 127 char addr[HS_SERVICE_ADDR_LEN_BASE32 + 1]; 128 const char *onion_address; 129 hs_build_address(&circ->hs_ident->identity_pk, HS_VERSION_THREE, addr); 130 onion_address = addr; 131 smartlist_add_asprintf(descparts, "REND_QUERY=%s", onion_address); 132 } 133 134 { 135 char tbuf[ISO_TIME_USEC_LEN+1]; 136 format_iso_time_nospace_usec(tbuf, &circ->base_.timestamp_created); 137 138 smartlist_add_asprintf(descparts, "TIME_CREATED=%s", tbuf); 139 } 140 141 // Show username and/or password if available. 142 if (circ->socks_username_len > 0) { 143 char* socks_username_escaped = esc_for_log_len(circ->socks_username, 144 (size_t) circ->socks_username_len); 145 smartlist_add_asprintf(descparts, "SOCKS_USERNAME=%s", 146 socks_username_escaped); 147 tor_free(socks_username_escaped); 148 } 149 if (circ->socks_password_len > 0) { 150 char* socks_password_escaped = esc_for_log_len(circ->socks_password, 151 (size_t) circ->socks_password_len); 152 smartlist_add_asprintf(descparts, "SOCKS_PASSWORD=%s", 153 socks_password_escaped); 154 tor_free(socks_password_escaped); 155 } 156 157 /* Attach the proof-of-work solution effort, if it's nonzero. Clients set 158 * this to the effort they've chosen, services set this to a value that 159 * was provided by the client and then verified by the service. */ 160 if (circ->hs_pow_effort > 0) { 161 smartlist_add_asprintf(descparts, "HS_POW=v1,%u", circ->hs_pow_effort); 162 } 163 164 /* Add conflux id and RTT info, for accurate circuit display. The RTT is 165 * provided to indicate the primary (preferred) circuit of a set 166 * (which will have the lowest current RTT). 167 * 168 * NOTE: Because control port events can happen at arbitrary points, we 169 * must specifically check exactly what we need from the conflux object. 170 * We cannot use CIRCUIT_IS_CONFLUX() because this event may have been 171 * emitted while a set was under partial construction or teardown. */ 172 if (TO_CIRCUIT(circ)->conflux || TO_CIRCUIT(circ)->conflux_pending_nonce) { 173 const uint8_t *nonce = conflux_get_nonce(TO_CIRCUIT(circ)); 174 tor_assert(nonce); 175 176 /* The conflux nonce is an ephemeral cryptographic secret that if known in 177 * full, enables confirmation or data injection on a set by adding new legs 178 * at an exit from elsewhere. Only output half of it. */ 179 smartlist_add_asprintf(descparts, "CONFLUX_ID=%s", 180 hex_str((const char *)nonce, DIGEST256_LEN/2)); 181 182 /* If we have a conflux object that is fully linked, the circ has an RTT */ 183 if (TO_CIRCUIT(circ)->conflux && 184 TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED) { 185 uint64_t circ_rtt = conflux_get_circ_rtt(TO_CIRCUIT(circ)); 186 if (circ_rtt) { 187 smartlist_add_asprintf(descparts, "CONFLUX_RTT=%" PRIu64, circ_rtt); 188 } 189 } 190 } 191 192 rv = smartlist_join_strings(descparts, " ", 0, NULL); 193 194 SMARTLIST_FOREACH(descparts, char *, cp, tor_free(cp)); 195 smartlist_free(descparts); 196 197 return rv; 198 } 199 200 /** Allocate and return a description of <b>conn</b>'s current status. */ 201 char * 202 entry_connection_describe_status_for_controller(const entry_connection_t *conn) 203 { 204 char *rv; 205 smartlist_t *descparts = smartlist_new(); 206 207 if (conn->socks_request != NULL) { 208 // Show username and/or password if available; used by IsolateSOCKSAuth. 209 if (conn->socks_request->usernamelen > 0) { 210 char* username_escaped = esc_for_log_len(conn->socks_request->username, 211 (size_t) conn->socks_request->usernamelen); 212 smartlist_add_asprintf(descparts, "SOCKS_USERNAME=%s", 213 username_escaped); 214 tor_free(username_escaped); 215 } 216 if (conn->socks_request->passwordlen > 0) { 217 char* password_escaped = esc_for_log_len(conn->socks_request->password, 218 (size_t) conn->socks_request->passwordlen); 219 smartlist_add_asprintf(descparts, "SOCKS_PASSWORD=%s", 220 password_escaped); 221 tor_free(password_escaped); 222 } 223 224 const char *client_protocol; 225 // Show the client protocol; used by IsolateClientProtocol. 226 switch (conn->socks_request->listener_type) 227 { 228 case CONN_TYPE_AP_LISTENER: 229 switch (conn->socks_request->socks_version) 230 { 231 case 4: client_protocol = "SOCKS4"; break; 232 case 5: client_protocol = "SOCKS5"; break; 233 default: client_protocol = "UNKNOWN"; 234 } 235 break; 236 case CONN_TYPE_AP_TRANS_LISTENER: client_protocol = "TRANS"; break; 237 case CONN_TYPE_AP_NATD_LISTENER: client_protocol = "NATD"; break; 238 case CONN_TYPE_AP_DNS_LISTENER: client_protocol = "DNS"; break; 239 case CONN_TYPE_AP_HTTP_CONNECT_LISTENER: 240 client_protocol = "HTTPCONNECT"; break; 241 case CONN_TYPE_METRICS_LISTENER: 242 client_protocol = "METRICS"; break; 243 default: client_protocol = "UNKNOWN"; 244 } 245 smartlist_add_asprintf(descparts, "CLIENT_PROTOCOL=%s", 246 client_protocol); 247 } 248 249 // Show newnym epoch; used for stream isolation when NEWNYM is used. 250 smartlist_add_asprintf(descparts, "NYM_EPOCH=%u", 251 conn->nym_epoch); 252 253 // Show session group; used for stream isolation of multiple listener ports. 254 smartlist_add_asprintf(descparts, "SESSION_GROUP=%d", 255 conn->entry_cfg.session_group); 256 257 // Show isolation flags. 258 smartlist_t *isoflaglist = smartlist_new(); 259 char *isoflaglist_joined; 260 if (conn->entry_cfg.isolation_flags & ISO_DESTPORT) { 261 smartlist_add(isoflaglist, (void *)"DESTPORT"); 262 } 263 if (conn->entry_cfg.isolation_flags & ISO_DESTADDR) { 264 smartlist_add(isoflaglist, (void *)"DESTADDR"); 265 } 266 if (conn->entry_cfg.isolation_flags & ISO_SOCKSAUTH) { 267 smartlist_add(isoflaglist, (void *)"SOCKS_USERNAME"); 268 smartlist_add(isoflaglist, (void *)"SOCKS_PASSWORD"); 269 } 270 if (conn->entry_cfg.isolation_flags & ISO_CLIENTPROTO) { 271 smartlist_add(isoflaglist, (void *)"CLIENT_PROTOCOL"); 272 } 273 if (conn->entry_cfg.isolation_flags & ISO_CLIENTADDR) { 274 smartlist_add(isoflaglist, (void *)"CLIENTADDR"); 275 } 276 if (conn->entry_cfg.isolation_flags & ISO_SESSIONGRP) { 277 smartlist_add(isoflaglist, (void *)"SESSION_GROUP"); 278 } 279 if (conn->entry_cfg.isolation_flags & ISO_NYM_EPOCH) { 280 smartlist_add(isoflaglist, (void *)"NYM_EPOCH"); 281 } 282 isoflaglist_joined = smartlist_join_strings(isoflaglist, ",", 0, NULL); 283 smartlist_add_asprintf(descparts, "ISO_FIELDS=%s", isoflaglist_joined); 284 tor_free(isoflaglist_joined); 285 smartlist_free(isoflaglist); 286 287 rv = smartlist_join_strings(descparts, " ", 0, NULL); 288 289 SMARTLIST_FOREACH(descparts, char *, cp, tor_free(cp)); 290 smartlist_free(descparts); 291 292 return rv; 293 } 294 295 /** Return a longname the node whose identity is <b>id_digest</b>. If 296 * node_get_by_id() returns NULL, base 16 encoding of <b>id_digest</b> is 297 * returned instead. 298 * 299 * This function is not thread-safe. Each call to this function invalidates 300 * previous values returned by this function. 301 */ 302 MOCK_IMPL(const char *, 303 node_describe_longname_by_id,(const char *id_digest)) 304 { 305 static char longname[MAX_VERBOSE_NICKNAME_LEN+1]; 306 node_get_verbose_nickname_by_id(id_digest, longname); 307 return longname; 308 }