Commit fixes for several pending tor core tasks: document all DOCDOCed functions; time out uncontrolled unattached streams; feed reasons to SOCKS5 (refactoring connection_ap_handshake_socks_reply in the process); change DirFetchPeriod/StatusFetchPeriod to have a special "Be smart" value.

svn:r3769
This commit is contained in:
Nick Mathewson 2005-03-17 12:38:37 +00:00
parent b5a7347db5
commit df9c8feac7
17 changed files with 208 additions and 98 deletions

View File

@ -38,7 +38,9 @@ N . Switch to libevent
o Implement patch, if so. o Implement patch, if so.
- Implement Tor side once patch is accepted. - Implement Tor side once patch is accepted.
o Check return from event_set, event_add, event_del. o Check return from event_set, event_add, event_del.
- Keep pushing to get a windows patch accepted. o Keep pushing to get a windows patch accepted.
- After about 26 March, check back with Niels; he should be back
by then.
Security: Security:
- Make sure logged info is "safe"ish. - Make sure logged info is "safe"ish.
@ -72,13 +74,13 @@ N . Implement pending controller features.
- EXTENDCIRCUIT - EXTENDCIRCUIT
R - revised circ selection stuff. R - revised circ selection stuff.
- Implement controller interface. - Implement controller interface.
. ATTACHSTREAM o ATTACHSTREAM
o Make streams have an 'unattached and not-automatically-attachable' o Make streams have an 'unattached and not-automatically-attachable'
state. ("Controller managed.") state. ("Controller managed.")
o Add support to put new streams into this state rather than try to o Add support to put new streams into this state rather than try to
attach them automatically. ("Hidden" config option.) attach them automatically. ("Hidden" config option.)
o Implement 'attach stream X to circuit Y' logic. o Implement 'attach stream X to circuit Y' logic.
- Time out never-attached streams. o Time out never-attached streams.
o If we never get a CONNECTED back, we should put the stream back in o If we never get a CONNECTED back, we should put the stream back in
CONTROLLER_WAIT, not in CIRCUIT_WAIT. CONTROLLER_WAIT, not in CIRCUIT_WAIT.
- Tests for new controller features - Tests for new controller features
@ -101,9 +103,9 @@ R o HTTPS proxy for OR CONNECT stuff. (For outgoing SSL connections to
(Turns out, if package_raw_inbuf fails, it *can't* send an end cell.) (Turns out, if package_raw_inbuf fails, it *can't* send an end cell.)
o Check for any place where we can close an edge connection without o Check for any place where we can close an edge connection without
sending an end; see if we should send an end. sending an end; see if we should send an end.
N . Feed end reason back into SOCK5 as reasonable. o Feed end reason back into SOCK5 as reasonable.
R o cache .foo.exit names better, or differently, or not. R o cache .foo.exit names better, or differently, or not.
N - make !advertised_server_mode() ORs fetch dirs less often. o make !advertised_server_mode() ORs fetch dirs less often.
N - Clean up NT service code even more. Document it. Enable it by default. N - Clean up NT service code even more. Document it. Enable it by default.
Make sure it works. Make sure it works.

View File

@ -346,8 +346,6 @@ the message.
3.15 ATTACHSTREAM (Type 0x000E) 3.15 ATTACHSTREAM (Type 0x000E)
[Proposal; not finalized]
Sent from the client to the server. The message body contains two fields: Sent from the client to the server. The message body contains two fields:
Stream ID [4 octets] Stream ID [4 octets]
Circuit ID [4 octets] Circuit ID [4 octets]
@ -367,8 +365,6 @@ the message.
3.16 POSTDESCRIPTOR (Type 0x000F) 3.16 POSTDESCRIPTOR (Type 0x000F)
[Proposal; not finalized]
Sent from the client to the server. The message body contains one field: Sent from the client to the server. The message body contains one field:
Descriptor [NUL-terminated string] Descriptor [NUL-terminated string]
@ -383,10 +379,8 @@ the message.
3.17 FRAGMENTHEADER (Type 0x0010) 3.17 FRAGMENTHEADER (Type 0x0010)
[Proposal; not finalized]
Sent in either direction. Used to encapsulate messages longer than 65535 Sent in either direction. Used to encapsulate messages longer than 65535
bytes long. bytes in length.
Underlying type [2 bytes] Underlying type [2 bytes]
Total Length [4 bytes] Total Length [4 bytes]
@ -403,10 +397,12 @@ the message.
3.18 FRAGMENT (Type 0x0011) 3.18 FRAGMENT (Type 0x0011)
[Proposal; not finalized]
Data [Entire message] Data [Entire message]
See FRAGMENTHEADER for more information
3.19
4. Implementation notes 4. Implementation notes
4.1. There are four ways we could authenticate, for now: 4.1. There are four ways we could authenticate, for now:

View File

@ -114,11 +114,14 @@ security.
\fBDirFetchPeriod \fR\fIN\fR \fBseconds\fR|\fBminutes\fR|\fBhours\fR|\fBdays\fR|\fBweeks\fP \fBDirFetchPeriod \fR\fIN\fR \fBseconds\fR|\fBminutes\fR|\fBhours\fR|\fBdays\fR|\fBweeks\fP
Every time the specified period elapses, Tor downloads a directory. Every time the specified period elapses, Tor downloads a directory.
A directory contains a signed list of all known servers as well as A directory contains a signed list of all known servers as well as
their current liveness status. (Default: 1 hour) their current liveness status. A value of "0 seconds" tells Tor to choose an
appropriate default. (Default: 1 hour for clients, 20 minutes for servers.)
.TP .TP
\fBStatusFetchPeriod \fR\fIN\fR \fBseconds\fR|\fBminutes\fR|\fBhours\fR|\fBdays\fR|\fBweeks\fP \fBStatusFetchPeriod \fR\fIN\fR \fBseconds\fR|\fBminutes\fR|\fBhours\fR|\fBdays\fR|\fBweeks\fP Every time the
Every time the specified period elapses, Tor downloads signed status specified period elapses, Tor downloads signed status information about the
information about the current state of known servers. (Default: 20 minutes.) current state of known servers. A value of "0 seconds" tells Tor to choose
an appropriate default. (Default: 30 minutes for clients, 15 minutes for
servers.) (Default: 20 minutes.)
.TP .TP
\fBRendPostPeriod \fR\fIN\fR \fBseconds\fR|\fBminutes\fR|\fBhours\fR|\fBdays\fR|\fBweeks\fP \fBRendPostPeriod \fR\fIN\fR \fBseconds\fR|\fBminutes\fR|\fBhours\fR|\fBdays\fR|\fBweeks\fP
Every time the specified period elapses, Tor uploads any rendezvous Every time the specified period elapses, Tor uploads any rendezvous

View File

@ -55,6 +55,9 @@ static void delete_log(logfile_t *victim);
static void close_log(logfile_t *victim); static void close_log(logfile_t *victim);
static int reset_log(logfile_t *lf); static int reset_log(logfile_t *lf);
/** Helper: Write the standard prefix for log lines to a
* <b>buf_len</b> character buffer in <b>buf</b>.
*/
static INLINE size_t static INLINE size_t
_log_prefix(char *buf, size_t buf_len, int severity) _log_prefix(char *buf, size_t buf_len, int severity)
{ {
@ -290,7 +293,8 @@ static void delete_log(logfile_t *victim) {
tor_free(victim); tor_free(victim);
} }
/** DOCDOC */ /** Helper: release system resources (but not memory) held by a single
* logfile_t. */
static void close_log(logfile_t *victim) static void close_log(logfile_t *victim)
{ {
if (victim->needs_close && victim->file) { if (victim->needs_close && victim->file) {
@ -304,7 +308,9 @@ static void close_log(logfile_t *victim)
} }
} }
/** DOCDOC */ /** Helper: reset a single logfile_t. For a file log, this involves
* closing and reopening the log, and maybe writing the version. For
* other log types, do nothing. */
static int reset_log(logfile_t *lf) static int reset_log(logfile_t *lf)
{ {
if (lf->needs_close) { if (lf->needs_close) {
@ -342,6 +348,11 @@ void add_temp_log(void)
logfiles->is_temporary = 1; logfiles->is_temporary = 1;
} }
/**
* Add a log handler to send messages of severity between
* <b>logLevelmin</b> and <b>logLevelMax</b> to the function
* <b>cb</b>.
*/
int add_callback_log(int loglevelMin, int loglevelMax, log_callback cb) int add_callback_log(int loglevelMin, int loglevelMax, log_callback cb)
{ {
logfile_t *lf; logfile_t *lf;
@ -437,11 +448,13 @@ int parse_log_level(const char *level) {
return -1; return -1;
} }
/** Return the string equivalent of a given log level. */
const char *log_level_to_string(int level) const char *log_level_to_string(int level)
{ {
return sev_to_string(level); return sev_to_string(level);
} }
/** Return the least severe log level that any current log is interested in. */
int get_min_log_level(void) int get_min_log_level(void)
{ {
logfile_t *lf; logfile_t *lf;

View File

@ -1288,6 +1288,10 @@ parse_addr_and_port_range(const char *s, uint32_t *addr_out,
return -1; return -1;
} }
/** Given an IPv4 address <b>in</b> (in network order, as usual),
* write it as a string into the <b>buf_len</b>-byte buffer in
* <b>buf</b>.
*/
int int
tor_inet_ntoa(struct in_addr *in, char *buf, size_t buf_len) tor_inet_ntoa(struct in_addr *in, char *buf, size_t buf_len)
{ {
@ -1299,7 +1303,8 @@ tor_inet_ntoa(struct in_addr *in, char *buf, size_t buf_len)
(int)(uint8_t)((a )&0xff)); (int)(uint8_t)((a )&0xff));
} }
/* DOCDOC */ /* Return true iff <b>name</b> looks like it might be a hostname or IP
* address of some kind. */
int int
is_plausible_address(const char *name) is_plausible_address(const char *name)
{ {
@ -1437,4 +1442,3 @@ void write_pidfile(char *filename) {
} }
#endif #endif
} }

View File

@ -183,7 +183,8 @@ circuit_free_cpath_node(crypt_path_t *victim) {
tor_free(victim); tor_free(victim);
} }
/** DOCDOC **/ /** Return the circuit whose global ID is <b>id</b>, or NULL if no
* such circuit exists. */
circuit_t * circuit_t *
circuit_get_by_global_id(uint32_t id) circuit_get_by_global_id(uint32_t id)
{ {

View File

@ -975,7 +975,9 @@ consider_recording_trackhost(connection_t *conn, circuit_t *circ) {
time(NULL) + options->TrackHostExitsExpire); time(NULL) + options->TrackHostExitsExpire);
} }
/* DOCDOC. Return as for connection_ap_handshake_attach_chosen_circuit. */ /** Attempt to attach the connection <b>conn</b> to <b>circ</b>, and
* send a begin or resolve cell as appropriate. Return values for
* connection_ap_handshake_attach_chosen_circuit. */
int int
connection_ap_handshake_attach_chosen_circuit(connection_t *conn, connection_ap_handshake_attach_chosen_circuit(connection_t *conn,
circuit_t *circ) circuit_t *circ)

View File

@ -108,9 +108,8 @@ static config_var_t config_vars[] = {
VAR("DirAllowPrivateAddresses",BOOL, DirAllowPrivateAddresses, NULL), VAR("DirAllowPrivateAddresses",BOOL, DirAllowPrivateAddresses, NULL),
VAR("DirPort", UINT, DirPort, "0"), VAR("DirPort", UINT, DirPort, "0"),
VAR("DirBindAddress", LINELIST, DirBindAddress, NULL), VAR("DirBindAddress", LINELIST, DirBindAddress, NULL),
/* XXX we'd like dirfetchperiod to be higher for people with dirport not /** DOCDOC **/
* set, but low for people with dirport set. how to have two defaults? */ VAR("DirFetchPeriod", INTERVAL, DirFetchPeriod, "0 seconds"),
VAR("DirFetchPeriod", INTERVAL, DirFetchPeriod, "1 hour"),
VAR("DirPostPeriod", INTERVAL, DirPostPeriod, "20 minutes"), VAR("DirPostPeriod", INTERVAL, DirPostPeriod, "20 minutes"),
VAR("RendPostPeriod", INTERVAL, RendPostPeriod, "20 minutes"), VAR("RendPostPeriod", INTERVAL, RendPostPeriod, "20 minutes"),
VAR("DirPolicy", LINELIST, DirPolicy, NULL), VAR("DirPolicy", LINELIST, DirPolicy, NULL),
@ -169,9 +168,8 @@ static config_var_t config_vars[] = {
VAR("SocksPort", UINT, SocksPort, "9050"), VAR("SocksPort", UINT, SocksPort, "9050"),
VAR("SocksBindAddress", LINELIST, SocksBindAddress, NULL), VAR("SocksBindAddress", LINELIST, SocksBindAddress, NULL),
VAR("SocksPolicy", LINELIST, SocksPolicy, NULL), VAR("SocksPolicy", LINELIST, SocksPolicy, NULL),
/* XXX as with dirfetchperiod, we want this to be 15 minutes for people /** DOCDOC */
* with a dirport open, but higher for people without a dirport open. */ VAR("StatusFetchPeriod", INTERVAL, StatusFetchPeriod, "0 seconds"),
VAR("StatusFetchPeriod", INTERVAL, StatusFetchPeriod, "15 minutes"),
VAR("SysLog", LINELIST_S, OldLogOptions, NULL), VAR("SysLog", LINELIST_S, OldLogOptions, NULL),
OBSOLETE("TrafficShaping"), OBSOLETE("TrafficShaping"),
VAR("User", STRING, User, NULL), VAR("User", STRING, User, NULL),
@ -1375,11 +1373,13 @@ options_validate(or_options_t *options)
#define MAX_CACHE_DIR_FETCH_PERIOD 3600 #define MAX_CACHE_DIR_FETCH_PERIOD 3600
#define MAX_CACHE_STATUS_FETCH_PERIOD 900 #define MAX_CACHE_STATUS_FETCH_PERIOD 900
if (options->DirFetchPeriod < MIN_DIR_FETCH_PERIOD) { if (options->DirFetchPeriod &&
options->DirFetchPeriod < MIN_DIR_FETCH_PERIOD) {
log(LOG_WARN, "DirFetchPeriod option must be at least %d seconds. Clipping.", MIN_DIR_FETCH_PERIOD); log(LOG_WARN, "DirFetchPeriod option must be at least %d seconds. Clipping.", MIN_DIR_FETCH_PERIOD);
options->DirFetchPeriod = MIN_DIR_FETCH_PERIOD; options->DirFetchPeriod = MIN_DIR_FETCH_PERIOD;
} }
if (options->StatusFetchPeriod < MIN_STATUS_FETCH_PERIOD) { if (options->StatusFetchPeriod &&
options->StatusFetchPeriod < MIN_STATUS_FETCH_PERIOD) {
log(LOG_WARN, "StatusFetchPeriod option must be at least %d seconds. Clipping.", MIN_STATUS_FETCH_PERIOD); log(LOG_WARN, "StatusFetchPeriod option must be at least %d seconds. Clipping.", MIN_STATUS_FETCH_PERIOD);
options->StatusFetchPeriod = MIN_STATUS_FETCH_PERIOD; options->StatusFetchPeriod = MIN_STATUS_FETCH_PERIOD;
} }

View File

@ -283,8 +283,7 @@ void connection_about_to_close_connection(connection_t *conn)
conn->hold_open_until_flushed = 1; conn->hold_open_until_flushed = 1;
/* XXX this socks_reply never gets sent, since conn /* XXX this socks_reply never gets sent, since conn
* gets removed right after this function finishes. */ * gets removed right after this function finishes. */
connection_ap_handshake_socks_reply(conn, NULL, 0, -1); connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_GENERAL_ERROR);
conn->socks_request->has_finished = 1;
} else { } else {
control_event_stream_status(conn, STREAM_EVENT_CLOSED); control_event_stream_status(conn, STREAM_EVENT_CLOSED);
} }

