1 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
2 * Copyright (c) 2007-2021, The Tor Project, Inc. */
3 /* See LICENSE for licensing information */
6 * \file control_proto.c
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_proto.h"
17 #include "feature/nodelist/nodelist.h"
19 #include "core/or/cpath_build_state_st.h"
20 #include "core/or/entry_connection_st.h"
21 #include "core/or/or_connection_st.h"
22 #include "core/or/origin_circuit_st.h"
23 #include "core/or/socks_request_st.h"
24 #include "feature/control/control_connection_st.h"
25 #include "lib/container/smartlist.h"
26 #include "lib/encoding/kvline.h"
28 /** Append a NUL-terminated string <b>s</b> to the end of
29 * <b>conn</b>-\>outbuf.
32 connection_write_str_to_buf(const char *s
, control_connection_t
*conn
)
34 size_t len
= strlen(s
);
35 connection_buf_add(s
, len
, TO_CONN(conn
));
38 /** Acts like sprintf, but writes its formatted string to the end of
39 * <b>conn</b>-\>outbuf. */
41 connection_printf_to_buf(control_connection_t
*conn
, const char *format
, ...)
48 len
= tor_vasprintf(&buf
, format
, ap
);
52 log_err(LD_BUG
, "Unable to format string for controller.");
56 connection_buf_add(buf
, (size_t)len
, TO_CONN(conn
));
61 /** Given a <b>len</b>-character string in <b>data</b>, made of lines
62 * terminated by CRLF, allocate a new string in *<b>out</b>, and copy the
63 * contents of <b>data</b> into *<b>out</b>, adding a period before any period
64 * that appears at the start of a line, and adding a period-CRLF line at
65 * the end. Replace all LF characters sequences with CRLF. Return the number
66 * of bytes in *<b>out</b>.
68 * This corresponds to CmdData in control-spec.txt.
71 write_escaped_data(const char *data
, size_t len
, char **out
)
73 tor_assert(len
< SIZE_MAX
- 9);
74 size_t sz_out
= len
+8+1;
76 const char *start
= data
, *end
;
79 for (i
=0; i
< len
; ++i
) {
80 if (data
[i
] == '\n') {
81 sz_out
+= 2; /* Maybe add a CR; maybe add a dot. */
82 if (sz_out
>= SIZE_T_CEILING
) {
83 log_warn(LD_BUG
, "Input to write_escaped_data was too long");
84 *out
= tor_strdup(".\r\n");
89 *out
= outp
= tor_malloc(sz_out
);
94 if (data
> start
&& data
[-1] != '\r')
97 } else if (*data
== '.') {
107 if (outp
< *out
+2 || fast_memcmp(outp
-2, "\r\n", 2)) {
114 *outp
= '\0'; /* NUL-terminate just in case. */
115 tor_assert(outp
>= *out
);
116 tor_assert((size_t)(outp
- *out
) <= sz_out
);
120 /** Given a <b>len</b>-character string in <b>data</b>, made of lines
121 * terminated by CRLF, allocate a new string in *<b>out</b>, and copy
122 * the contents of <b>data</b> into *<b>out</b>, removing any period
123 * that appears at the start of a line, and replacing all CRLF sequences
124 * with LF. Return the number of
125 * bytes in *<b>out</b>.
127 * This corresponds to CmdData in control-spec.txt.
130 read_escaped_data(const char *data
, size_t len
, char **out
)
136 *out
= outp
= tor_malloc(len
+1);
141 /* we're at the start of a line. */
144 next
= memchr(data
, '\n', end
-data
);
146 size_t n_to_copy
= next
-data
;
147 /* Don't copy a CR that precedes this LF. */
148 if (n_to_copy
&& *(next
-1) == '\r')
150 memcpy(outp
, data
, n_to_copy
);
152 data
= next
+1; /* This will point at the start of the next line,
153 * or the end of the string, or a period. */
155 memcpy(outp
, data
, end
-data
);
167 /** Send a "DONE" message down the control connection <b>conn</b>. */
169 send_control_done(control_connection_t
*conn
)
171 control_write_endreply(conn
, 250, "OK");
174 /** Write a reply to the control channel.
176 * @param conn control connection
177 * @param code numeric result code
178 * @param c separator character, usually ' ', '-', or '+'
179 * @param s string reply content
182 control_write_reply
, (control_connection_t
*conn
, int code
, int c
,
185 connection_printf_to_buf(conn
, "%03d%c%s\r\n", code
, c
, s
);
188 /** Write a formatted reply to the control channel.
190 * @param conn control connection
191 * @param code numeric result code
192 * @param c separator character, usually ' ', '-', or '+'
193 * @param fmt format string
194 * @param ap va_list from caller
197 control_vprintf_reply(control_connection_t
*conn
, int code
, int c
,
198 const char *fmt
, va_list ap
)
203 len
= tor_vasprintf(&buf
, fmt
, ap
);
205 log_err(LD_BUG
, "Unable to format string for controller.");
208 control_write_reply(conn
, code
, c
, buf
);
212 /** Write an EndReplyLine */
214 control_write_endreply(control_connection_t
*conn
, int code
, const char *s
)
216 control_write_reply(conn
, code
, ' ', s
);
219 /** Write a formatted EndReplyLine */
221 control_printf_endreply(control_connection_t
*conn
, int code
,
222 const char *fmt
, ...)
227 control_vprintf_reply(conn
, code
, ' ', fmt
, ap
);
231 /** Write a MidReplyLine */
233 control_write_midreply(control_connection_t
*conn
, int code
, const char *s
)
235 control_write_reply(conn
, code
, '-', s
);
238 /** Write a formatted MidReplyLine */
240 control_printf_midreply(control_connection_t
*conn
, int code
, const char *fmt
,
246 control_vprintf_reply(conn
, code
, '-', fmt
, ap
);
250 /** Write a DataReplyLine */
252 control_write_datareply(control_connection_t
*conn
, int code
, const char *s
)
254 control_write_reply(conn
, code
, '+', s
);
257 /** Write a formatted DataReplyLine */
259 control_printf_datareply(control_connection_t
*conn
, int code
, const char *fmt
,
265 control_vprintf_reply(conn
, code
, '+', fmt
, ap
);
269 /** Write a CmdData */
271 control_write_data(control_connection_t
*conn
, const char *data
)
276 esc_len
= write_escaped_data(data
, strlen(data
), &esc
);
277 connection_buf_add(esc
, esc_len
, TO_CONN(conn
));
281 /** Write a single reply line to @a conn.
283 * @param conn control connection
284 * @param line control reply line to write
285 * @param lastone true if this is the last reply line of a multi-line reply
288 control_write_reply_line(control_connection_t
*conn
,
289 const control_reply_line_t
*line
, bool lastone
)
291 const config_line_t
*kvline
= line
->kvline
;
294 if (strpbrk(kvline
->value
, "\r\n") != NULL
) {
295 /* If a key-value pair needs to be encoded as CmdData, it can be
296 the only key-value pair in that reply line */
297 tor_assert(kvline
->next
== NULL
);
298 control_printf_datareply(conn
, line
->code
, "%s=", kvline
->key
);
299 control_write_data(conn
, kvline
->value
);
302 s
= kvline_encode(kvline
, line
->flags
);
304 control_write_endreply(conn
, line
->code
, s
);
306 control_write_midreply(conn
, line
->code
, s
);
311 /** Write a set of reply lines to @a conn.
313 * @param conn control connection
314 * @param lines smartlist of pointers to control_reply_line_t to write
317 control_write_reply_lines(control_connection_t
*conn
, smartlist_t
*lines
)
319 bool lastone
= false;
321 SMARTLIST_FOREACH_BEGIN(lines
, control_reply_line_t
*, line
) {
322 if (line_sl_idx
>= line_sl_len
- 1)
324 control_write_reply_line(conn
, line
, lastone
);
325 } SMARTLIST_FOREACH_END(line
);
328 /** Add a single key-value pair as a new reply line to a control reply
331 * @param reply smartlist of pointers to control_reply_line_t
332 * @param code numeric control reply code
333 * @param flags kvline encoding flags
338 control_reply_add_one_kv(smartlist_t
*reply
, int code
, int flags
,
339 const char *key
, const char *val
)
341 control_reply_line_t
*line
= tor_malloc_zero(sizeof(*line
));
345 config_line_append(&line
->kvline
, key
, val
);
346 smartlist_add(reply
, line
);
349 /** Append a single key-value pair to last reply line in a control
352 * @param reply smartlist of pointers to control_reply_line_t
357 control_reply_append_kv(smartlist_t
*reply
, const char *key
, const char *val
)
359 int len
= smartlist_len(reply
);
360 control_reply_line_t
*line
;
364 line
= smartlist_get(reply
, len
- 1);
365 config_line_append(&line
->kvline
, key
, val
);
368 /** Add new reply line consisting of the string @a s
370 * @param reply smartlist of pointers to control_reply_line_t
371 * @param code numeric control reply code
372 * @param s string containing the rest of the reply line
375 control_reply_add_str(smartlist_t
*reply
, int code
, const char *s
)
377 control_reply_add_one_kv(reply
, code
, KV_OMIT_KEYS
|KV_RAW
, "", s
);
380 /** Format a new reply line
382 * @param reply smartlist of pointers to control_reply_line_t
383 * @param code numeric control reply code
384 * @param fmt format string
387 control_reply_add_printf(smartlist_t
*reply
, int code
, const char *fmt
, ...)
393 (void)tor_vasprintf(&buf
, fmt
, ap
);
395 control_reply_add_str(reply
, code
, buf
);
399 /** Add a "250 OK" line to a set of control reply lines */
401 control_reply_add_done(smartlist_t
*reply
)
403 control_reply_add_str(reply
, 250, "OK");
406 /** Free a control_reply_line_t. Don't call this directly; use the
407 * control_reply_line_free() macro instead. */
409 control_reply_line_free_(control_reply_line_t
*line
)
413 config_free_lines(line
->kvline
);
417 /** Clear a smartlist of control_reply_line_t. Doesn't free the
418 * smartlist, but does free each individual line. */
420 control_reply_clear(smartlist_t
*reply
)
422 SMARTLIST_FOREACH(reply
, control_reply_line_t
*, line
,
423 control_reply_line_free(line
));
424 smartlist_clear(reply
);
427 /** Free a smartlist of control_reply_line_t. Don't call this
428 * directly; use the control_reply_free() macro instead. */
430 control_reply_free_(smartlist_t
*reply
)
432 control_reply_clear(reply
);
433 smartlist_free_(reply
);