control_proto.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  2. * Copyright (c) 2007-2019, The Tor Project, Inc. */
  3. /* See LICENSE for licensing information */
  4. /**
  5. * \file control_proto.c
  6. * \brief Formatting functions for controller data.
  7. */
  8. #include "core/or/or.h"
  9. #include "core/mainloop/connection.h"
  10. #include "core/or/circuitbuild.h"
  11. #include "core/or/circuitlist.h"
  12. #include "core/or/connection_edge.h"
  13. #include "feature/control/control_proto.h"
  14. #include "feature/nodelist/nodelist.h"
  15. #include "core/or/cpath_build_state_st.h"
  16. #include "core/or/entry_connection_st.h"
  17. #include "core/or/or_connection_st.h"
  18. #include "core/or/origin_circuit_st.h"
  19. #include "core/or/socks_request_st.h"
  20. #include "feature/control/control_connection_st.h"
  21. /** Append a NUL-terminated string <b>s</b> to the end of
  22. * <b>conn</b>-\>outbuf.
  23. */
  24. void
  25. connection_write_str_to_buf(const char *s, control_connection_t *conn)
  26. {
  27. size_t len = strlen(s);
  28. connection_buf_add(s, len, TO_CONN(conn));
  29. }
  30. /** Acts like sprintf, but writes its formatted string to the end of
  31. * <b>conn</b>-\>outbuf. */
  32. void
  33. connection_printf_to_buf(control_connection_t *conn, const char *format, ...)
  34. {
  35. va_list ap;
  36. char *buf = NULL;
  37. int len;
  38. va_start(ap,format);
  39. len = tor_vasprintf(&buf, format, ap);
  40. va_end(ap);
  41. if (len < 0) {
  42. log_err(LD_BUG, "Unable to format string for controller.");
  43. tor_assert(0);
  44. }
  45. connection_buf_add(buf, (size_t)len, TO_CONN(conn));
  46. tor_free(buf);
  47. }
  48. /** Given a <b>len</b>-character string in <b>data</b>, made of lines
  49. * terminated by CRLF, allocate a new string in *<b>out</b>, and copy the
  50. * contents of <b>data</b> into *<b>out</b>, adding a period before any period
  51. * that appears at the start of a line, and adding a period-CRLF line at
  52. * the end. Replace all LF characters sequences with CRLF. Return the number
  53. * of bytes in *<b>out</b>.
  54. *
  55. * This corresponds to CmdData in control-spec.txt.
  56. */
  57. size_t
  58. write_escaped_data(const char *data, size_t len, char **out)
  59. {
  60. tor_assert(len < SIZE_MAX - 9);
  61. size_t sz_out = len+8+1;
  62. char *outp;
  63. const char *start = data, *end;
  64. size_t i;
  65. int start_of_line;
  66. for (i=0; i < len; ++i) {
  67. if (data[i] == '\n') {
  68. sz_out += 2; /* Maybe add a CR; maybe add a dot. */
  69. if (sz_out >= SIZE_T_CEILING) {
  70. log_warn(LD_BUG, "Input to write_escaped_data was too long");
  71. *out = tor_strdup(".\r\n");
  72. return 3;
  73. }
  74. }
  75. }
  76. *out = outp = tor_malloc(sz_out);
  77. end = data+len;
  78. start_of_line = 1;
  79. while (data < end) {
  80. if (*data == '\n') {
  81. if (data > start && data[-1] != '\r')
  82. *outp++ = '\r';
  83. start_of_line = 1;
  84. } else if (*data == '.') {
  85. if (start_of_line) {
  86. start_of_line = 0;
  87. *outp++ = '.';
  88. }
  89. } else {
  90. start_of_line = 0;
  91. }
  92. *outp++ = *data++;
  93. }
  94. if (outp < *out+2 || fast_memcmp(outp-2, "\r\n", 2)) {
  95. *outp++ = '\r';
  96. *outp++ = '\n';
  97. }
  98. *outp++ = '.';
  99. *outp++ = '\r';
  100. *outp++ = '\n';
  101. *outp = '\0'; /* NUL-terminate just in case. */
  102. tor_assert(outp >= *out);
  103. tor_assert((size_t)(outp - *out) <= sz_out);
  104. return outp - *out;
  105. }
  106. /** Given a <b>len</b>-character string in <b>data</b>, made of lines
  107. * terminated by CRLF, allocate a new string in *<b>out</b>, and copy
  108. * the contents of <b>data</b> into *<b>out</b>, removing any period
  109. * that appears at the start of a line, and replacing all CRLF sequences
  110. * with LF. Return the number of
  111. * bytes in *<b>out</b>.
  112. *
  113. * This corresponds to CmdData in control-spec.txt.
  114. */
  115. size_t
  116. read_escaped_data(const char *data, size_t len, char **out)
  117. {
  118. char *outp;
  119. const char *next;
  120. const char *end;
  121. *out = outp = tor_malloc(len+1);
  122. end = data+len;
  123. while (data < end) {
  124. /* we're at the start of a line. */
  125. if (*data == '.')
  126. ++data;
  127. next = memchr(data, '\n', end-data);
  128. if (next) {
  129. size_t n_to_copy = next-data;
  130. /* Don't copy a CR that precedes this LF. */
  131. if (n_to_copy && *(next-1) == '\r')
  132. --n_to_copy;
  133. memcpy(outp, data, n_to_copy);
  134. outp += n_to_copy;
  135. data = next+1; /* This will point at the start of the next line,
  136. * or the end of the string, or a period. */
  137. } else {
  138. memcpy(outp, data, end-data);
  139. outp += (end-data);
  140. *outp = '\0';
  141. return outp - *out;
  142. }
  143. *outp++ = '\n';
  144. }
  145. *outp = '\0';
  146. return outp - *out;
  147. }
  148. /** Send a "DONE" message down the control connection <b>conn</b>. */
  149. void
  150. send_control_done(control_connection_t *conn)
  151. {
  152. control_write_endreply(conn, 250, "OK");
  153. }
  154. /** Write a reply to the control channel.
  155. *
  156. * @param conn control connection
  157. * @param code numeric result code
  158. * @param c separator character, usually ' ', '-', or '+'
  159. * @param s string reply content
  160. */
  161. MOCK_IMPL(void,
  162. control_write_reply, (control_connection_t *conn, int code, int c,
  163. const char *s))
  164. {
  165. connection_printf_to_buf(conn, "%03d%c%s\r\n", code, c, s);
  166. }
  167. /** Write a formatted reply to the control channel.
  168. *
  169. * @param conn control connection
  170. * @param code numeric result code
  171. * @param c separator character, usually ' ', '-', or '+'
  172. * @param fmt format string
  173. * @param ap va_list from caller
  174. */
  175. void
  176. control_vprintf_reply(control_connection_t *conn, int code, int c,
  177. const char *fmt, va_list ap)
  178. {
  179. char *buf = NULL;
  180. int len;
  181. len = tor_vasprintf(&buf, fmt, ap);
  182. if (len < 0) {
  183. log_err(LD_BUG, "Unable to format string for controller.");
  184. tor_assert(0);
  185. }
  186. control_write_reply(conn, code, c, buf);
  187. tor_free(buf);
  188. }
  189. /** Write an EndReplyLine */
  190. void
  191. control_write_endreply(control_connection_t *conn, int code, const char *s)
  192. {
  193. control_write_reply(conn, code, ' ', s);
  194. }
  195. /** Write a formatted EndReplyLine */
  196. void
  197. control_printf_endreply(control_connection_t *conn, int code,
  198. const char *fmt, ...)
  199. {
  200. va_list ap;
  201. va_start(ap, fmt);
  202. control_vprintf_reply(conn, code, ' ', fmt, ap);
  203. va_end(ap);
  204. }
  205. /** Write a MidReplyLine */
  206. void
  207. control_write_midreply(control_connection_t *conn, int code, const char *s)
  208. {
  209. control_write_reply(conn, code, '-', s);
  210. }
  211. /** Write a formatted MidReplyLine */
  212. void
  213. control_printf_midreply(control_connection_t *conn, int code, const char *fmt,
  214. ...)
  215. {
  216. va_list ap;
  217. va_start(ap, fmt);
  218. control_vprintf_reply(conn, code, '-', fmt, ap);
  219. va_end(ap);
  220. }
  221. /** Write a DataReplyLine */
  222. void
  223. control_write_datareply(control_connection_t *conn, int code, const char *s)
  224. {
  225. control_write_reply(conn, code, '+', s);
  226. }
  227. /** Write a formatted DataReplyLine */
  228. void
  229. control_printf_datareply(control_connection_t *conn, int code, const char *fmt,
  230. ...)
  231. {
  232. va_list ap;
  233. va_start(ap, fmt);
  234. control_vprintf_reply(conn, code, '+', fmt, ap);
  235. va_end(ap);
  236. }
  237. /** Write a CmdData */
  238. void
  239. control_write_data(control_connection_t *conn, const char *data)
  240. {
  241. char *esc = NULL;
  242. size_t esc_len;
  243. esc_len = write_escaped_data(data, strlen(data), &esc);
  244. connection_buf_add(esc, esc_len, TO_CONN(conn));
  245. tor_free(esc);
  246. }