1 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
2 * Copyright (c) 2007-2021, The Tor Project, Inc. */
3 /* See LICENSE for licensing information */
7 * \brief Formatting functions for controller data.
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
32 write_stream_target_to_buf(entry_connection_t
*conn
, char *buf
, size_t len
)
35 if (conn
->chosen_exit_name
)
36 if (tor_snprintf(buf2
, sizeof(buf2
), ".%s.exit", conn
->chosen_exit_name
)<0)
38 if (!conn
->socks_request
)
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)
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
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
);
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
)) {
62 base16_encode(name
+1, len
-1, conn
->identity_digest
,
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). */
73 circuit_describe_status_for_controller(origin_circuit_t
*circ
)
76 smartlist_t
*descparts
= smartlist_new();
79 char *vpath
= circuit_list_path_for_controller(circ
);
81 smartlist_add(descparts
, vpath
);
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 /* Attach the proof-of-work solution effort, if it's nonzero. Clients set
157 * this to the effort they've chosen, services set this to a value that
158 * was provided by the client and then verified by the service. */
159 if (circ
->hs_pow_effort
> 0) {
160 smartlist_add_asprintf(descparts
, "HS_POW=v1,%u", circ
->hs_pow_effort
);
163 rv
= smartlist_join_strings(descparts
, " ", 0, NULL
);
165 SMARTLIST_FOREACH(descparts
, char *, cp
, tor_free(cp
));
166 smartlist_free(descparts
);
171 /** Allocate and return a description of <b>conn</b>'s current status. */
173 entry_connection_describe_status_for_controller(const entry_connection_t
*conn
)
176 smartlist_t
*descparts
= smartlist_new();
178 if (conn
->socks_request
!= NULL
) {
179 // Show username and/or password if available; used by IsolateSOCKSAuth.
180 if (conn
->socks_request
->usernamelen
> 0) {
181 char* username_escaped
= esc_for_log_len(conn
->socks_request
->username
,
182 (size_t) conn
->socks_request
->usernamelen
);
183 smartlist_add_asprintf(descparts
, "SOCKS_USERNAME=%s",
185 tor_free(username_escaped
);
187 if (conn
->socks_request
->passwordlen
> 0) {
188 char* password_escaped
= esc_for_log_len(conn
->socks_request
->password
,
189 (size_t) conn
->socks_request
->passwordlen
);
190 smartlist_add_asprintf(descparts
, "SOCKS_PASSWORD=%s",
192 tor_free(password_escaped
);
195 const char *client_protocol
;
196 // Show the client protocol; used by IsolateClientProtocol.
197 switch (conn
->socks_request
->listener_type
)
199 case CONN_TYPE_AP_LISTENER
:
200 switch (conn
->socks_request
->socks_version
)
202 case 4: client_protocol
= "SOCKS4"; break;
203 case 5: client_protocol
= "SOCKS5"; break;
204 default: client_protocol
= "UNKNOWN";
207 case CONN_TYPE_AP_TRANS_LISTENER
: client_protocol
= "TRANS"; break;
208 case CONN_TYPE_AP_NATD_LISTENER
: client_protocol
= "NATD"; break;
209 case CONN_TYPE_AP_DNS_LISTENER
: client_protocol
= "DNS"; break;
210 case CONN_TYPE_AP_HTTP_CONNECT_LISTENER
:
211 client_protocol
= "HTTPCONNECT"; break;
212 case CONN_TYPE_METRICS_LISTENER
:
213 client_protocol
= "METRICS"; break;
214 default: client_protocol
= "UNKNOWN";
216 smartlist_add_asprintf(descparts
, "CLIENT_PROTOCOL=%s",
220 // Show newnym epoch; used for stream isolation when NEWNYM is used.
221 smartlist_add_asprintf(descparts
, "NYM_EPOCH=%u",
224 // Show session group; used for stream isolation of multiple listener ports.
225 smartlist_add_asprintf(descparts
, "SESSION_GROUP=%d",
226 conn
->entry_cfg
.session_group
);
228 // Show isolation flags.
229 smartlist_t
*isoflaglist
= smartlist_new();
230 char *isoflaglist_joined
;
231 if (conn
->entry_cfg
.isolation_flags
& ISO_DESTPORT
) {
232 smartlist_add(isoflaglist
, (void *)"DESTPORT");
234 if (conn
->entry_cfg
.isolation_flags
& ISO_DESTADDR
) {
235 smartlist_add(isoflaglist
, (void *)"DESTADDR");
237 if (conn
->entry_cfg
.isolation_flags
& ISO_SOCKSAUTH
) {
238 smartlist_add(isoflaglist
, (void *)"SOCKS_USERNAME");
239 smartlist_add(isoflaglist
, (void *)"SOCKS_PASSWORD");
241 if (conn
->entry_cfg
.isolation_flags
& ISO_CLIENTPROTO
) {
242 smartlist_add(isoflaglist
, (void *)"CLIENT_PROTOCOL");
244 if (conn
->entry_cfg
.isolation_flags
& ISO_CLIENTADDR
) {
245 smartlist_add(isoflaglist
, (void *)"CLIENTADDR");
247 if (conn
->entry_cfg
.isolation_flags
& ISO_SESSIONGRP
) {
248 smartlist_add(isoflaglist
, (void *)"SESSION_GROUP");
250 if (conn
->entry_cfg
.isolation_flags
& ISO_NYM_EPOCH
) {
251 smartlist_add(isoflaglist
, (void *)"NYM_EPOCH");
253 isoflaglist_joined
= smartlist_join_strings(isoflaglist
, ",", 0, NULL
);
254 smartlist_add_asprintf(descparts
, "ISO_FIELDS=%s", isoflaglist_joined
);
255 tor_free(isoflaglist_joined
);
256 smartlist_free(isoflaglist
);
258 rv
= smartlist_join_strings(descparts
, " ", 0, NULL
);
260 SMARTLIST_FOREACH(descparts
, char *, cp
, tor_free(cp
));
261 smartlist_free(descparts
);
266 /** Return a longname the node whose identity is <b>id_digest</b>. If
267 * node_get_by_id() returns NULL, base 16 encoding of <b>id_digest</b> is
270 * This function is not thread-safe. Each call to this function invalidates
271 * previous values returned by this function.
273 MOCK_IMPL(const char *,
274 node_describe_longname_by_id
,(const char *id_digest
))
276 static char longname
[MAX_VERBOSE_NICKNAME_LEN
+1];
277 node_get_verbose_nickname_by_id(id_digest
, longname
);