|
@@ -0,0 +1,165 @@
|
|
|
+
|
|
|
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ * \file control_proto.c
|
|
|
+ * \brief Formatting functions for controller data.
|
|
|
+ */
|
|
|
+
|
|
|
+#include "core/or/or.h"
|
|
|
+
|
|
|
+#include "core/mainloop/connection.h"
|
|
|
+#include "core/or/circuitbuild.h"
|
|
|
+#include "core/or/circuitlist.h"
|
|
|
+#include "core/or/connection_edge.h"
|
|
|
+#include "feature/control/control_proto.h"
|
|
|
+#include "feature/nodelist/nodelist.h"
|
|
|
+
|
|
|
+#include "core/or/cpath_build_state_st.h"
|
|
|
+#include "core/or/entry_connection_st.h"
|
|
|
+#include "core/or/or_connection_st.h"
|
|
|
+#include "core/or/origin_circuit_st.h"
|
|
|
+#include "core/or/socks_request_st.h"
|
|
|
+#include "feature/control/control_connection_st.h"
|
|
|
+
|
|
|
+
|
|
|
+ * <b>conn</b>-\>outbuf.
|
|
|
+ */
|
|
|
+void
|
|
|
+connection_write_str_to_buf(const char *s, control_connection_t *conn)
|
|
|
+{
|
|
|
+ size_t len = strlen(s);
|
|
|
+ connection_buf_add(s, len, TO_CONN(conn));
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * <b>conn</b>-\>outbuf. */
|
|
|
+void
|
|
|
+connection_printf_to_buf(control_connection_t *conn, const char *format, ...)
|
|
|
+{
|
|
|
+ va_list ap;
|
|
|
+ char *buf = NULL;
|
|
|
+ int len;
|
|
|
+
|
|
|
+ va_start(ap,format);
|
|
|
+ len = tor_vasprintf(&buf, format, ap);
|
|
|
+ va_end(ap);
|
|
|
+
|
|
|
+ if (len < 0) {
|
|
|
+ log_err(LD_BUG, "Unable to format string for controller.");
|
|
|
+ tor_assert(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ connection_buf_add(buf, (size_t)len, TO_CONN(conn));
|
|
|
+
|
|
|
+ tor_free(buf);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * terminated by CRLF, allocate a new string in *<b>out</b>, and copy the
|
|
|
+ * contents of <b>data</b> into *<b>out</b>, adding a period before any period
|
|
|
+ * that appears at the start of a line, and adding a period-CRLF line at
|
|
|
+ * the end. Replace all LF characters sequences with CRLF. Return the number
|
|
|
+ * of bytes in *<b>out</b>.
|
|
|
+ */
|
|
|
+size_t
|
|
|
+write_escaped_data(const char *data, size_t len, char **out)
|
|
|
+{
|
|
|
+ tor_assert(len < SIZE_MAX - 9);
|
|
|
+ size_t sz_out = len+8+1;
|
|
|
+ char *outp;
|
|
|
+ const char *start = data, *end;
|
|
|
+ size_t i;
|
|
|
+ int start_of_line;
|
|
|
+ for (i=0; i < len; ++i) {
|
|
|
+ if (data[i] == '\n') {
|
|
|
+ sz_out += 2;
|
|
|
+ if (sz_out >= SIZE_T_CEILING) {
|
|
|
+ log_warn(LD_BUG, "Input to write_escaped_data was too long");
|
|
|
+ *out = tor_strdup(".\r\n");
|
|
|
+ return 3;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ *out = outp = tor_malloc(sz_out);
|
|
|
+ end = data+len;
|
|
|
+ start_of_line = 1;
|
|
|
+ while (data < end) {
|
|
|
+ if (*data == '\n') {
|
|
|
+ if (data > start && data[-1] != '\r')
|
|
|
+ *outp++ = '\r';
|
|
|
+ start_of_line = 1;
|
|
|
+ } else if (*data == '.') {
|
|
|
+ if (start_of_line) {
|
|
|
+ start_of_line = 0;
|
|
|
+ *outp++ = '.';
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ start_of_line = 0;
|
|
|
+ }
|
|
|
+ *outp++ = *data++;
|
|
|
+ }
|
|
|
+ if (outp < *out+2 || fast_memcmp(outp-2, "\r\n", 2)) {
|
|
|
+ *outp++ = '\r';
|
|
|
+ *outp++ = '\n';
|
|
|
+ }
|
|
|
+ *outp++ = '.';
|
|
|
+ *outp++ = '\r';
|
|
|
+ *outp++ = '\n';
|
|
|
+ *outp = '\0';
|
|
|
+ tor_assert(outp >= *out);
|
|
|
+ tor_assert((size_t)(outp - *out) <= sz_out);
|
|
|
+ return outp - *out;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * terminated by CRLF, allocate a new string in *<b>out</b>, and copy
|
|
|
+ * the contents of <b>data</b> into *<b>out</b>, removing any period
|
|
|
+ * that appears at the start of a line, and replacing all CRLF sequences
|
|
|
+ * with LF. Return the number of
|
|
|
+ * bytes in *<b>out</b>. */
|
|
|
+size_t
|
|
|
+read_escaped_data(const char *data, size_t len, char **out)
|
|
|
+{
|
|
|
+ char *outp;
|
|
|
+ const char *next;
|
|
|
+ const char *end;
|
|
|
+
|
|
|
+ *out = outp = tor_malloc(len+1);
|
|
|
+
|
|
|
+ end = data+len;
|
|
|
+
|
|
|
+ while (data < end) {
|
|
|
+
|
|
|
+ if (*data == '.')
|
|
|
+ ++data;
|
|
|
+ next = memchr(data, '\n', end-data);
|
|
|
+ if (next) {
|
|
|
+ size_t n_to_copy = next-data;
|
|
|
+
|
|
|
+ if (n_to_copy && *(next-1) == '\r')
|
|
|
+ --n_to_copy;
|
|
|
+ memcpy(outp, data, n_to_copy);
|
|
|
+ outp += n_to_copy;
|
|
|
+ data = next+1;
|
|
|
+ * or the end of the string, or a period. */
|
|
|
+ } else {
|
|
|
+ memcpy(outp, data, end-data);
|
|
|
+ outp += (end-data);
|
|
|
+ *outp = '\0';
|
|
|
+ return outp - *out;
|
|
|
+ }
|
|
|
+ *outp++ = '\n';
|
|
|
+ }
|
|
|
+
|
|
|
+ *outp = '\0';
|
|
|
+ return outp - *out;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void
|
|
|
+send_control_done(control_connection_t *conn)
|
|
|
+{
|
|
|
+ connection_write_str_to_buf("250 OK\r\n", conn);
|
|
|
+}
|