View File

@ -162,7 +162,10 @@ connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_layer)
return 0; return 0;
} }
/** DOCDOC **/ /** An error has just occured on an operation on an edge connection
* <b>conn</b>. Extract the errno; convert it to an end reason, and send
* an appropriate relay end cell to <b>cpath_layer</b>.
**/
int int
connection_edge_end_errno(connection_t *conn, crypt_path_t *cpath_layer) connection_edge_end_errno(connection_t *conn, crypt_path_t *cpath_layer)
{ {
@ -265,7 +268,15 @@ void connection_ap_expire_beginning(void) {
conn = carray[i]; conn = carray[i];
if (conn->type != CONN_TYPE_AP) if (conn->type != CONN_TYPE_AP)
continue; continue;
if (conn->state != AP_CONN_STATE_RESOLVE_WAIT && if (conn->state == AP_CONN_STATE_CONTROLLER_WAIT) {
if (now - conn->timestamp_lastread >= 120) {
log_fn(LOG_NOTICE, "Closing unattached stream.");
connection_mark_for_close(conn);
}
continue;
}
else if (conn->state != AP_CONN_STATE_RESOLVE_WAIT &&
conn->state != AP_CONN_STATE_CONNECT_WAIT) conn->state != AP_CONN_STATE_CONNECT_WAIT)
continue; continue;
if (now - conn->timestamp_lastread < 15) if (now - conn->timestamp_lastread < 15)
@ -338,17 +349,21 @@ void connection_ap_attach_pending(void)
} }
} }
/** DOCDOC /** The AP connection <b>conn</b> has just failed while attaching or
* -1 on err, 1 on success, 0 on not-yet-sure. * sending a BEGIN or resolving on <b>circ</b>, but another circuit
* might work. Detach the circuit, and either reattach it, launch a
* new circuit, tell the controller, or give up as a appropriate.
*
* Returns -1 on err, 1 on success, 0 on not-yet-sure.
*/ */
int int
connection_ap_detach_retriable(connection_t *conn, circuit_t *circ) connection_ap_detach_retriable(connection_t *conn, circuit_t *circ)
{ {
control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE); control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE);
conn->timestamp_lastread = time(NULL);
if (get_options()->ManageConnections) { if (get_options()->ManageConnections) {
conn->state = AP_CONN_STATE_CIRCUIT_WAIT; conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
circuit_detach_stream(circ,conn); circuit_detach_stream(circ,conn);
/* Muck with timestamps? */
return connection_ap_handshake_attach_circuit(conn); return connection_ap_handshake_attach_circuit(conn);
} else { } else {
conn->state = AP_CONN_STATE_CONTROLLER_WAIT; conn->state = AP_CONN_STATE_CONTROLLER_WAIT;
@ -678,7 +693,15 @@ addressmap_get_virtual_address(int type)
} }
} }
/* DOCDOC */ /** A controller has requested that we map some address of type
* <b>type</b> to the address <b>new_address</b>. Choose an address
* that is unlikely to be used, and map it, and return it in a newly
* allocated string. If another address of the same type is already
* mapped to <b>new_address</b>, try to return a copy of that address.
*
* The string in <b>new_address</b> may be freed, or inserted into a map
* as appropriate.
**/
char * char *
addressmap_register_virtual_address(int type, char *new_address) addressmap_register_virtual_address(int type, char *new_address)
{ {
@ -720,7 +743,7 @@ address_is_invalid_destination(const char *address) {
return 0; return 0;
} }
/* Iterate over all address mapings which have exipry times between /** Iterate over all address mapings which have exipry times between
* min_expires and max_expires, inclusive. If sl is provided, add an * min_expires and max_expires, inclusive. If sl is provided, add an
* "old-addr new-addr" string to sl for each mapping. If sl is NULL, * "old-addr new-addr" string to sl for each mapping. If sl is NULL,
* remove the mappings. * remove the mappings.
@ -779,19 +802,23 @@ static int connection_ap_handshake_process_socks(connection_t *conn) {
log_fn(LOG_DEBUG,"entered."); log_fn(LOG_DEBUG,"entered.");
sockshere = fetch_from_buf_socks(conn->inbuf, socks); sockshere = fetch_from_buf_socks(conn->inbuf, socks);
if (sockshere == -1 || sockshere == 0) { if (sockshere == 0) {
if (socks->replylen) { /* we should send reply back */ if (socks->replylen) {
log_fn(LOG_DEBUG,"reply is already set for us. Using it."); connection_write_to_buf(socks->reply, socks->replylen, conn);
connection_ap_handshake_socks_reply(conn, socks->reply, socks->replylen, 0);
socks->replylen = 0; /* zero it out so we can do another round of negotiation */
} else if (sockshere == -1) { /* send normal reject */
log_fn(LOG_WARN,"Fetching socks handshake failed. Closing.");
connection_ap_handshake_socks_reply(conn, NULL, 0, -1);
} else { } else {
log_fn(LOG_DEBUG,"socks handshake not all here yet."); log_fn(LOG_DEBUG,"socks handshake not all here yet.");
} }
if (sockshere == -1) return 0;
socks->has_finished = 1; } else if (sockshere == -1) {
if (socks->replylen) { /* we should send reply back */
log_fn(LOG_DEBUG,"reply is already set for us. Using it.");
connection_ap_handshake_socks_reply(conn, socks->reply, socks->replylen,
SOCKS5_GENERAL_ERROR);
socks->replylen = 0; /* zero it out so we can do another round of negotiation */
} else {
log_fn(LOG_WARN,"Fetching socks handshake failed. Closing.");
connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_GENERAL_ERROR);
}
return sockshere; return sockshere;
} /* else socks handshake is done, continue processing */ } /* else socks handshake is done, continue processing */
@ -1080,7 +1107,11 @@ int connection_ap_make_bridge(char *address, uint16_t port) {
return fd[1]; return fd[1];
} }
/* DOCDOC */ /** Send an answer to an AP connection that has requested a DNS lookup
* via SOCKS. The type should be one of RESOLVED_TYPE_(IPV4|IPV6) or
* -1 for unreachable; the answer should be in the format specified
* in the socks extensions document.
**/
void connection_ap_handshake_socks_resolved(connection_t *conn, void connection_ap_handshake_socks_resolved(connection_t *conn,
int answer_type, int answer_type,
size_t answer_len, size_t answer_len,
@ -1132,15 +1163,15 @@ void connection_ap_handshake_socks_resolved(connection_t *conn,
} }
} }
connection_ap_handshake_socks_reply(conn, buf, replylen, connection_ap_handshake_socks_reply(conn, buf, replylen,
(answer_type == RESOLVED_TYPE_IPV4 || (answer_type == RESOLVED_TYPE_IPV4 ||
answer_type == RESOLVED_TYPE_IPV6) ? 1 : -1); answer_type == RESOLVED_TYPE_IPV6) ?
SOCKS5_SUCCEEDED : SOCKS5_HOST_UNREACHABLE);
conn->socks_request->has_finished = 1; conn->socks_request->has_finished = 1;
} }
/** Send a socks reply to stream <b>conn</b>, using the appropriate /** Send a socks reply to stream <b>conn</b>, using the appropriate
* socks version, etc. * socks version, etc, and mark <b>conn</b> as completed with SOCKS
* * handshaking.
* Status can be 1 (succeeded), -1 (failed), or 0 (not sure yet).
* *
* If <b>reply</b> is defined, then write <b>replylen</b> bytes of it * If <b>reply</b> is defined, then write <b>replylen</b> bytes of it
* to conn and return, else reply based on <b>status</b>. * to conn and return, else reply based on <b>status</b>.
@ -1148,32 +1179,34 @@ void connection_ap_handshake_socks_resolved(connection_t *conn,
* If <b>reply</b> is undefined, <b>status</b> can't be 0. * If <b>reply</b> is undefined, <b>status</b> can't be 0.
*/ */
void connection_ap_handshake_socks_reply(connection_t *conn, char *reply, void connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
size_t replylen, int status) { size_t replylen,
socks5_reply_status_t status) {
char buf[256]; char buf[256];
if (status) /* it's either 1 or -1 */ control_event_stream_status(conn,
control_event_stream_status(conn, status==SOCKS5_SUCCEEDED ? STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED);
status==1 ? STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED);
if (replylen) { /* we already have a reply in mind */ tor_assert(conn->socks_request);
connection_write_to_buf(reply, replylen, conn); if (conn->socks_request->has_finished) {
log_fn(LOG_WARN, "Harmless bug: duplicate calls to connection_ap_handshake_socks_reply.");
return;
}
if (replylen) { /* we already have a reply in mind */
connection_write_to_buf(reply, replylen, conn);
conn->socks_request->has_finished = 1;
return; return;
} }
tor_assert(conn->socks_request);
tor_assert(status == 1 || status == -1);
if (conn->socks_request->socks_version == 4) { if (conn->socks_request->socks_version == 4) {
memset(buf,0,SOCKS4_NETWORK_LEN); memset(buf,0,SOCKS4_NETWORK_LEN);
#define SOCKS4_GRANTED 90 #define SOCKS4_GRANTED 90
#define SOCKS4_REJECT 91 #define SOCKS4_REJECT 91
buf[1] = (status==1 ? SOCKS4_GRANTED : SOCKS4_REJECT); buf[1] = (status==SOCKS5_SUCCEEDED ? SOCKS4_GRANTED : SOCKS4_REJECT);
/* leave version, destport, destip zero */ /* leave version, destport, destip zero */
connection_write_to_buf(buf, SOCKS4_NETWORK_LEN, conn); connection_write_to_buf(buf, SOCKS4_NETWORK_LEN, conn);
} }
if (conn->socks_request->socks_version == 5) { if (conn->socks_request->socks_version == 5) {
buf[0] = 5; /* version 5 */ buf[0] = 5; /* version 5 */
#define SOCKS5_SUCCESS 0 buf[1] = (char)status;
#define SOCKS5_GENERIC_ERROR 1
buf[1] = status==1 ? SOCKS5_SUCCESS : SOCKS5_GENERIC_ERROR;
buf[2] = 0; buf[2] = 0;
buf[3] = 1; /* ipv4 addr */ buf[3] = 1; /* ipv4 addr */
memset(buf+4,0,6); /* Set external addr/port to 0. memset(buf+4,0,6); /* Set external addr/port to 0.
@ -1182,6 +1215,7 @@ void connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
} }
/* If socks_version isn't 4 or 5, don't send anything. /* If socks_version isn't 4 or 5, don't send anything.
* This can happen in the case of AP bridges. */ * This can happen in the case of AP bridges. */
conn->socks_request->has_finished = 1;
return; return;
} }

View File

@ -926,7 +926,10 @@ control_event_logmsg(int severity, const char *msg)
send_control_event(EVENT_WARNING, (uint32_t)(len+1), msg); send_control_event(EVENT_WARNING, (uint32_t)(len+1), msg);
} }
/** DOCDOC */ /** Called whenever we receive new router descriptors: tell any
* interested control connections. <b>routers</b> is a list of
* DIGEST_LEN-byte identity digests.
*/
int control_event_descriptors_changed(smartlist_t *routers) int control_event_descriptors_changed(smartlist_t *routers)
{ {
size_t len; size_t len;

View File

@ -195,7 +195,7 @@ static void connection_unlink(connection_t *conn, int remove) {
connection_free(conn); connection_free(conn);
} }
/** DOCDOC **/ /** Schedule <b>conn</b> to be closed. **/
void void
add_connection_to_closeable_list(connection_t *conn) add_connection_to_closeable_list(connection_t *conn)
{ {
@ -318,7 +318,7 @@ void connection_start_writing(connection_t *conn) {
(int)conn->s); (int)conn->s);
} }
/** DOCDOC */ /** Close all connections that have been schedule to get closed */
static void static void
close_closeable_connections(void) close_closeable_connections(void)
{ {
@ -337,7 +337,8 @@ close_closeable_connections(void)
} }
} }
/** DOCDOC */ /** Libevent callback: this gets invoked when (connection_t*)<b>conn</b> has
* some data to read. */
static void static void
conn_read_callback(int fd, short event, void *_conn) conn_read_callback(int fd, short event, void *_conn)
{ {
@ -371,6 +372,8 @@ conn_read_callback(int fd, short event, void *_conn)
close_closeable_connections(); close_closeable_connections();
} }
/** Libevent callback: this gets invoked when (connection_t*)<b>conn</b> has
* some data to write. */
static void conn_write_callback(int fd, short events, void *_conn) static void conn_write_callback(int fd, short events, void *_conn)
{ {
connection_t *conn = _conn; connection_t *conn = _conn;
@ -512,7 +515,6 @@ static void conn_write(int i) {
* - Otherwise, remove the connection from connection_array and from * - Otherwise, remove the connection from connection_array and from
* all other lists, close it, and free it. * all other lists, close it, and free it.
* Returns 1 if the connection was closed, 0 otherwise. * Returns 1 if the connection was closed, 0 otherwise.
* DOCDOC closeable_list
*/ */
static int conn_close_if_marked(int i) { static int conn_close_if_marked(int i) {
connection_t *conn; connection_t *conn;
@ -580,6 +582,35 @@ void directory_all_unreachable(time_t now) {
} }
} }
INLINE int
get_dir_fetch_period(or_options_t *options)
{
if (options->DirFetchPeriod)
/* Value from config file. */
return options->DirFetchPeriod;
else if (options->DirPort)
/* Default for directory server */
return 20*60;
else
/* Default for average user. */
return 40*60;
}
INLINE int
get_status_fetch_period(or_options_t *options)
{
if (options->StatusFetchPeriod)
/* Value from config file. */
return options->StatusFetchPeriod;
else if (options->DirPort)
/* Default for directory server */
return 15*60;
else
/* Default for average user. */
return 30*60;
}
/** This function is called whenever we successfully pull down a directory. /** This function is called whenever we successfully pull down a directory.
* If <b>identity_digest</b> is defined, it contains the digest of the * If <b>identity_digest</b> is defined, it contains the digest of the
* router that just gave us this directory. */ * router that just gave us this directory. */
@ -593,13 +624,13 @@ void directory_has_arrived(time_t now, char *identity_digest) {
* after the directory we had when we started. * after the directory we had when we started.
*/ */
if (!time_to_fetch_directory) if (!time_to_fetch_directory)
time_to_fetch_directory = now + options->DirFetchPeriod; time_to_fetch_directory = now + get_dir_fetch_period(options);
if (!time_to_force_upload_descriptor) if (!time_to_force_upload_descriptor)
time_to_force_upload_descriptor = now + options->DirPostPeriod; time_to_force_upload_descriptor = now + options->DirPostPeriod;
if (!time_to_fetch_running_routers) if (!time_to_fetch_running_routers)
time_to_fetch_running_routers = now + options->StatusFetchPeriod; time_to_fetch_running_routers = now + get_status_fetch_period(options);
if (identity_digest) { /* if this is us, then our dirport is reachable */ if (identity_digest) { /* if this is us, then our dirport is reachable */
routerinfo_t *router = router_get_by_digest(identity_digest); routerinfo_t *router = router_get_by_digest(identity_digest);
@ -720,6 +751,7 @@ static void run_scheduled_events(time_t now) {
* new running-routers list, and/or force-uploading our descriptor * new running-routers list, and/or force-uploading our descriptor
* (if we've passed our internal checks). */ * (if we've passed our internal checks). */
if (time_to_fetch_directory < now) { if (time_to_fetch_directory < now) {
time_t next_status_fetch;
/* purge obsolete entries */ /* purge obsolete entries */
routerlist_remove_old_routers(ROUTER_MAX_AGE); routerlist_remove_old_routers(ROUTER_MAX_AGE);
@ -734,9 +766,10 @@ static void run_scheduled_events(time_t now) {
} }
directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 1); directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 1);
time_to_fetch_directory = now + options->DirFetchPeriod; time_to_fetch_directory = now + get_dir_fetch_period(options);
if (time_to_fetch_running_routers < now + options->StatusFetchPeriod) { next_status_fetch = now + get_status_fetch_period(options);
time_to_fetch_running_routers = now + options->StatusFetchPeriod; if (time_to_fetch_running_routers < next_status_fetch) {
time_to_fetch_running_routers = next_status_fetch;
} }
/* Also, take this chance to remove old information from rephist. */ /* Also, take this chance to remove old information from rephist. */
@ -747,7 +780,7 @@ static void run_scheduled_events(time_t now) {
if (!authdir_mode(options)) { if (!authdir_mode(options)) {
directory_get_from_dirserver(DIR_PURPOSE_FETCH_RUNNING_LIST, NULL, 1); directory_get_from_dirserver(DIR_PURPOSE_FETCH_RUNNING_LIST, NULL, 1);
} }
time_to_fetch_running_routers = now + options->StatusFetchPeriod; time_to_fetch_running_routers = now + get_status_fetch_period(options);
} }
if (time_to_force_upload_descriptor < now) { if (time_to_force_upload_descriptor < now) {
@ -816,7 +849,7 @@ static void run_scheduled_events(time_t now) {
close_closeable_connections(); close_closeable_connections();
} }
/** DOCDOC */ /** Libevent callback: invoked once every second. */
static void second_elapsed_callback(int fd, short event, void *args) static void second_elapsed_callback(int fd, short event, void *args)
{ {
static struct event *timeout_event = NULL; static struct event *timeout_event = NULL;

View File

@ -700,8 +700,7 @@ typedef struct {
*/ */
time_t published_on; time_t published_on;
time_t running_routers_updated_on; time_t running_routers_updated_on;
/** DOCDOC /** What is the most recently received running_routers structure? */
*/
running_routers_t *running_routers; running_routers_t *running_routers;
/** Which router is claimed to have signed it? */ /** Which router is claimed to have signed it? */
char *signing_router; char *signing_router;
@ -1308,7 +1307,8 @@ int connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ)
int connection_ap_make_bridge(char *address, uint16_t port); int connection_ap_make_bridge(char *address, uint16_t port);
void connection_ap_handshake_socks_reply(connection_t *conn, char *reply, void connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
size_t replylen, int status); size_t replylen,
socks5_reply_status_t status);
void connection_ap_handshake_socks_resolved(connection_t *conn, void connection_ap_handshake_socks_resolved(connection_t *conn,
int answer_type, int answer_type,
size_t answer_len, size_t answer_len,

View File

@ -481,8 +481,11 @@ connection_edge_end_reason_str(char *payload, uint16_t length) {
} }
} }
socks5_reply_status_t /** Translate the <b>payload</b> of length <b>length</b>, which
connection_edge_end_reason_sock5_response(char *payload, uint16_t length) { * came from a relay 'end' cell, into an appropriate SOCKS5 reply code.
*/
static socks5_reply_status_t
connection_edge_end_reason_socks5_response(char *payload, uint16_t length) {
if (length < 1) { if (length < 1) {
log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1."); log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1.");
return SOCKS5_GENERAL_ERROR; return SOCKS5_GENERAL_ERROR;
@ -641,8 +644,6 @@ connection_edge_process_relay_cell_not_open(
circuit_log_path(LOG_INFO,circ); circuit_log_path(LOG_INFO,circ);
tor_assert(circ->timestamp_dirty); tor_assert(circ->timestamp_dirty);
circ->timestamp_dirty -= get_options()->MaxCircuitDirtiness; circ->timestamp_dirty -= get_options()->MaxCircuitDirtiness;
/* make sure not to expire/retry the stream quite yet */
conn->timestamp_lastread = time(NULL);
if (connection_ap_detach_retriable(conn, circ) >= 0) if (connection_ap_detach_retriable(conn, circ) >= 0)
return 0; return 0;
@ -685,8 +686,7 @@ connection_edge_process_relay_cell_not_open(
conn->chosen_exit_name); conn->chosen_exit_name);
} }
circuit_log_path(LOG_INFO,circ); circuit_log_path(LOG_INFO,circ);
connection_ap_handshake_socks_reply(conn, NULL, 0, 1); connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_SUCCEEDED);
conn->socks_request->has_finished = 1;
/* handle anything that might have queued */ /* handle anything that might have queued */
if (connection_edge_package_raw_inbuf(conn, 1) < 0) { if (connection_edge_package_raw_inbuf(conn, 1) < 0) {
/* (We already sent an end cell if possible) */ /* (We already sent an end cell if possible) */
@ -821,7 +821,12 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
connection_edge_end_reason_str(cell->payload+RELAY_HEADER_SIZE, connection_edge_end_reason_str(cell->payload+RELAY_HEADER_SIZE,
rh.length), rh.length),
conn->stream_id, (int)conn->stream_size); conn->stream_id, (int)conn->stream_size);
if (conn->socks_request && !conn->socks_request->has_finished) {
socks5_reply_status_t status =
connection_edge_end_reason_socks5_response(
cell->payload+RELAY_HEADER_SIZE, rh.length);
connection_ap_handshake_socks_reply(conn, NULL, 0, status);
}
#ifdef HALF_OPEN #ifdef HALF_OPEN
conn->done_sending = 1; conn->done_sending = 1;
shutdown(conn->s, 1); /* XXX check return; refactor NM */ shutdown(conn->s, 1); /* XXX check return; refactor NM */

View File

@ -57,6 +57,9 @@ crypto_pk_env_t *get_previous_onion_key(void) {
return lastonionkey; return lastonionkey;
} }
/** Store a copy of the current onion key into *<b>key</b>, and a copy
* of the most recent onion key into *<b>last</b>.
*/
void dup_onion_keys(crypto_pk_env_t **key, crypto_pk_env_t **last) void dup_onion_keys(crypto_pk_env_t **key, crypto_pk_env_t **last)
{ {
tor_assert(key); tor_assert(key);
@ -516,6 +519,8 @@ void router_retry_connections(void) {
} }
} }
/** Return true iff this OR should try to keep connections open to all
* other ORs. */
int router_is_clique_mode(routerinfo_t *router) { int router_is_clique_mode(routerinfo_t *router) {
if (router_digest_is_trusted_dir(router->identity_digest)) if (router_digest_is_trusted_dir(router->identity_digest))
return 1; return 1;
@ -533,8 +538,9 @@ static int desc_is_dirty = 1;
/** Boolean: do we need to regenerate the above? */ /** Boolean: do we need to regenerate the above? */
static int desc_needs_upload = 0; static int desc_needs_upload = 0;
/** OR only: try to upload our signed descriptor to all the directory servers /** OR only: If <b>force</b> is true, or we haven't uploaded this
* we know about. DOCDOC force * descriptor successfully yet, try to upload our signed descriptor to
* all the directory servers we know about.
*/ */
void router_upload_dir_desc_to_dirservers(int force) { void router_upload_dir_desc_to_dirservers(int force) {
const char *s; const char *s;
@ -630,8 +636,9 @@ const char *router_get_my_descriptor(void) {
return desc_routerinfo->signed_descriptor; return desc_routerinfo->signed_descriptor;
} }
/** Rebuild a fresh routerinfo and signed server descriptor for this /** If <b>force</b> is true, or our descriptor is out-of-date, rebuild
* OR. Return 0 on success, -1 on error. DOCDOC force * a fresh routerinfo and signed server descriptor for this OR.
* Return 0 on success, -1 on error.
*/ */
int router_rebuild_descriptor(int force) { int router_rebuild_descriptor(int force) {
routerinfo_t *ri; routerinfo_t *ri;
@ -694,7 +701,7 @@ int router_rebuild_descriptor(int force) {
return 0; return 0;
} }
/** DOCDOC */ /** Call when the current descriptor is out of date. */
void void
mark_my_descriptor_dirty(void) mark_my_descriptor_dirty(void)
{ {
@ -919,6 +926,7 @@ int router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
return written+1; return written+1;
} }
/** Return true iff <b>s</b> is a legally valid server nickname. */
int is_legal_nickname(const char *s) int is_legal_nickname(const char *s)
{ {
size_t len; size_t len;
@ -927,6 +935,8 @@ int is_legal_nickname(const char *s)
return len > 0 && len <= MAX_NICKNAME_LEN && return len > 0 && len <= MAX_NICKNAME_LEN &&
strspn(s,LEGAL_NICKNAME_CHARACTERS)==len; strspn(s,LEGAL_NICKNAME_CHARACTERS)==len;
} }
/** Return true iff <b>s</b> is a legally valid server nickname or
* hex-encoded identity-key digest. */
int is_legal_nickname_or_hexdigest(const char *s) int is_legal_nickname_or_hexdigest(const char *s)
{ {
size_t len; size_t len;
@ -938,6 +948,7 @@ int is_legal_nickname_or_hexdigest(const char *s)
return len == HEX_DIGEST_LEN+1 && strspn(s+1,HEX_CHARACTERS)==len-1; return len == HEX_DIGEST_LEN+1 && strspn(s+1,HEX_CHARACTERS)==len-1;
} }
/** Release all resources held in router keys. */
void router_free_all_keys(void) void router_free_all_keys(void)
{ {
if (onionkey) if (onionkey)

View File

@ -1192,7 +1192,8 @@ void running_routers_free(running_routers_t *rr)
tor_free(rr); tor_free(rr);
} }
/** DOCDOC*/ /** We've just got a running routers list in <b>rr</b>; update the
* status of the routers in <b>list</b>, and cache <b>rr</b> */
void void
routerlist_set_runningrouters(routerlist_t *list, running_routers_t *rr) routerlist_set_runningrouters(routerlist_t *list, running_routers_t *rr)
{ {
@ -1389,6 +1390,7 @@ add_trusted_dir_server(const char *address, uint16_t port, const char *digest)
smartlist_add(trusted_dir_servers, ent); smartlist_add(trusted_dir_servers, ent);
} }
/** Remove all members from the list of trusted dir servers. */
void clear_trusted_dir_servers(void) void clear_trusted_dir_servers(void)
{ {
if (trusted_dir_servers) { if (trusted_dir_servers) {

View File

@ -541,7 +541,9 @@ router_parse_routerlist_from_directory(const char *str,
return r; return r;
} }
/* DOCDOC */ /** Read a signed router status statement from <b>str</b>. On
* success, return it, and cache the original string if
* <b>write_to_cache</b> is set. Otherwise, return NULL. */
running_routers_t * running_routers_t *
router_parse_runningrouters(const char *str, int write_to_cache) router_parse_runningrouters(const char *str, int write_to_cache)
{ {