mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 13:13:44 +01:00
introduced a periodic keepalive padding cell
now tor can be run safely inside nat'ed areas that kill idle connections; and the proxy can handle when you suspend your laptop and then emerge hours later from a new domain. svn:r125
This commit is contained in:
parent
293e049a89
commit
7ed6c8bd39
@ -99,6 +99,8 @@ RETURN VALUE: 0 on success, non-zero on error
|
|||||||
0, "how many seconds between directory rebuilds", "<rebuildperiod>" },
|
0, "how many seconds between directory rebuilds", "<rebuildperiod>" },
|
||||||
{ "DirFetchPeriod", 'F', POPT_ARG_INT, &options->DirFetchPeriod,
|
{ "DirFetchPeriod", 'F', POPT_ARG_INT, &options->DirFetchPeriod,
|
||||||
0, "how many seconds between directory fetches", "<fetchperiod>" },
|
0, "how many seconds between directory fetches", "<fetchperiod>" },
|
||||||
|
{ "KeepalivePeriod", 'K', POPT_ARG_INT, &options->KeepalivePeriod,
|
||||||
|
0, "how many seconds between keepalives", "<keepaliveperiod>" },
|
||||||
// { "ReconnectPeriod", 'e', POPT_ARG_INT, &options->ReconnectPeriod,
|
// { "ReconnectPeriod", 'e', POPT_ARG_INT, &options->ReconnectPeriod,
|
||||||
// 0, "how many seconds between retrying all OR connections", "<reconnectperiod>" },
|
// 0, "how many seconds between retrying all OR connections", "<reconnectperiod>" },
|
||||||
{ "Role", 'R', POPT_ARG_INT, &options->Role,
|
{ "Role", 'R', POPT_ARG_INT, &options->Role,
|
||||||
@ -122,6 +124,7 @@ RETURN VALUE: 0 on success, non-zero on error
|
|||||||
options->LinkPadding = 0;
|
options->LinkPadding = 0;
|
||||||
options->DirRebuildPeriod = 600;
|
options->DirRebuildPeriod = 600;
|
||||||
options->DirFetchPeriod = 6000;
|
options->DirFetchPeriod = 6000;
|
||||||
|
options->KeepalivePeriod = 300;
|
||||||
// options->ReconnectPeriod = 6001;
|
// options->ReconnectPeriod = 6001;
|
||||||
options->Role = ROLE_OR_LISTEN | ROLE_OR_CONNECT_ALL | ROLE_OP_LISTEN | ROLE_AP_LISTEN;
|
options->Role = ROLE_OR_LISTEN | ROLE_OR_CONNECT_ALL | ROLE_OP_LISTEN | ROLE_AP_LISTEN;
|
||||||
|
|
||||||
@ -170,9 +173,10 @@ RETURN VALUE: 0 on success, non-zero on error
|
|||||||
options->MaxConn,
|
options->MaxConn,
|
||||||
options->TrafficShaping,
|
options->TrafficShaping,
|
||||||
options->LinkPadding);
|
options->LinkPadding);
|
||||||
printf("DirRebuildPeriod=%d, DirFetchPeriod=%d\n",
|
printf("DirRebuildPeriod=%d, DirFetchPeriod=%d KeepalivePeriod=%d\n",
|
||||||
options->DirRebuildPeriod,
|
options->DirRebuildPeriod,
|
||||||
options->DirFetchPeriod);
|
options->DirFetchPeriod,
|
||||||
|
options->KeepalivePeriod);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Validate options */
|
/* Validate options */
|
||||||
@ -287,6 +291,12 @@ RETURN VALUE: 0 on success, non-zero on error
|
|||||||
code = -1;
|
code = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( options->KeepalivePeriod < 1)
|
||||||
|
{
|
||||||
|
log(LOG_ERR,"KeepalivePeriod option must be positive.");
|
||||||
|
code = -1;
|
||||||
|
}
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,6 +86,10 @@ void tv_addms(struct timeval *a, long ms) {
|
|||||||
|
|
||||||
connection_t *connection_new(int type) {
|
connection_t *connection_new(int type) {
|
||||||
connection_t *conn;
|
connection_t *conn;
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
|
if(gettimeofday(&now,NULL) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
conn = (connection_t *)malloc(sizeof(connection_t));
|
conn = (connection_t *)malloc(sizeof(connection_t));
|
||||||
if(!conn)
|
if(!conn)
|
||||||
@ -99,6 +103,7 @@ connection_t *connection_new(int type) {
|
|||||||
|
|
||||||
conn->receiver_bucket = 10240; /* should be enough to do the handshake */
|
conn->receiver_bucket = 10240; /* should be enough to do the handshake */
|
||||||
conn->bandwidth = conn->receiver_bucket / 10; /* give it a default */
|
conn->bandwidth = conn->receiver_bucket / 10; /* give it a default */
|
||||||
|
conn->timestamp_created = now.tv_sec;
|
||||||
|
|
||||||
if (connection_speaks_cells(conn)) {
|
if (connection_speaks_cells(conn)) {
|
||||||
conn->f_crypto = crypto_new_cipher_env(CRYPTO_CIPHER_DES);
|
conn->f_crypto = crypto_new_cipher_env(CRYPTO_CIPHER_DES);
|
||||||
@ -320,6 +325,7 @@ connection_t *connection_connect_to_router_as_op(routerinfo_t *router, uint16_t
|
|||||||
|
|
||||||
int connection_read_to_buf(connection_t *conn) {
|
int connection_read_to_buf(connection_t *conn) {
|
||||||
int read_result;
|
int read_result;
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
if(connection_speaks_cells(conn)) {
|
if(connection_speaks_cells(conn)) {
|
||||||
assert(conn->receiver_bucket >= 0);
|
assert(conn->receiver_bucket >= 0);
|
||||||
@ -327,6 +333,11 @@ int connection_read_to_buf(connection_t *conn) {
|
|||||||
if(!connection_speaks_cells(conn)) {
|
if(!connection_speaks_cells(conn)) {
|
||||||
assert(conn->receiver_bucket < 0);
|
assert(conn->receiver_bucket < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(gettimeofday(&now,NULL) < 0)
|
||||||
|
return -1;
|
||||||
|
conn->timestamp_lastread = now.tv_sec;
|
||||||
|
|
||||||
read_result = read_to_buf(conn->s, conn->receiver_bucket, &conn->inbuf, &conn->inbuflen,
|
read_result = read_to_buf(conn->s, conn->receiver_bucket, &conn->inbuf, &conn->inbuflen,
|
||||||
&conn->inbuf_datalen, &conn->inbuf_reached_eof);
|
&conn->inbuf_datalen, &conn->inbuf_reached_eof);
|
||||||
// log(LOG_DEBUG,"connection_read_to_buf(): read_to_buf returned %d.",read_result);
|
// log(LOG_DEBUG,"connection_read_to_buf(): read_to_buf returned %d.",read_result);
|
||||||
@ -369,9 +380,16 @@ int connection_flush_buf(connection_t *conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int connection_write_to_buf(char *string, int len, connection_t *conn) {
|
int connection_write_to_buf(char *string, int len, connection_t *conn) {
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
|
if(gettimeofday(&now,NULL) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if(!len)
|
if(!len)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
conn->timestamp_lastwritten = now.tv_sec;
|
||||||
|
|
||||||
if( (!connection_speaks_cells(conn)) ||
|
if( (!connection_speaks_cells(conn)) ||
|
||||||
(!connection_state_is_open(conn)) ||
|
(!connection_state_is_open(conn)) ||
|
||||||
(options.LinkPadding == 0) ) {
|
(options.LinkPadding == 0) ) {
|
||||||
|
@ -310,20 +310,11 @@ int prepare_for_poll(int *timeout) {
|
|||||||
connection_t *conn = NULL;
|
connection_t *conn = NULL;
|
||||||
connection_t *tmpconn;
|
connection_t *tmpconn;
|
||||||
struct timeval now, soonest;
|
struct timeval now, soonest;
|
||||||
static int current_second = 0; /* from previous calls to gettimeofday */
|
static long current_second = 0; /* from previous calls to gettimeofday */
|
||||||
static int time_to_rebuild_directory = 0;
|
static long time_to_rebuild_directory = 0;
|
||||||
static int time_to_fetch_directory = 0;
|
static long time_to_fetch_directory = 0;
|
||||||
int ms_until_conn;
|
int ms_until_conn;
|
||||||
|
cell_t cell;
|
||||||
*timeout = -1; /* set it to never timeout, possibly overridden below */
|
|
||||||
|
|
||||||
/* first check if we need to refill buckets */
|
|
||||||
for(i=0;i<nfds;i++) {
|
|
||||||
if(connection_receiver_bucket_should_increase(connection_array[i])) {
|
|
||||||
need_to_refill_buckets = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(gettimeofday(&now,NULL) < 0)
|
if(gettimeofday(&now,NULL) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
@ -356,6 +347,50 @@ int prepare_for_poll(int *timeout) {
|
|||||||
*timeout = 1000*(time_to_fetch_directory - now.tv_sec) + (1000 - (now.tv_usec / 1000));
|
*timeout = 1000*(time_to_fetch_directory - now.tv_sec) + (1000 - (now.tv_usec / 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check connections to see whether we should send a keepalive, expire, or wait */
|
||||||
|
for(i=0;i<nfds;i++) {
|
||||||
|
tmpconn = connection_array[i];
|
||||||
|
if(!connection_speaks_cells(tmpconn))
|
||||||
|
continue; /* this conn type doesn't send cells */
|
||||||
|
if(!connection_state_is_open(tmpconn)) {
|
||||||
|
continue; /* only conns in state 'open' need a keepalive */
|
||||||
|
/* XXX should time-out unfinished connections someday too */
|
||||||
|
}
|
||||||
|
if(now.tv_sec >= tmpconn->timestamp_lastwritten + options.KeepalivePeriod) {
|
||||||
|
if(!(options.Role & ROLE_OR_CONNECT_ALL) && !circuit_get_by_conn(tmpconn)) {
|
||||||
|
/* we're an onion proxy, with no circuits. kill it. */
|
||||||
|
log(LOG_DEBUG,"prepare_for_poll(): Expiring connection to %d (%s:%d).",
|
||||||
|
i,tmpconn->address, tmpconn->port);
|
||||||
|
tmpconn->marked_for_close = 1;
|
||||||
|
} else {
|
||||||
|
/* either a full router, or we've got a circuit. send a padding cell. */
|
||||||
|
// log(LOG_DEBUG,"prepare_for_poll(): Sending keepalive to (%s:%d)",
|
||||||
|
// tmpconn->address, tmpconn->port);
|
||||||
|
memset(&cell,0,sizeof(cell_t));
|
||||||
|
cell.command = CELL_PADDING;
|
||||||
|
connection_write_cell_to_buf(&cell, tmpconn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!tmpconn->marked_for_close &&
|
||||||
|
*timeout > 1000*(tmpconn->timestamp_lastwritten + options.KeepalivePeriod - now.tv_sec)) {
|
||||||
|
*timeout = 1000*(tmpconn->timestamp_lastwritten + options.KeepalivePeriod - now.tv_sec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(*timeout >= 0);
|
||||||
|
/* blow away any connections that need to die. can't do this later
|
||||||
|
* because we might open up a circuit and not realize it.
|
||||||
|
*/
|
||||||
|
for(i=0;i<nfds;i++)
|
||||||
|
check_conn_marked(i);
|
||||||
|
|
||||||
|
/* check if we need to refill buckets */
|
||||||
|
for(i=0;i<nfds;i++) {
|
||||||
|
if(connection_receiver_bucket_should_increase(connection_array[i])) {
|
||||||
|
need_to_refill_buckets = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(need_to_refill_buckets) {
|
if(need_to_refill_buckets) {
|
||||||
if(now.tv_sec > current_second) { /* the second has already rolled over! */
|
if(now.tv_sec > current_second) { /* the second has already rolled over! */
|
||||||
// log(LOG_DEBUG,"prepare_for_poll(): The second has rolled over, immediately refilling.");
|
// log(LOG_DEBUG,"prepare_for_poll(): The second has rolled over, immediately refilling.");
|
||||||
@ -363,7 +398,7 @@ int prepare_for_poll(int *timeout) {
|
|||||||
connection_increment_receiver_bucket(connection_array[i]);
|
connection_increment_receiver_bucket(connection_array[i]);
|
||||||
current_second = now.tv_sec; /* remember which second it is, for next time */
|
current_second = now.tv_sec; /* remember which second it is, for next time */
|
||||||
}
|
}
|
||||||
/* this timeout is definitely sooner than either of the above two */
|
/* this timeout is definitely sooner than any of the above ones */
|
||||||
*timeout = 1000 - (now.tv_usec / 1000); /* how many milliseconds til the next second? */
|
*timeout = 1000 - (now.tv_usec / 1000); /* how many milliseconds til the next second? */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,7 +429,7 @@ int prepare_for_poll(int *timeout) {
|
|||||||
ms_until_conn = (soonest.tv_sec - now.tv_sec)*1000 +
|
ms_until_conn = (soonest.tv_sec - now.tv_sec)*1000 +
|
||||||
(soonest.tv_usec - now.tv_usec)/1000;
|
(soonest.tv_usec - now.tv_usec)/1000;
|
||||||
// log(LOG_DEBUG,"prepare_for_poll(): conn %d times out in %d ms.",conn->s, ms_until_conn);
|
// log(LOG_DEBUG,"prepare_for_poll(): conn %d times out in %d ms.",conn->s, ms_until_conn);
|
||||||
if(*timeout == -1 || ms_until_conn < *timeout) { /* use the new one */
|
if(ms_until_conn < *timeout) { /* use the new one */
|
||||||
// log(LOG_DEBUG,"prepare_for_poll(): conn %d soonest, in %d ms.",conn->s,ms_until_conn);
|
// log(LOG_DEBUG,"prepare_for_poll(): conn %d soonest, in %d ms.",conn->s,ms_until_conn);
|
||||||
*timeout = ms_until_conn;
|
*timeout = ms_until_conn;
|
||||||
}
|
}
|
||||||
@ -517,18 +552,25 @@ static void catch(int the_signal) {
|
|||||||
void dumpstats (void) { /* dump stats to stdout */
|
void dumpstats (void) { /* dump stats to stdout */
|
||||||
int i;
|
int i;
|
||||||
connection_t *conn;
|
connection_t *conn;
|
||||||
|
struct timeval now;
|
||||||
extern char *conn_type_to_string[];
|
extern char *conn_type_to_string[];
|
||||||
extern char *conn_state_to_string[][15];
|
extern char *conn_state_to_string[][15];
|
||||||
|
|
||||||
printf("Dumping stats:\n");
|
printf("Dumping stats:\n");
|
||||||
|
if(gettimeofday(&now,NULL) < 0)
|
||||||
|
return ;
|
||||||
|
|
||||||
for(i=0;i<nfds;i++) {
|
for(i=0;i<nfds;i++) {
|
||||||
conn = connection_array[i];
|
conn = connection_array[i];
|
||||||
printf("Conn %d (socket %d) type %d (%s), state %d (%s)\n",
|
printf("Conn %d (socket %d) type %d (%s), state %d (%s), created %ld secs ago\n",
|
||||||
i, conn->s, conn->type, conn_type_to_string[conn->type],
|
i, conn->s, conn->type, conn_type_to_string[conn->type],
|
||||||
conn->state, conn_state_to_string[conn->type][conn->state]);
|
conn->state, conn_state_to_string[conn->type][conn->state], now.tv_sec - conn->timestamp_created);
|
||||||
if(!connection_is_listener(conn)) {
|
if(!connection_is_listener(conn)) {
|
||||||
printf("Conn %d is to '%s:%d'.\n",i,conn->address, conn->port);
|
printf("Conn %d is to '%s:%d'.\n",i,conn->address, conn->port);
|
||||||
|
printf("Conn %d: %d bytes waiting on inbuf (last read %ld secs ago)\n",i,conn->inbuf_datalen,
|
||||||
|
now.tv_sec - conn->timestamp_lastread);
|
||||||
|
printf("Conn %d: %d bytes waiting on outbuf (last written %ld secs ago)\n",i,conn->outbuf_datalen,
|
||||||
|
now.tv_sec - conn->timestamp_lastwritten);
|
||||||
}
|
}
|
||||||
circuit_dump_by_conn(conn); /* dump info about all the circuits using this conn */
|
circuit_dump_by_conn(conn); /* dump info about all the circuits using this conn */
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
@ -188,11 +188,15 @@ typedef struct
|
|||||||
int inbuflen;
|
int inbuflen;
|
||||||
int inbuf_datalen;
|
int inbuf_datalen;
|
||||||
int inbuf_reached_eof;
|
int inbuf_reached_eof;
|
||||||
|
long timestamp_lastread;
|
||||||
|
|
||||||
char *outbuf;
|
char *outbuf;
|
||||||
int outbuflen; /* how many bytes are allocated for the outbuf? */
|
int outbuflen; /* how many bytes are allocated for the outbuf? */
|
||||||
int outbuf_flushlen; /* how much data should we try to flush from the outbuf? */
|
int outbuf_flushlen; /* how much data should we try to flush from the outbuf? */
|
||||||
int outbuf_datalen; /* how much data is there total on the outbuf? */
|
int outbuf_datalen; /* how much data is there total on the outbuf? */
|
||||||
|
long timestamp_lastwritten;
|
||||||
|
|
||||||
|
long timestamp_created;
|
||||||
|
|
||||||
// uint16_t aci; /* anonymous connection identifier */
|
// uint16_t aci; /* anonymous connection identifier */
|
||||||
|
|
||||||
@ -357,6 +361,7 @@ typedef struct
|
|||||||
int LinkPadding;
|
int LinkPadding;
|
||||||
int DirRebuildPeriod;
|
int DirRebuildPeriod;
|
||||||
int DirFetchPeriod;
|
int DirFetchPeriod;
|
||||||
|
int KeepalivePeriod;
|
||||||
int Role;
|
int Role;
|
||||||
int loglevel;
|
int loglevel;
|
||||||
} or_options_t;
|
} or_options_t;
|
||||||
|
Loading…
Reference in New Issue
Block a user