Tor  0.4.7.0-alpha-dev
control_proto.c
Go to the documentation of this file.
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 
13 #include "core/or/circuitbuild.h"
14 #include "core/or/circuitlist.h"
18 
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
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
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
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
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
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
318 {
319  bool lastone = false;
320 
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
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
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
421 {
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
431 {
432  control_reply_clear(reply);
433  smartlist_free_(reply);
434 }
Header file for circuitbuild.c.
Header file for circuitlist.c.
void config_line_append(config_line_t **lst, const char *key, const char *val)
Definition: confline.c:32
Header file for connection.c.
Header file for connection_edge.c.
Controller connection structure.
void control_write_data(control_connection_t *conn, const char *data)
void control_printf_datareply(control_connection_t *conn, int code, const char *fmt,...)
void control_write_endreply(control_connection_t *conn, int code, const char *s)
void control_printf_midreply(control_connection_t *conn, int code, const char *fmt,...)
void control_write_midreply(control_connection_t *conn, int code, const char *s)
void send_control_done(control_connection_t *conn)
void control_vprintf_reply(control_connection_t *conn, int code, int c, const char *fmt, va_list ap)
void control_write_reply(control_connection_t *conn, int code, int c, const char *s)
void control_printf_endreply(control_connection_t *conn, int code, const char *fmt,...)
size_t read_escaped_data(const char *data, size_t len, char **out)
void connection_write_str_to_buf(const char *s, control_connection_t *conn)
Definition: control_proto.c:32
void control_write_datareply(control_connection_t *conn, int code, const char *s)
size_t write_escaped_data(const char *data, size_t len, char **out)
Definition: control_proto.c:71
void connection_printf_to_buf(control_connection_t *conn, const char *format,...)
Definition: control_proto.c:41
Header file for control_proto.c.
Circuit-build-stse structure.
#define fast_memcmp(a, b, c)
Definition: di_ops.h:28
Entry connection structure.
void control_reply_append_kv(smartlist_t *reply, const char *key, const char *val)
void control_write_reply_lines(control_connection_t *conn, smartlist_t *lines)
void control_reply_clear(smartlist_t *reply)
void control_reply_add_printf(smartlist_t *reply, int code, const char *fmt,...)
void control_reply_add_one_kv(smartlist_t *reply, int code, int flags, const char *key, const char *val)
void control_reply_line_free_(control_reply_line_t *line)
void control_reply_add_str(smartlist_t *reply, int code, const char *s)
void control_reply_add_done(smartlist_t *reply)
void control_write_reply_line(control_connection_t *conn, const control_reply_line_t *line, bool lastone)
void control_reply_free_(smartlist_t *reply)
#define control_reply_line_free(line)
Free and null a control_reply_line_t.
Definition: control_proto.h:55
char * kvline_encode(const config_line_t *line, unsigned flags)
Definition: kvline.c:126
Header for kvline.c.
#define LD_BUG
Definition: log.h:86
void tor_free_(void *mem)
Definition: malloc.c:227
#define tor_free(p)
Definition: malloc.h:52
Header file for nodelist.c.
Master header file for Tor-specific functionality.
#define TO_CONN(c)
Definition: or.h:616
OR connection structure.
Origin circuit structure.
int tor_vasprintf(char **strp, const char *fmt, va_list args)
Definition: printf.c:96
Header for smartlist.c.
void smartlist_add(smartlist_t *sl, void *element)
void smartlist_clear(smartlist_t *sl)
void smartlist_free_(smartlist_t *sl)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
Client request structure.
A reply line for the control protocol.
Definition: control_proto.h:43
config_line_t * kvline
Definition: control_proto.h:46
#define MOCK_IMPL(rv, funcname, arglist)
Definition: testsupport.h:133
#define SIZE_T_CEILING
Definition: torint.h:126
#define tor_assert(expr)
Definition: util_bug.h:102