Add a new circuit purpose 'controller' to let the controller

ask for a circuit that Tor won't try to use.

Extend the EXTENDCIRCUIT controller command to let you specify
the purpose if you're starting a new circuit.

Add a new SETCIRCUITPURPOSE controller command to let you
change a circuit's purpose after it's been created.


svn:r6075
This commit is contained in:
Roger Dingledine 2006-02-23 06:51:09 +00:00
parent 2bfd2a2400
commit 329af979e0
3 changed files with 99 additions and 14 deletions

View File

@ -405,19 +405,32 @@ $Id$
3.10. EXTENDCIRCUIT
Sent from the client to the server. The format is:
"EXTENDCIRCUIT" SP CircuitID SP ServerID *("," ServerID) CRLF
"EXTENDCIRCUIT" SP CircuitID SP
ServerID *("," ServerID) SP
("purpose=" Purpose) CRLF
This request takes one of two forms: either the Circuit ID is zero, in
This request takes one of two forms: either the CircuitID is zero, in
which case it is a request for the server to build a new circuit according
to the specified path, or the Circuit ID is nonzero, in which case it is a
to the specified path, or the CircuitID is nonzero, in which case it is a
request for the server to extend an existing circuit with that ID according
to the specified path.
If the request is successful, the server sends a reply containing a message
body consisting of the Circuit ID of the (maybe newly created) circuit.
The syntax is "250" SP "EXTENDED" SP CircuitID CRLF.
If CircuitID is 0 and "purpose=" is specified, then the circuit's
purpose is set. Two choices are recognized: "general" and
"controller". If not specified, circuits are created as "general".
3.11. ATTACHSTREAM
If the request is successful, the server sends a reply containing a
message body consisting of the CircuitID of the (maybe newly created)
circuit. The syntax is "250" SP "EXTENDED" SP CircuitID CRLF.
3.11. SETCIRCUITPURPOSE
Sent from the client to the server. The format is:
"SETCIRCUITPURPOSE" SP CircuitID SP Purpose CRLF
This changes the circuit's purpose. See EXTENDCIRCUIT above for details.
3.12. ATTACHSTREAM
Sent from the client to the server. The syntax is:
"ATTACHSTREAM" SP StreamID SP CircuitID CRLF
@ -446,7 +459,7 @@ $Id$
via TC when "__LeaveStreamsUnattached" is false may cause a race between
Tor and the controller, as both attempt to attach streams to circuits.}
3.12. POSTDESCRIPTOR
3.13. POSTDESCRIPTOR
Sent from the client to the server. The syntax is:
"+POSTDESCRIPTOR" CRLF Descriptor CRLF "." CRLF
@ -462,7 +475,7 @@ $Id$
why the server was not added. If the descriptor is added, Tor replies with
"250 OK".
3.13. REDIRECTSTREAM
3.14. REDIRECTSTREAM
Sent from the client to the server. The syntax is:
"REDIRECTSTREAM" SP StreamID SP Address (SP Port) CRLF
@ -477,7 +490,7 @@ $Id$
Tor replies with "250 OK" on success.
3.14. CLOSESTREAM
3.15. CLOSESTREAM
Sent from the client to the server. The syntax is:
@ -491,7 +504,7 @@ $Id$
Tor replies with "250 OK" on success, or a 512 if there aren't enough
arguments, or a 552 if it doesn't recognize the StreamID or reason.
3.15. CLOSECIRCUIT
3.16. CLOSECIRCUIT
The syntax is:
CLOSECIRCUIT SP CircuitID *(SP Flag) CRLF
@ -506,7 +519,7 @@ $Id$
Tor replies with "250 OK" on success, or a 512 if there aren't enough
arguments, or a 552 if it doesn't recognize the CircuitID.
3.16. QUIT
3.17. QUIT
Tells the server to hang up on this controller connection. This command
can be used before authenticating.

View File

@ -169,6 +169,8 @@ static int handle_control_getinfo(connection_t *conn, uint32_t len,
const char *body);
static int handle_control_extendcircuit(connection_t *conn, uint32_t len,
const char *body);
static int handle_control_setcircuitpurpose(connection_t *conn, uint32_t len,
const char *body);
static int handle_control_attachstream(connection_t *conn, uint32_t len,
const char *body);
static int handle_control_postdescriptor(connection_t *conn, uint32_t len,
@ -1541,6 +1543,25 @@ handle_control_getinfo(connection_t *conn, uint32_t len, const char *body)
return 0;
}
/** If <b>string</b> contains a recognized circuit purpose,
* possibly prefaced with the string "purpose=", then assign it
* and return 0. Otherwise return -1. */
static int
get_purpose(char *string, uint8_t *purpose)
{
if (!strcmpstart(string, "purpose="))
string += strlen("purpose=");
if (!strcmp(string, "general"))
*purpose = CIRCUIT_PURPOSE_C_GENERAL;
else if (!strcmp(string, "controller"))
*purpose = CIRCUIT_PURPOSE_CONTROLLER;
else { /* not a recognized purpose */
return -1;
}
return 0;
}
/** Called when we get an EXTENDCIRCUIT message. Try to extend the listed
* circuit, and report success or failure. */
static int
@ -1552,6 +1573,7 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len,
circuit_t *circ = NULL;
int zero_circ, v0;
char reply[4];
uint8_t intended_purpose = CIRCUIT_PURPOSE_C_GENERAL;
v0 = STATE_IS_V0(conn->state);
router_nicknames = smartlist_create();
@ -1600,6 +1622,13 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len,
if (!zero_circ && !circ) {
goto done;
}
if (zero_circ && smartlist_len(args)>2) {
if (get_purpose(smartlist_get(args,2), &intended_purpose) < 0) {
connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n",
(char *)smartlist_get(args,2));
goto done;
}
}
}
routers = smartlist_create();
@ -1625,7 +1654,7 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len,
if (zero_circ) {
/* start a new circuit */
circ = circuit_init(CIRCUIT_PURPOSE_C_GENERAL, 0, 0, 0);
circ = circuit_init(intended_purpose, 0, 0, 0);
}
/* now circ refers to something that is ready to be extended */
@ -1677,6 +1706,44 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len,
return 0;
}
/** Called when we get a SETCIRCUITPURPOSE message. If we can find
* the circuit and it's a valid purpose, change it. */
static int
handle_control_setcircuitpurpose(connection_t *conn, uint32_t len,
const char *body)
{
circuit_t *circ;
uint8_t new_purpose;
smartlist_t *args = smartlist_create();
smartlist_split_string(args, body, " ",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
if (smartlist_len(args)<2) {
connection_printf_to_buf(conn,
"512 Missing argument to SETCIRCUITPURPOSE\r\n");
goto done;
}
if (!(circ = get_circ(smartlist_get(args,0)))) {
connection_printf_to_buf(conn, "552 Unknown circuit \"%s\"\r\n",
(char*)smartlist_get(args, 0));
goto done;
}
if (get_purpose(smartlist_get(args,1), &new_purpose) < 0) {
connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n",
(char *)smartlist_get(args,1));
goto done;
}
circ->purpose = new_purpose;
connection_write_str_to_buf("250 OK\r\n", conn);
done:
SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
smartlist_free(args);
return 0;
}
/** Called when we get an ATTACHSTREAM message. Try to attach the requested
* stream, and report success or failure. */
static int
@ -2187,6 +2254,9 @@ connection_control_process_inbuf_v1(connection_t *conn)
} else if (!strcasecmp(conn->incoming_cmd, "EXTENDCIRCUIT")) {
if (handle_control_extendcircuit(conn, data_len, args))
return -1;
} else if (!strcasecmp(conn->incoming_cmd, "SETCIRCUITPURPOSE")) {
if (handle_control_setcircuitpurpose(conn, data_len, args))
return -1;
} else if (!strcasecmp(conn->incoming_cmd, "ATTACHSTREAM")) {
if (handle_control_attachstream(conn, data_len, args))
return -1;

View File

@ -423,7 +423,9 @@ typedef enum {
#define CIRCUIT_PURPOSE_S_REND_JOINED 16
/** A testing circuit; not meant to be used for actual traffic. */
#define CIRCUIT_PURPOSE_TESTING 17
#define _CIRCUIT_PURPOSE_MAX 17
/** A controller made this circuit and Tor should not use it. */
#define CIRCUIT_PURPOSE_CONTROLLER 18
#define _CIRCUIT_PURPOSE_MAX 18
/** True iff the circuit purpose <b>p</b> is for a circuit that
* originated at this node. */