📄 control.c
字号:
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2008, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* $Id$ */
const char control_c_id[] =
"$Id$";
/**
* \file control.c
* \brief Implementation for Tor's control-socket interface.
* See doc/spec/control-spec.txt for full details on protocol.
**/
#define CONTROL_PRIVATE
#include "or.h"
/** Yield true iff <b>s</b> is the state of a control_connection_t that has
* finished authentication and is accepting commands. */
#define STATE_IS_OPEN(s) ((s) == CONTROL_CONN_STATE_OPEN)
/* Recognized asynchronous event types. It's okay to expand this list
* because it is used both as a list of v0 event types, and as indices
* into the bitfield to determine which controllers want which events.
*/
#define _EVENT_MIN 0x0001
#define EVENT_CIRCUIT_STATUS 0x0001
#define EVENT_STREAM_STATUS 0x0002
#define EVENT_OR_CONN_STATUS 0x0003
#define EVENT_BANDWIDTH_USED 0x0004
#define EVENT_LOG_OBSOLETE 0x0005 /* Can reclaim this. */
#define EVENT_NEW_DESC 0x0006
#define EVENT_DEBUG_MSG 0x0007
#define EVENT_INFO_MSG 0x0008
#define EVENT_NOTICE_MSG 0x0009
#define EVENT_WARN_MSG 0x000A
#define EVENT_ERR_MSG 0x000B
#define EVENT_ADDRMAP 0x000C
// #define EVENT_AUTHDIR_NEWDESCS 0x000D
#define EVENT_DESCCHANGED 0x000E
// #define EVENT_NS 0x000F
#define EVENT_STATUS_CLIENT 0x0010
#define EVENT_STATUS_SERVER 0x0011
#define EVENT_STATUS_GENERAL 0x0012
#define EVENT_GUARD 0x0013
#define EVENT_STREAM_BANDWIDTH_USED 0x0014
#define _EVENT_MAX 0x0014
/* If _EVENT_MAX ever hits 0x0020, we need to make the mask wider. */
/** Bitfield: The bit 1<<e is set if <b>any</b> open control
* connection is interested in events of type <b>e</b>. We use this
* so that we can decide to skip generating event messages that nobody
* has interest in without having to walk over the global connection
* list to find out.
**/
typedef uint32_t event_mask_t;
static event_mask_t global_event_mask1long = 0;
static event_mask_t global_event_mask1short = 0;
/** True iff we have disabled log messages from being sent to the controller */
static int disable_log_messages = 0;
/** Macro: true if any control connection is interested in events of type
* <b>e</b>. */
#define EVENT_IS_INTERESTING(e) \
((global_event_mask1long|global_event_mask1short) & (1<<(e)))
#define EVENT_IS_INTERESTING1L(e) (global_event_mask1long & (1<<(e)))
#define EVENT_IS_INTERESTING1S(e) (global_event_mask1short & (1<<(e)))
/** If we're using cookie-type authentication, how long should our cookies be?
*/
#define AUTHENTICATION_COOKIE_LEN 32
/** If true, we've set authentication_cookie to a secret code and
* stored it to disk. */
static int authentication_cookie_is_set = 0;
static char authentication_cookie[AUTHENTICATION_COOKIE_LEN];
#define SHORT_NAMES 1
#define LONG_NAMES 2
#define ALL_NAMES (SHORT_NAMES|LONG_NAMES)
#define EXTENDED_FORMAT 4
#define NONEXTENDED_FORMAT 8
#define ALL_FORMATS (EXTENDED_FORMAT|NONEXTENDED_FORMAT)
typedef int event_format_t;
static void connection_printf_to_buf(control_connection_t *conn,
const char *format, ...)
CHECK_PRINTF(2,3);
static void send_control_done(control_connection_t *conn);
static void send_control_event(uint16_t event, event_format_t which,
const char *format, ...)
CHECK_PRINTF(3,4);
static void send_control_event_extended(uint16_t event, event_format_t which,
const char *format, ...)
CHECK_PRINTF(3,4);
static int handle_control_setconf(control_connection_t *conn, uint32_t len,
char *body);
static int handle_control_resetconf(control_connection_t *conn, uint32_t len,
char *body);
static int handle_control_getconf(control_connection_t *conn, uint32_t len,
const char *body);
static int handle_control_loadconf(control_connection_t *conn, uint32_t len,
const char *body);
static int handle_control_setevents(control_connection_t *conn, uint32_t len,
const char *body);
static int handle_control_authenticate(control_connection_t *conn,
uint32_t len,
const char *body);
static int handle_control_saveconf(control_connection_t *conn, uint32_t len,
const char *body);
static int handle_control_signal(control_connection_t *conn, uint32_t len,
const char *body);
static int handle_control_mapaddress(control_connection_t *conn, uint32_t len,
const char *body);
static char *list_getinfo_options(void);
static int handle_control_getinfo(control_connection_t *conn, uint32_t len,
const char *body);
static int handle_control_extendcircuit(control_connection_t *conn,
uint32_t len,
const char *body);
static int handle_control_setcircuitpurpose(control_connection_t *conn,
uint32_t len, const char *body);
static int handle_control_attachstream(control_connection_t *conn,
uint32_t len,
const char *body);
static int handle_control_postdescriptor(control_connection_t *conn,
uint32_t len,
const char *body);
static int handle_control_redirectstream(control_connection_t *conn,
uint32_t len,
const char *body);
static int handle_control_closestream(control_connection_t *conn, uint32_t len,
const char *body);
static int handle_control_closecircuit(control_connection_t *conn,
uint32_t len,
const char *body);
static int handle_control_resolve(control_connection_t *conn, uint32_t len,
const char *body);
static int handle_control_usefeature(control_connection_t *conn,
uint32_t len,
const char *body);
static int write_stream_target_to_buf(edge_connection_t *conn, char *buf,
size_t len);
static void orconn_target_get_name(int long_names, char *buf, size_t len,
or_connection_t *conn);
static char *get_cookie_file(void);
/** Given a control event code for a message event, return the corresponding
* log severity. */
static INLINE int
event_to_log_severity(int event)
{
switch (event) {
case EVENT_DEBUG_MSG: return LOG_DEBUG;
case EVENT_INFO_MSG: return LOG_INFO;
case EVENT_NOTICE_MSG: return LOG_NOTICE;
case EVENT_WARN_MSG: return LOG_WARN;
case EVENT_ERR_MSG: return LOG_ERR;
default: return -1;
}
}
/** Given a log severity, return the corresponding control event code. */
static INLINE int
log_severity_to_event(int severity)
{
switch (severity) {
case LOG_DEBUG: return EVENT_DEBUG_MSG;
case LOG_INFO: return EVENT_INFO_MSG;
case LOG_NOTICE: return EVENT_NOTICE_MSG;
case LOG_WARN: return EVENT_WARN_MSG;
case LOG_ERR: return EVENT_ERR_MSG;
default: return -1;
}
}
/** Set <b>global_event_mask*</b> to the bitwise OR of each live control
* connection's event_mask field. */
void
control_update_global_event_mask(void)
{
smartlist_t *conns = get_connection_array();
event_mask_t old_mask, new_mask;
old_mask = global_event_mask1short;
old_mask |= global_event_mask1long;
global_event_mask1short = 0;
global_event_mask1long = 0;
SMARTLIST_FOREACH(conns, connection_t *, _conn,
{
if (_conn->type == CONN_TYPE_CONTROL &&
STATE_IS_OPEN(_conn->state)) {
control_connection_t *conn = TO_CONTROL_CONN(_conn);
if (conn->use_long_names)
global_event_mask1long |= conn->event_mask;
else
global_event_mask1short |= conn->event_mask;
}
});
new_mask = global_event_mask1short;
new_mask |= global_event_mask1long;
/* Handle the aftermath. Set up the log callback to tell us only what
* we want to hear...*/
control_adjust_event_log_severity();
/* ...then, if we've started logging stream bw, clear the appropriate
* fields. */
if (! (old_mask & EVENT_STREAM_BANDWIDTH_USED) &&
(new_mask & EVENT_STREAM_BANDWIDTH_USED)) {
SMARTLIST_FOREACH(conns, connection_t *, conn,
{
if (conn->type == CONN_TYPE_AP) {
edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
edge_conn->n_written = edge_conn->n_read = 0;
}
});
}
}
/** Adjust the log severities that result in control_event_logmsg being called
* to match the severity of log messages that any controllers are interested
* in. */
void
control_adjust_event_log_severity(void)
{
int i;
int min_log_event=EVENT_ERR_MSG, max_log_event=EVENT_DEBUG_MSG;
for (i = EVENT_DEBUG_MSG; i <= EVENT_ERR_MSG; ++i) {
if (EVENT_IS_INTERESTING(i)) {
min_log_event = i;
break;
}
}
for (i = EVENT_ERR_MSG; i >= EVENT_DEBUG_MSG; --i) {
if (EVENT_IS_INTERESTING(i)) {
max_log_event = i;
break;
}
}
if (EVENT_IS_INTERESTING(EVENT_LOG_OBSOLETE) ||
EVENT_IS_INTERESTING(EVENT_STATUS_GENERAL)) {
if (min_log_event > EVENT_NOTICE_MSG)
min_log_event = EVENT_NOTICE_MSG;
if (max_log_event < EVENT_ERR_MSG)
max_log_event = EVENT_ERR_MSG;
}
if (min_log_event <= max_log_event)
change_callback_log_severity(event_to_log_severity(min_log_event),
event_to_log_severity(max_log_event),
control_event_logmsg);
else
change_callback_log_severity(LOG_ERR, LOG_ERR,
control_event_logmsg);
}
/** Return true iff the event with code <b>c</b> is being sent to any current
* control connection. This is useful if the amount of work needed to prepare
* to call the appropriate control_event_...() function is high.
*/
int
control_event_is_interesting(int event)
{
return EVENT_IS_INTERESTING(event);
}
/** Append a NUL-terminated string <b>s</b> to the end of
* <b>conn</b>-\>outbuf.
*/
static INLINE void
connection_write_str_to_buf(const char *s, control_connection_t *conn)
{
size_t len = strlen(s);
connection_write_to_buf(s, len, TO_CONN(conn));
}
/** Given a <b>len</b>-character string in <b>data</b>, made of lines
* 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 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>.
*/
/* static */ size_t
write_escaped_data(const char *data, size_t len, char **out)
{
size_t sz_out = len+8;
char *outp;
const char *start = data, *end;
int i;
int start_of_line;
for (i=0; i<(int)len; ++i) {
if (data[i]== '\n')
sz_out += 2; /* Maybe add a CR; maybe add a dot. */
}
*out = outp = tor_malloc(sz_out+1);
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 || memcmp(outp-2, "\r\n", 2)) {
*outp++ = '\r';
*outp++ = '\n';
}
*outp++ = '.';
*outp++ = '\r';
*outp++ = '\n';
*outp = '\0'; /* NUL-terminate just in case. */
tor_assert((outp - *out) <= (int)sz_out);
return outp - *out;
}
/** Given a <b>len</b>-character string in <b>data</b>, made of lines
* 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>. */
/* static */ 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) {
/* we're at the start of a line. */
if (*data == '.')
++data;
next = memchr(data, '\n', end-data);
if (next) {
size_t n_to_copy = next-data;
/* Don't copy a CR that precedes this LF. */
if (n_to_copy && *(next-1) == '\r')
--n_to_copy;
memcpy(outp, data, n_to_copy);
outp += n_to_copy;
data = next+1; /* This will point at the start of the next line,
* or the end of the string, or a period. */
} else {
memcpy(outp, data, end-data);
outp += (end-data);
*outp = '\0';
return outp - *out;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -