Control port STREAM XON/XOFF status event notification
[tor.git] / src / feature / control / control_fmt.c
blobcc8686818a488f5c361348f522ac9cd7fe993943
1 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
2 * Copyright (c) 2007-2021, The Tor Project, Inc. */
3 /* See LICENSE for licensing information */
5 /**
6 * \file control_fmt.c
7 * \brief Formatting functions for controller data.
8 */
10 #include "core/or/or.h"
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"
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/socks_request_st.h"
25 #include "feature/control/control_connection_st.h"
27 /** Given an AP connection <b>conn</b> and a <b>len</b>-character buffer
28 * <b>buf</b>, determine the address:port combination requested on
29 * <b>conn</b>, and write it to <b>buf</b>. Return 0 on success, -1 on
30 * failure. */
31 int
32 write_stream_target_to_buf(entry_connection_t *conn, char *buf, size_t len)
34 char buf2[256];
35 if (conn->chosen_exit_name)
36 if (tor_snprintf(buf2, sizeof(buf2), ".%s.exit", conn->chosen_exit_name)<0)
37 return -1;
38 if (!conn->socks_request)
39 return -1;
40 if (tor_snprintf(buf, len, "%s%s%s:%d",
41 conn->socks_request->address,
42 conn->chosen_exit_name ? buf2 : "",
43 !conn->chosen_exit_name && connection_edge_is_rendezvous_stream(
44 ENTRY_TO_EDGE_CONN(conn)) ? ".onion" : "",
45 conn->socks_request->port)<0)
46 return -1;
47 return 0;
50 /** Figure out the best name for the target router of an OR connection
51 * <b>conn</b>, and write it into the <b>len</b>-character buffer
52 * <b>name</b>. */
53 void
54 orconn_target_get_name(char *name, size_t len, or_connection_t *conn)
56 const node_t *node = node_get_by_id(conn->identity_digest);
57 if (node) {
58 tor_assert(len > MAX_VERBOSE_NICKNAME_LEN);
59 node_get_verbose_nickname(node, name);
60 } else if (! tor_digest_is_zero(conn->identity_digest)) {
61 name[0] = '$';
62 base16_encode(name+1, len-1, conn->identity_digest,
63 DIGEST_LEN);
64 } else {
65 tor_snprintf(name, len, "%s:%d",
66 conn->base_.address, conn->base_.port);
70 /** Allocate and return a description of <b>circ</b>'s current status,
71 * including its path (if any). */
72 char *
73 circuit_describe_status_for_controller(origin_circuit_t *circ)
75 char *rv;
76 smartlist_t *descparts = smartlist_new();
79 char *vpath = circuit_list_path_for_controller(circ);
80 if (*vpath) {
81 smartlist_add(descparts, vpath);
82 } else {
83 tor_free(vpath); /* empty path; don't put an extra space in the result */
88 cpath_build_state_t *build_state = circ->build_state;
89 smartlist_t *flaglist = smartlist_new();
90 char *flaglist_joined;
92 if (build_state->onehop_tunnel)
93 smartlist_add(flaglist, (void *)"ONEHOP_TUNNEL");
94 if (build_state->is_internal)
95 smartlist_add(flaglist, (void *)"IS_INTERNAL");
96 if (build_state->need_capacity)
97 smartlist_add(flaglist, (void *)"NEED_CAPACITY");
98 if (build_state->need_uptime)
99 smartlist_add(flaglist, (void *)"NEED_UPTIME");
101 /* Only emit a BUILD_FLAGS argument if it will have a non-empty value. */
102 if (smartlist_len(flaglist)) {
103 flaglist_joined = smartlist_join_strings(flaglist, ",", 0, NULL);
105 smartlist_add_asprintf(descparts, "BUILD_FLAGS=%s", flaglist_joined);
107 tor_free(flaglist_joined);
110 smartlist_free(flaglist);
113 smartlist_add_asprintf(descparts, "PURPOSE=%s",
114 circuit_purpose_to_controller_string(circ->base_.purpose));
117 const char *hs_state =
118 circuit_purpose_to_controller_hs_state_string(circ->base_.purpose);
120 if (hs_state != NULL) {
121 smartlist_add_asprintf(descparts, "HS_STATE=%s", hs_state);
125 if (circ->hs_ident != NULL) {
126 char addr[HS_SERVICE_ADDR_LEN_BASE32 + 1];
127 const char *onion_address;
128 hs_build_address(&circ->hs_ident->identity_pk, HS_VERSION_THREE, addr);
129 onion_address = addr;
130 smartlist_add_asprintf(descparts, "REND_QUERY=%s", onion_address);
134 char tbuf[ISO_TIME_USEC_LEN+1];
135 format_iso_time_nospace_usec(tbuf, &circ->base_.timestamp_created);
137 smartlist_add_asprintf(descparts, "TIME_CREATED=%s", tbuf);
140 // Show username and/or password if available.
141 if (circ->socks_username_len > 0) {
142 char* socks_username_escaped = esc_for_log_len(circ->socks_username,
143 (size_t) circ->socks_username_len);
144 smartlist_add_asprintf(descparts, "SOCKS_USERNAME=%s",
145 socks_username_escaped);
146 tor_free(socks_username_escaped);
148 if (circ->socks_password_len > 0) {
149 char* socks_password_escaped = esc_for_log_len(circ->socks_password,
150 (size_t) circ->socks_password_len);
151 smartlist_add_asprintf(descparts, "SOCKS_PASSWORD=%s",
152 socks_password_escaped);
153 tor_free(socks_password_escaped);
156 rv = smartlist_join_strings(descparts, " ", 0, NULL);
158 SMARTLIST_FOREACH(descparts, char *, cp, tor_free(cp));
159 smartlist_free(descparts);
161 return rv;
164 /** Allocate and return a description of <b>conn</b>'s current status. */
165 char *
166 entry_connection_describe_status_for_controller(const entry_connection_t *conn)
168 char *rv;
169 smartlist_t *descparts = smartlist_new();
171 if (conn->socks_request != NULL) {
172 // Show username and/or password if available; used by IsolateSOCKSAuth.
173 if (conn->socks_request->usernamelen > 0) {
174 char* username_escaped = esc_for_log_len(conn->socks_request->username,
175 (size_t) conn->socks_request->usernamelen);
176 smartlist_add_asprintf(descparts, "SOCKS_USERNAME=%s",
177 username_escaped);
178 tor_free(username_escaped);
180 if (conn->socks_request->passwordlen > 0) {
181 char* password_escaped = esc_for_log_len(conn->socks_request->password,
182 (size_t) conn->socks_request->passwordlen);
183 smartlist_add_asprintf(descparts, "SOCKS_PASSWORD=%s",
184 password_escaped);
185 tor_free(password_escaped);
188 const char *client_protocol;
189 // Show the client protocol; used by IsolateClientProtocol.
190 switch (conn->socks_request->listener_type)
192 case CONN_TYPE_AP_LISTENER:
193 switch (conn->socks_request->socks_version)
195 case 4: client_protocol = "SOCKS4"; break;
196 case 5: client_protocol = "SOCKS5"; break;
197 default: client_protocol = "UNKNOWN";
199 break;
200 case CONN_TYPE_AP_TRANS_LISTENER: client_protocol = "TRANS"; break;
201 case CONN_TYPE_AP_NATD_LISTENER: client_protocol = "NATD"; break;
202 case CONN_TYPE_AP_DNS_LISTENER: client_protocol = "DNS"; break;
203 case CONN_TYPE_AP_HTTP_CONNECT_LISTENER:
204 client_protocol = "HTTPCONNECT"; break;
205 case CONN_TYPE_METRICS_LISTENER:
206 client_protocol = "METRICS"; break;
207 default: client_protocol = "UNKNOWN";
209 smartlist_add_asprintf(descparts, "CLIENT_PROTOCOL=%s",
210 client_protocol);
213 // Show newnym epoch; used for stream isolation when NEWNYM is used.
214 smartlist_add_asprintf(descparts, "NYM_EPOCH=%u",
215 conn->nym_epoch);
217 // Show session group; used for stream isolation of multiple listener ports.
218 smartlist_add_asprintf(descparts, "SESSION_GROUP=%d",
219 conn->entry_cfg.session_group);
221 // Show isolation flags.
222 smartlist_t *isoflaglist = smartlist_new();
223 char *isoflaglist_joined;
224 if (conn->entry_cfg.isolation_flags & ISO_DESTPORT) {
225 smartlist_add(isoflaglist, (void *)"DESTPORT");
227 if (conn->entry_cfg.isolation_flags & ISO_DESTADDR) {
228 smartlist_add(isoflaglist, (void *)"DESTADDR");
230 if (conn->entry_cfg.isolation_flags & ISO_SOCKSAUTH) {
231 smartlist_add(isoflaglist, (void *)"SOCKS_USERNAME");
232 smartlist_add(isoflaglist, (void *)"SOCKS_PASSWORD");
234 if (conn->entry_cfg.isolation_flags & ISO_CLIENTPROTO) {
235 smartlist_add(isoflaglist, (void *)"CLIENT_PROTOCOL");
237 if (conn->entry_cfg.isolation_flags & ISO_CLIENTADDR) {
238 smartlist_add(isoflaglist, (void *)"CLIENTADDR");
240 if (conn->entry_cfg.isolation_flags & ISO_SESSIONGRP) {
241 smartlist_add(isoflaglist, (void *)"SESSION_GROUP");
243 if (conn->entry_cfg.isolation_flags & ISO_NYM_EPOCH) {
244 smartlist_add(isoflaglist, (void *)"NYM_EPOCH");
246 isoflaglist_joined = smartlist_join_strings(isoflaglist, ",", 0, NULL);
247 smartlist_add_asprintf(descparts, "ISO_FIELDS=%s", isoflaglist_joined);
248 tor_free(isoflaglist_joined);
249 smartlist_free(isoflaglist);
251 rv = smartlist_join_strings(descparts, " ", 0, NULL);
253 SMARTLIST_FOREACH(descparts, char *, cp, tor_free(cp));
254 smartlist_free(descparts);
256 return rv;
259 /** Return a longname the node whose identity is <b>id_digest</b>. If
260 * node_get_by_id() returns NULL, base 16 encoding of <b>id_digest</b> is
261 * returned instead.
263 * This function is not thread-safe. Each call to this function invalidates
264 * previous values returned by this function.
266 MOCK_IMPL(const char *,
267 node_describe_longname_by_id,(const char *id_digest))
269 static char longname[MAX_VERBOSE_NICKNAME_LEN+1];
270 node_get_verbose_nickname_by_id(id_digest, longname);
271 return longname;