control_proto.c (11362B)
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_proto.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_proto.h" 17 #include "feature/nodelist/nodelist.h" 18 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" 27 28 /** Append a NUL-terminated string <b>s</b> to the end of 29 * <b>conn</b>-\>outbuf. 30 */ 31 void 32 connection_write_str_to_buf(const char *s, control_connection_t *conn) 33 { 34 size_t len = strlen(s); 35 connection_buf_add(s, len, TO_CONN(conn)); 36 } 37 38 /** Acts like sprintf, but writes its formatted string to the end of 39 * <b>conn</b>-\>outbuf. */ 40 void 41 connection_printf_to_buf(control_connection_t *conn, const char *format, ...) 42 { 43 va_list ap; 44 char *buf = NULL; 45 int len; 46 47 va_start(ap,format); 48 len = tor_vasprintf(&buf, format, ap); 49 va_end(ap); 50 51 if (len < 0) { 52 log_err(LD_BUG, "Unable to format string for controller."); 53 tor_assert(0); 54 } 55 56 connection_buf_add(buf, (size_t)len, TO_CONN(conn)); 57 58 tor_free(buf); 59 } 60 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>. 67 * 68 * This corresponds to CmdData in control-spec.txt. 69 */ 70 size_t 71 write_escaped_data(const char *data, size_t len, char **out) 72 { 73 tor_assert(len < SIZE_MAX - 9); 74 size_t sz_out = len+8+1; 75 char *outp; 76 const char *start = data, *end; 77 size_t i; 78 int start_of_line; 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"); 85 return 3; 86 } 87 } 88 } 89 *out = outp = tor_malloc(sz_out); 90 end = data+len; 91 start_of_line = 1; 92 while (data < end) { 93 if (*data == '\n') { 94 if (data > start && data[-1] != '\r') 95 *outp++ = '\r'; 96 start_of_line = 1; 97 } else if (*data == '.') { 98 if (start_of_line) { 99 start_of_line = 0; 100 *outp++ = '.'; 101 } 102 } else { 103 start_of_line = 0; 104 } 105 *outp++ = *data++; 106 } 107 if (outp < *out+2 || fast_memcmp(outp-2, "\r\n", 2)) { 108 *outp++ = '\r'; 109 *outp++ = '\n'; 110 } 111 *outp++ = '.'; 112 *outp++ = '\r'; 113 *outp++ = '\n'; 114 *outp = '\0'; /* NUL-terminate just in case. */ 115 tor_assert(outp >= *out); 116 tor_assert((size_t)(outp - *out) <= sz_out); 117 return outp - *out; 118 } 119 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>. 126 * 127 * This corresponds to CmdData in control-spec.txt. 128 */ 129 size_t 130 read_escaped_data(const char *data, size_t len, char **out) 131 { 132 char *outp; 133 const char *next; 134 const char *end; 135 136 *out = outp = tor_malloc(len+1); 137 138 end = data+len; 139 140 while (data < end) { 141 /* we're at the start of a line. */ 142 if (*data == '.') 143 ++data; 144 next = memchr(data, '\n', end-data); 145 if (next) { 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') 149 --n_to_copy; 150 memcpy(outp, data, n_to_copy); 151 outp += 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. */ 154 } else { 155 memcpy(outp, data, end-data); 156 outp += (end-data); 157 *outp = '\0'; 158 return outp - *out; 159 } 160 *outp++ = '\n'; 161 } 162 163 *outp = '\0'; 164 return outp - *out; 165 } 166 167 /** Send a "DONE" message down the control connection <b>conn</b>. */ 168 void 169 send_control_done(control_connection_t *conn) 170 { 171 control_write_endreply(conn, 250, "OK"); 172 } 173 174 /** Write a reply to the control channel. 175 * 176 * @param conn control connection 177 * @param code numeric result code 178 * @param c separator character, usually ' ', '-', or '+' 179 * @param s string reply content 180 */ 181 MOCK_IMPL(void, 182 control_write_reply, (control_connection_t *conn, int code, int c, 183 const char *s)) 184 { 185 connection_printf_to_buf(conn, "%03d%c%s\r\n", code, c, s); 186 } 187 188 /** Write a formatted reply to the control channel. 189 * 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 195 */ 196 void 197 control_vprintf_reply(control_connection_t *conn, int code, int c, 198 const char *fmt, va_list ap) 199 { 200 char *buf = NULL; 201 int len; 202 203 len = tor_vasprintf(&buf, fmt, ap); 204 if (len < 0) { 205 log_err(LD_BUG, "Unable to format string for controller."); 206 tor_assert(0); 207 } 208 control_write_reply(conn, code, c, buf); 209 tor_free(buf); 210 } 211 212 /** Write an EndReplyLine */ 213 void 214 control_write_endreply(control_connection_t *conn, int code, const char *s) 215 { 216 control_write_reply(conn, code, ' ', s); 217 } 218 219 /** Write a formatted EndReplyLine */ 220 void 221 control_printf_endreply(control_connection_t *conn, int code, 222 const char *fmt, ...) 223 { 224 va_list ap; 225 226 va_start(ap, fmt); 227 control_vprintf_reply(conn, code, ' ', fmt, ap); 228 va_end(ap); 229 } 230 231 /** Write a MidReplyLine */ 232 void 233 control_write_midreply(control_connection_t *conn, int code, const char *s) 234 { 235 control_write_reply(conn, code, '-', s); 236 } 237 238 /** Write a formatted MidReplyLine */ 239 void 240 control_printf_midreply(control_connection_t *conn, int code, const char *fmt, 241 ...) 242 { 243 va_list ap; 244 245 va_start(ap, fmt); 246 control_vprintf_reply(conn, code, '-', fmt, ap); 247 va_end(ap); 248 } 249 250 /** Write a DataReplyLine */ 251 void 252 control_write_datareply(control_connection_t *conn, int code, const char *s) 253 { 254 control_write_reply(conn, code, '+', s); 255 } 256 257 /** Write a formatted DataReplyLine */ 258 void 259 control_printf_datareply(control_connection_t *conn, int code, const char *fmt, 260 ...) 261 { 262 va_list ap; 263 264 va_start(ap, fmt); 265 control_vprintf_reply(conn, code, '+', fmt, ap); 266 va_end(ap); 267 } 268 269 /** Write a CmdData */ 270 void 271 control_write_data(control_connection_t *conn, const char *data) 272 { 273 char *esc = NULL; 274 size_t esc_len; 275 276 esc_len = write_escaped_data(data, strlen(data), &esc); 277 connection_buf_add(esc, esc_len, TO_CONN(conn)); 278 tor_free(esc); 279 } 280 281 /** Write a single reply line to @a conn. 282 * 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 286 */ 287 void 288 control_write_reply_line(control_connection_t *conn, 289 const control_reply_line_t *line, bool lastone) 290 { 291 const config_line_t *kvline = line->kvline; 292 char *s = NULL; 293 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); 300 return; 301 } 302 s = kvline_encode(kvline, line->flags); 303 if (lastone) { 304 control_write_endreply(conn, line->code, s); 305 } else { 306 control_write_midreply(conn, line->code, s); 307 } 308 tor_free(s); 309 } 310 311 /** Write a set of reply lines to @a conn. 312 * 313 * @param conn control connection 314 * @param lines smartlist of pointers to control_reply_line_t to write 315 */ 316 void 317 control_write_reply_lines(control_connection_t *conn, smartlist_t *lines) 318 { 319 bool lastone = false; 320 321 SMARTLIST_FOREACH_BEGIN(lines, control_reply_line_t *, line) { 322 if (line_sl_idx >= line_sl_len - 1) 323 lastone = true; 324 control_write_reply_line(conn, line, lastone); 325 } SMARTLIST_FOREACH_END(line); 326 } 327 328 /** Add a single key-value pair as a new reply line to a control reply 329 * line list. 330 * 331 * @param reply smartlist of pointers to control_reply_line_t 332 * @param code numeric control reply code 333 * @param flags kvline encoding flags 334 * @param key key 335 * @param val value 336 */ 337 void 338 control_reply_add_one_kv(smartlist_t *reply, int code, int flags, 339 const char *key, const char *val) 340 { 341 control_reply_line_t *line = tor_malloc_zero(sizeof(*line)); 342 343 line->code = code; 344 line->flags = flags; 345 config_line_append(&line->kvline, key, val); 346 smartlist_add(reply, line); 347 } 348 349 /** Append a single key-value pair to last reply line in a control 350 * reply line list. 351 * 352 * @param reply smartlist of pointers to control_reply_line_t 353 * @param key key 354 * @param val value 355 */ 356 void 357 control_reply_append_kv(smartlist_t *reply, const char *key, const char *val) 358 { 359 int len = smartlist_len(reply); 360 control_reply_line_t *line; 361 362 tor_assert(len > 0); 363 364 line = smartlist_get(reply, len - 1); 365 config_line_append(&line->kvline, key, val); 366 } 367 368 /** Add new reply line consisting of the string @a s 369 * 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 373 */ 374 void 375 control_reply_add_str(smartlist_t *reply, int code, const char *s) 376 { 377 control_reply_add_one_kv(reply, code, KV_OMIT_KEYS|KV_RAW, "", s); 378 } 379 380 /** Format a new reply line 381 * 382 * @param reply smartlist of pointers to control_reply_line_t 383 * @param code numeric control reply code 384 * @param fmt format string 385 */ 386 void 387 control_reply_add_printf(smartlist_t *reply, int code, const char *fmt, ...) 388 { 389 va_list ap; 390 char *buf = NULL; 391 392 va_start(ap, fmt); 393 (void)tor_vasprintf(&buf, fmt, ap); 394 va_end(ap); 395 control_reply_add_str(reply, code, buf); 396 tor_free(buf); 397 } 398 399 /** Add a "250 OK" line to a set of control reply lines */ 400 void 401 control_reply_add_done(smartlist_t *reply) 402 { 403 control_reply_add_str(reply, 250, "OK"); 404 } 405 406 /** Free a control_reply_line_t. Don't call this directly; use the 407 * control_reply_line_free() macro instead. */ 408 void 409 control_reply_line_free_(control_reply_line_t *line) 410 { 411 if (!line) 412 return; 413 config_free_lines(line->kvline); 414 tor_free_(line); 415 } 416 417 /** Clear a smartlist of control_reply_line_t. Doesn't free the 418 * smartlist, but does free each individual line. */ 419 void 420 control_reply_clear(smartlist_t *reply) 421 { 422 SMARTLIST_FOREACH(reply, control_reply_line_t *, line, 423 control_reply_line_free(line)); 424 smartlist_clear(reply); 425 } 426 427 /** Free a smartlist of control_reply_line_t. Don't call this 428 * directly; use the control_reply_free() macro instead. */ 429 void 430 control_reply_free_(smartlist_t *reply) 431 { 432 control_reply_clear(reply); 433 smartlist_free_(reply); 434 }