mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-23 20:03:31 +01:00
directory servers in and functional
proxies now periodically pull down an hourly-updated directory, and replace their router list with it if it parses correctly. svn:r112
This commit is contained in:
parent
d6360c57bc
commit
01f6727306
@ -9,7 +9,7 @@ or_LDADD = -L../common -lor
|
|||||||
|
|
||||||
or_SOURCES = buffers.c cell.c circuit.c command.c connection.c \
|
or_SOURCES = buffers.c cell.c circuit.c command.c connection.c \
|
||||||
connection_exit.c connection_ap.c connection_op.c connection_or.c config.c \
|
connection_exit.c connection_ap.c connection_op.c connection_or.c config.c \
|
||||||
main.c onion.c routers.c
|
main.c onion.c routers.c directory.c
|
||||||
|
|
||||||
test_config_SOURCES = test_config.c
|
test_config_SOURCES = test_config.c
|
||||||
|
|
||||||
|
@ -85,6 +85,8 @@ RETURN VALUE: 0 on success, non-zero on error
|
|||||||
0, "onion proxy port", "<port>" },
|
0, "onion proxy port", "<port>" },
|
||||||
{ "ORPort", 'p', POPT_ARG_INT, &options->ORPort,
|
{ "ORPort", 'p', POPT_ARG_INT, &options->ORPort,
|
||||||
0, "onion router port", "<port>" },
|
0, "onion router port", "<port>" },
|
||||||
|
{ "DirPort", 'd', POPT_ARG_INT, &options->DirPort,
|
||||||
|
0, "directory server port", "<port>" },
|
||||||
{ "PrivateKeyFile", 'k', POPT_ARG_STRING, &options->PrivateKeyFile,
|
{ "PrivateKeyFile", 'k', POPT_ARG_STRING, &options->PrivateKeyFile,
|
||||||
0, "maximum number of incoming connections", "<file>" },
|
0, "maximum number of incoming connections", "<file>" },
|
||||||
{ "RouterFile", 'r', POPT_ARG_STRING, &options->RouterFile,
|
{ "RouterFile", 'r', POPT_ARG_STRING, &options->RouterFile,
|
||||||
@ -92,8 +94,14 @@ RETURN VALUE: 0 on success, non-zero on error
|
|||||||
{ "TrafficShaping", 't', POPT_ARG_INT, &options->TrafficShaping,
|
{ "TrafficShaping", 't', POPT_ARG_INT, &options->TrafficShaping,
|
||||||
0, "which traffic shaping policy to use", "<policy>" },
|
0, "which traffic shaping policy to use", "<policy>" },
|
||||||
{ "LinkPadding", 'P', POPT_ARG_INT, &options->LinkPadding,
|
{ "LinkPadding", 'P', POPT_ARG_INT, &options->LinkPadding,
|
||||||
0, "whether to use link padding", "<padding>" },
|
0, "whether to use link padding", "<padding>" },
|
||||||
{ "Role", 'g', POPT_ARG_INT, &options->Role,
|
{ "DirRebuildPeriod",'D', POPT_ARG_INT, &options->DirRebuildPeriod,
|
||||||
|
0, "how many seconds between directory rebuilds", "<rebuildperiod>" },
|
||||||
|
{ "DirFetchPeriod", 'F', POPT_ARG_INT, &options->DirFetchPeriod,
|
||||||
|
0, "how many seconds between directory fetches", "<fetchperiod>" },
|
||||||
|
// { "ReconnectPeriod", 'e', POPT_ARG_INT, &options->ReconnectPeriod,
|
||||||
|
// 0, "how many seconds between retrying all OR connections", "<reconnectperiod>" },
|
||||||
|
{ "Role", 'R', POPT_ARG_INT, &options->Role,
|
||||||
0, "4-bit global role id", "<role>" },
|
0, "4-bit global role id", "<role>" },
|
||||||
{ "Verbose", 'v', POPT_ARG_NONE, &Verbose,
|
{ "Verbose", 'v', POPT_ARG_NONE, &Verbose,
|
||||||
0, "display options selected before execution", NULL },
|
0, "display options selected before execution", NULL },
|
||||||
@ -112,7 +120,11 @@ RETURN VALUE: 0 on success, non-zero on error
|
|||||||
options->loglevel = LOG_DEBUG;
|
options->loglevel = LOG_DEBUG;
|
||||||
options->CoinWeight = 0.8;
|
options->CoinWeight = 0.8;
|
||||||
options->LinkPadding = 0;
|
options->LinkPadding = 0;
|
||||||
options->Role = ROLE_OR_LISTEN | ROLE_OR_CONNECT_ALL | ROLE_OP_LISTEN | ROLE_AP_LISTEN;
|
options->DirRebuildPeriod = 600;
|
||||||
|
options->DirFetchPeriod = 6000;
|
||||||
|
// options->ReconnectPeriod = 6001;
|
||||||
|
options->Role = ROLE_OR_LISTEN | ROLE_OR_CONNECT_ALL | ROLE_OP_LISTEN | ROLE_AP_LISTEN |
|
||||||
|
ROLE_DIR_LISTEN | ROLE_DIR_SERVER;
|
||||||
|
|
||||||
code = poptGetNextOpt(optCon); /* first we handle command-line args */
|
code = poptGetNextOpt(optCon); /* first we handle command-line args */
|
||||||
if ( code == -1 )
|
if ( code == -1 )
|
||||||
@ -151,14 +163,17 @@ RETURN VALUE: 0 on success, non-zero on error
|
|||||||
printf("RouterFile=%s, PrivateKeyFile=%s\n",
|
printf("RouterFile=%s, PrivateKeyFile=%s\n",
|
||||||
options->RouterFile,
|
options->RouterFile,
|
||||||
options->PrivateKeyFile);
|
options->PrivateKeyFile);
|
||||||
printf("ORPort=%d, OPPort=%d, APPort=%d\n",
|
printf("ORPort=%d, OPPort=%d, APPort=%d DirPort=%d\n",
|
||||||
options->ORPort,options->OPPort,
|
options->ORPort,options->OPPort,
|
||||||
options->APPort);
|
options->APPort,options->DirPort);
|
||||||
printf("CoinWeight=%6.4f, MaxConn=%d, TrafficShaping=%d, LinkPadding=%d\n",
|
printf("CoinWeight=%6.4f, MaxConn=%d, TrafficShaping=%d, LinkPadding=%d\n",
|
||||||
options->CoinWeight,
|
options->CoinWeight,
|
||||||
options->MaxConn,
|
options->MaxConn,
|
||||||
options->TrafficShaping,
|
options->TrafficShaping,
|
||||||
options->LinkPadding);
|
options->LinkPadding);
|
||||||
|
printf("DirRebuildPeriod=%d, DirFetchPeriod=%d\n",
|
||||||
|
options->DirRebuildPeriod,
|
||||||
|
options->DirFetchPeriod);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Validate options */
|
/* Validate options */
|
||||||
@ -188,9 +203,9 @@ RETURN VALUE: 0 on success, non-zero on error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( options->Role < 0 || options->Role > 15 )
|
if ( options->Role < 0 || options->Role > 63 )
|
||||||
{
|
{
|
||||||
log(LOG_ERR,"Role option must be an integer between 0 and 15 (inclusive).");
|
log(LOG_ERR,"Role option must be an integer between 0 and 63 (inclusive).");
|
||||||
code = -1;
|
code = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,6 +239,12 @@ RETURN VALUE: 0 on success, non-zero on error
|
|||||||
code = -1;
|
code = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( (options->Role & ROLE_DIR_LISTEN) && options->DirPort < 1 )
|
||||||
|
{
|
||||||
|
log(LOG_ERR,"DirPort option required and must be a positive integer value.");
|
||||||
|
code = -1;
|
||||||
|
}
|
||||||
|
|
||||||
if ( (options->Role & ROLE_AP_LISTEN) &&
|
if ( (options->Role & ROLE_AP_LISTEN) &&
|
||||||
(options->CoinWeight < 0.0 || options->CoinWeight >= 1.0) )
|
(options->CoinWeight < 0.0 || options->CoinWeight >= 1.0) )
|
||||||
{
|
{
|
||||||
@ -255,6 +276,18 @@ RETURN VALUE: 0 on success, non-zero on error
|
|||||||
code = -1;
|
code = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( options->DirRebuildPeriod < 1)
|
||||||
|
{
|
||||||
|
log(LOG_ERR,"DirRebuildPeriod option must be positive.");
|
||||||
|
code = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( options->DirFetchPeriod < 1)
|
||||||
|
{
|
||||||
|
log(LOG_ERR,"DirFetchPeriod option must be positive.");
|
||||||
|
code = -1;
|
||||||
|
}
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,10 +16,12 @@ char *conn_type_to_string[] = {
|
|||||||
"OR", /* 4 */
|
"OR", /* 4 */
|
||||||
"Exit", /* 5 */
|
"Exit", /* 5 */
|
||||||
"App listener",/* 6 */
|
"App listener",/* 6 */
|
||||||
"App" /* 7 */
|
"App", /* 7 */
|
||||||
|
"Dir listener",/* 8 */
|
||||||
|
"Dir", /* 9 */
|
||||||
};
|
};
|
||||||
|
|
||||||
char *conn_state_to_string[][10] = {
|
char *conn_state_to_string[][15] = {
|
||||||
{ }, /* no type associated with 0 */
|
{ }, /* no type associated with 0 */
|
||||||
{ "ready" }, /* op listener, 0 */
|
{ "ready" }, /* op listener, 0 */
|
||||||
{ "awaiting keys", /* op, 0 */
|
{ "awaiting keys", /* op, 0 */
|
||||||
@ -43,7 +45,13 @@ char *conn_state_to_string[][10] = {
|
|||||||
{ "ready" }, /* app listener, 0 */
|
{ "ready" }, /* app listener, 0 */
|
||||||
{ "awaiting dest info", /* app, 0 */
|
{ "awaiting dest info", /* app, 0 */
|
||||||
"waiting for OR connection", /* 1 */
|
"waiting for OR connection", /* 1 */
|
||||||
"open" } /* 2 */
|
"open" }, /* 2 */
|
||||||
|
{ "ready" }, /* dir listener, 0 */
|
||||||
|
{ "connecting", /* 0 */
|
||||||
|
"sending command", /* 1 */
|
||||||
|
"reading", /* 2 */
|
||||||
|
"awaiting command", /* 3 */
|
||||||
|
"writing" }, /* 4 */
|
||||||
};
|
};
|
||||||
|
|
||||||
/********* END VARIABLES ************/
|
/********* END VARIABLES ************/
|
||||||
@ -261,27 +269,20 @@ static int learn_local(struct sockaddr_in *local) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int retry_all_connections(int role, routerinfo_t **router_array, int rarray_len,
|
int retry_all_connections(int role, crypto_pk_env_t *prkey, uint16_t or_listenport,
|
||||||
crypto_pk_env_t *prkey, uint16_t or_listenport, uint16_t op_listenport, uint16_t ap_listenport) {
|
uint16_t op_listenport, uint16_t ap_listenport, uint16_t dir_listenport) {
|
||||||
|
|
||||||
/* start all connections that should be up but aren't */
|
/* start all connections that should be up but aren't */
|
||||||
|
|
||||||
routerinfo_t *router;
|
|
||||||
int i;
|
|
||||||
struct sockaddr_in local; /* local address */
|
struct sockaddr_in local; /* local address */
|
||||||
|
|
||||||
if(learn_local(&local) < 0)
|
if(learn_local(&local) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
local.sin_port = htons(or_listenport);
|
local.sin_port = htons(or_listenport);
|
||||||
|
|
||||||
if(role & ROLE_OR_CONNECT_ALL) {
|
if(role & ROLE_OR_CONNECT_ALL) {
|
||||||
for (i=0;i<rarray_len;i++) {
|
router_retry_connections(prkey, &local);
|
||||||
router = router_array[i];
|
|
||||||
if(!connection_exact_get_by_addr_port(router->addr,router->or_port)) { /* not in the list */
|
|
||||||
log(LOG_DEBUG,"retry_all_connections(): connecting to OR %s:%u.",router->address,router->or_port);
|
|
||||||
connection_or_connect_as_or(router, prkey, &local);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(role & ROLE_OR_LISTEN) {
|
if(role & ROLE_OR_LISTEN) {
|
||||||
@ -303,6 +304,13 @@ int retry_all_connections(int role, routerinfo_t **router_array, int rarray_len,
|
|||||||
connection_ap_create_listener(NULL, &local); /* no need to tell it the private key. */
|
connection_ap_create_listener(NULL, &local); /* no need to tell it the private key. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(role & ROLE_DIR_LISTEN) {
|
||||||
|
local.sin_port = htons(dir_listenport);
|
||||||
|
if(!connection_get_by_type(CONN_TYPE_DIR_LISTENER)) {
|
||||||
|
connection_dir_create_listener(NULL, &local); /* no need to tell it the private key. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -415,7 +423,8 @@ int connection_speaks_cells(connection_t *conn) {
|
|||||||
int connection_is_listener(connection_t *conn) {
|
int connection_is_listener(connection_t *conn) {
|
||||||
if(conn->type == CONN_TYPE_OP_LISTENER ||
|
if(conn->type == CONN_TYPE_OP_LISTENER ||
|
||||||
conn->type == CONN_TYPE_OR_LISTENER ||
|
conn->type == CONN_TYPE_OR_LISTENER ||
|
||||||
conn->type == CONN_TYPE_AP_LISTENER)
|
conn->type == CONN_TYPE_AP_LISTENER ||
|
||||||
|
conn->type == CONN_TYPE_DIR_LISTENER)
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -586,6 +595,8 @@ int connection_process_inbuf(connection_t *conn) {
|
|||||||
return connection_exit_process_inbuf(conn);
|
return connection_exit_process_inbuf(conn);
|
||||||
case CONN_TYPE_AP:
|
case CONN_TYPE_AP:
|
||||||
return connection_ap_process_inbuf(conn);
|
return connection_ap_process_inbuf(conn);
|
||||||
|
case CONN_TYPE_DIR:
|
||||||
|
return connection_dir_process_inbuf(conn);
|
||||||
default:
|
default:
|
||||||
log(LOG_DEBUG,"connection_process_inbuf() got unexpected conn->type.");
|
log(LOG_DEBUG,"connection_process_inbuf() got unexpected conn->type.");
|
||||||
return -1;
|
return -1;
|
||||||
@ -709,6 +720,8 @@ int connection_finished_flushing(connection_t *conn) {
|
|||||||
return connection_or_finished_flushing(conn);
|
return connection_or_finished_flushing(conn);
|
||||||
case CONN_TYPE_EXIT:
|
case CONN_TYPE_EXIT:
|
||||||
return connection_exit_finished_flushing(conn);
|
return connection_exit_finished_flushing(conn);
|
||||||
|
case CONN_TYPE_DIR:
|
||||||
|
return connection_dir_finished_flushing(conn);
|
||||||
default:
|
default:
|
||||||
log(LOG_DEBUG,"connection_finished_flushing() got unexpected conn->type.");
|
log(LOG_DEBUG,"connection_finished_flushing() got unexpected conn->type.");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -179,8 +179,8 @@ int connection_exit_process_data_cell(cell_t *cell, connection_t *conn) {
|
|||||||
/* also, deliver a 'connected' cell back through the circuit. */
|
/* also, deliver a 'connected' cell back through the circuit. */
|
||||||
return connection_exit_send_connected(conn);
|
return connection_exit_send_connected(conn);
|
||||||
} else {
|
} else {
|
||||||
log(LOG_DEBUG,"connection_exit_process_data_cell(): in connecting_wait, but I've already received everything. Closing.");
|
log(LOG_DEBUG,"connection_exit_process_data_cell(): in connecting_wait, but I've already received everything. Closing.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
case EXIT_CONN_STATE_CONNECTING:
|
case EXIT_CONN_STATE_CONNECTING:
|
||||||
|
@ -66,7 +66,7 @@ int connection_or_finished_flushing(connection_t *conn) {
|
|||||||
if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, &e, &len) < 0) { /* not yet */
|
if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, &e, &len) < 0) { /* not yet */
|
||||||
if(errno != EINPROGRESS){
|
if(errno != EINPROGRESS){
|
||||||
/* yuck. kill it. */
|
/* yuck. kill it. */
|
||||||
log(LOG_DEBUG,"connection_or_finished_flushing(): in-progress connect failed. Removing.");
|
log(LOG_DEBUG,"connection_or_finished_flushing(): in-progress connect failed. Removing.");
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
return 0; /* no change, see if next time is better */
|
return 0; /* no change, see if next time is better */
|
||||||
|
250
src/or/directory.c
Normal file
250
src/or/directory.c
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
/* Copyright 2001,2002 Roger Dingledine, Matej Pfaêfar. */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
/* $Id$ */
|
||||||
|
|
||||||
|
#include "or.h"
|
||||||
|
|
||||||
|
#define MAX_DIR_SIZE 50000 /* XXX, big enough? */
|
||||||
|
|
||||||
|
/********* START VARIABLES **********/
|
||||||
|
|
||||||
|
extern or_options_t options; /* command-line and config-file options */
|
||||||
|
|
||||||
|
static char the_directory[MAX_DIR_SIZE+1];
|
||||||
|
static int directorylen=0;
|
||||||
|
|
||||||
|
static char getstring[] = "GET / HTTP/1.0\n\r";
|
||||||
|
|
||||||
|
/********* END VARIABLES ************/
|
||||||
|
|
||||||
|
void directory_initiate_fetch(routerinfo_t *router) {
|
||||||
|
connection_t *conn;
|
||||||
|
struct sockaddr_in router_addr;
|
||||||
|
int s;
|
||||||
|
|
||||||
|
log(LOG_DEBUG,"directory_initiate_fetch(): initiating directory fetch");
|
||||||
|
|
||||||
|
if(!router) /* i guess they didn't have one in mind for me to use */
|
||||||
|
return;
|
||||||
|
|
||||||
|
conn = connection_new(CONN_TYPE_DIR);
|
||||||
|
if(!conn)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* set up conn so it's got all the data we need to remember */
|
||||||
|
conn->addr = router->addr, conn->port = router->or_port; /* NOTE we store or_port here always */
|
||||||
|
conn->address = strdup(router->address);
|
||||||
|
conn->receiver_bucket = -1; /* edge connections don't do receiver buckets */
|
||||||
|
conn->bandwidth = -1;
|
||||||
|
|
||||||
|
s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
|
||||||
|
if (s < 0)
|
||||||
|
{
|
||||||
|
log(LOG_ERR,"directory_initiate_fetch(): Error creating network socket.");
|
||||||
|
connection_free(conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fcntl(s, F_SETFL, O_NONBLOCK); /* set s to non-blocking */
|
||||||
|
|
||||||
|
memset((void *)&router_addr,0,sizeof(router_addr));
|
||||||
|
router_addr.sin_family = AF_INET;
|
||||||
|
router_addr.sin_port = htons(router->dir_port);
|
||||||
|
router_addr.sin_addr.s_addr = router->addr;
|
||||||
|
|
||||||
|
log(LOG_DEBUG,"directory_initiate_fetch(): Trying to connect to %s:%u.",inet_ntoa(*(struct in_addr *)&router->addr),router->dir_port);
|
||||||
|
|
||||||
|
if(connect(s,(struct sockaddr *)&router_addr,sizeof(router_addr)) < 0){
|
||||||
|
if(errno != EINPROGRESS){
|
||||||
|
/* yuck. kill it. */
|
||||||
|
connection_free(conn);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
/* it's in progress. set state appropriately and return. */
|
||||||
|
conn->s = s;
|
||||||
|
|
||||||
|
if(connection_add(conn) < 0) { /* no space, forget it */
|
||||||
|
connection_free(conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log(LOG_DEBUG,"directory_initiate_fetch(): connect in progress.");
|
||||||
|
connection_watch_events(conn, POLLIN | POLLOUT); /* writable indicates finish, readable indicates broken link */
|
||||||
|
conn->state = DIR_CONN_STATE_CONNECTING;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* it succeeded. we're connected. */
|
||||||
|
conn->s = s;
|
||||||
|
|
||||||
|
if(connection_add(conn) < 0) { /* no space, forget it */
|
||||||
|
connection_free(conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log(LOG_DEBUG,"directory_initiate_fetch(): Connection to router %s:%u established.",router->address,router->dir_port);
|
||||||
|
|
||||||
|
if(directory_send_command(conn) < 0) {
|
||||||
|
connection_remove(conn);
|
||||||
|
connection_free(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int directory_send_command(connection_t *conn) {
|
||||||
|
|
||||||
|
assert(conn && conn->type == CONN_TYPE_DIR);
|
||||||
|
|
||||||
|
if(connection_write_to_buf(getstring, strlen(getstring), conn) < 0) {
|
||||||
|
log(LOG_DEBUG,"directory_send_command(): Couldn't write command to buffer.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->state = DIR_CONN_STATE_SENDING_COMMAND;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void directory_rebuild(void) {
|
||||||
|
|
||||||
|
dump_directory_to_string(the_directory, MAX_DIR_SIZE);
|
||||||
|
log(LOG_DEBUG,"New directory:\n'%s'",the_directory);
|
||||||
|
directorylen = strlen(the_directory);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int connection_dir_process_inbuf(connection_t *conn) {
|
||||||
|
|
||||||
|
assert(conn && conn->type == CONN_TYPE_DIR);
|
||||||
|
|
||||||
|
if(conn->inbuf_reached_eof) {
|
||||||
|
if(conn->state != DIR_CONN_STATE_READING) {
|
||||||
|
log(LOG_DEBUG,"connection_dir_process_inbuf(): conn reached eof, not reading. Closing.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* eof reached, kill it, but first process the_directory and learn about new routers. */
|
||||||
|
log(LOG_DEBUG,"connection_dir_process_inbuf(): conn reached eof. Processing directory.");
|
||||||
|
log(LOG_DEBUG,"connection_dir_process_inbuf(): Received directory (size %d) '%s'", directorylen, the_directory);
|
||||||
|
if(directorylen == 0) {
|
||||||
|
log(LOG_DEBUG,"connection_dir_process_inbuf(): Empty directory. Ignoring.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(router_get_list_from_string(the_directory, options.ORPort) < 0) {
|
||||||
|
log(LOG_DEBUG,"connection_dir_process_inbuf(): ...but parsing failed. Ignoring.");
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(conn->state) {
|
||||||
|
case DIR_CONN_STATE_COMMAND_WAIT:
|
||||||
|
return directory_handle_command(conn);
|
||||||
|
case DIR_CONN_STATE_READING:
|
||||||
|
return directory_handle_reading(conn);
|
||||||
|
default:
|
||||||
|
log(LOG_DEBUG,"connection_dir_process_inbuf(): Got data while writing; Ignoring.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int directory_handle_command(connection_t *conn) {
|
||||||
|
|
||||||
|
assert(conn && conn->type == CONN_TYPE_DIR);
|
||||||
|
|
||||||
|
if(conn->inbuf_datalen < strlen(getstring)) { /* entire response available? */
|
||||||
|
log(LOG_DEBUG,"directory_handle_command(): Entire command not here yet. Waiting.");
|
||||||
|
return 0; /* not yet */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for now, don't bother reading it. */
|
||||||
|
|
||||||
|
if(directorylen == 0) {
|
||||||
|
log(LOG_DEBUG,"directory_handle_command(): My directory is empty. Closing.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
log(LOG_DEBUG,"directory_handle_command(): Dumping directory to client.");
|
||||||
|
if(connection_write_to_buf(the_directory, directorylen, conn) < 0) {
|
||||||
|
log(LOG_DEBUG,"directory_handle_command(): my outbuf is full. Oops.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->state = DIR_CONN_STATE_WRITING;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int directory_handle_reading(connection_t *conn) {
|
||||||
|
int amt;
|
||||||
|
|
||||||
|
assert(conn && conn->type == CONN_TYPE_DIR);
|
||||||
|
|
||||||
|
amt = conn->inbuf_datalen;
|
||||||
|
|
||||||
|
if(amt + directorylen >= MAX_DIR_SIZE) {
|
||||||
|
log(LOG_DEBUG,"directory_handle_reading(): Directory too large. Failing messily.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
log(LOG_DEBUG,"directory_handle_reading(): Pulling %d bytes in at offset %d.",
|
||||||
|
amt, directorylen);
|
||||||
|
|
||||||
|
if(connection_fetch_from_buf(the_directory+directorylen,amt,conn) < 0) {
|
||||||
|
log(LOG_DEBUG,"directory_handle_reading(): fetch_from_buf failed.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
directorylen += amt;
|
||||||
|
|
||||||
|
the_directory[directorylen] = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int connection_dir_finished_flushing(connection_t *conn) {
|
||||||
|
int e, len=sizeof(e);
|
||||||
|
|
||||||
|
assert(conn && conn->type == CONN_TYPE_DIR);
|
||||||
|
|
||||||
|
switch(conn->state) {
|
||||||
|
case DIR_CONN_STATE_CONNECTING:
|
||||||
|
if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, &e, &len) < 0) { /* not yet */
|
||||||
|
if(errno != EINPROGRESS){
|
||||||
|
/* yuck. kill it. */
|
||||||
|
log(LOG_DEBUG,"connection_dir_finished_flushing(): in-progress connect failed. Removing.");
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 0; /* no change, see if next time is better */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* the connect has finished. */
|
||||||
|
|
||||||
|
log(LOG_DEBUG,"connection_dir_finished_flushing(): DIR connection to router %s:%u established.",
|
||||||
|
conn->address,conn->port);
|
||||||
|
|
||||||
|
return directory_send_command(conn);
|
||||||
|
case DIR_CONN_STATE_SENDING_COMMAND:
|
||||||
|
log(LOG_DEBUG,"connection_dir_finished_flushing(): client finished sending command.");
|
||||||
|
directorylen = 0;
|
||||||
|
conn->state = DIR_CONN_STATE_READING;
|
||||||
|
connection_watch_events(conn, POLLIN);
|
||||||
|
return 0;
|
||||||
|
case DIR_CONN_STATE_WRITING:
|
||||||
|
log(LOG_DEBUG,"connection_dir_finished_flushing(): Finished writing directory. Closing.");
|
||||||
|
return -1; /* kill it */
|
||||||
|
default:
|
||||||
|
log(LOG_DEBUG,"Bug: connection_dir_finished_flushing() called in unexpected state.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int connection_dir_create_listener(crypto_pk_env_t *prkey, struct sockaddr_in *local) {
|
||||||
|
log(LOG_DEBUG,"connection_create_dir_listener starting");
|
||||||
|
return connection_create_listener(prkey, local, CONN_TYPE_DIR_LISTENER);
|
||||||
|
}
|
||||||
|
|
||||||
|
int connection_dir_handle_listener_read(connection_t *conn) {
|
||||||
|
log(LOG_NOTICE,"Dir: Received a connection request. Waiting for command.");
|
||||||
|
return connection_handle_listener_read(conn, CONN_TYPE_DIR, DIR_CONN_STATE_COMMAND_WAIT);
|
||||||
|
}
|
||||||
|
|
139
src/or/main.c
139
src/or/main.c
@ -21,10 +21,6 @@ static int please_dumpstats=0; /* whether we should dump stats during the loop *
|
|||||||
/* private key */
|
/* private key */
|
||||||
static crypto_pk_env_t *prkey;
|
static crypto_pk_env_t *prkey;
|
||||||
|
|
||||||
/* router array */
|
|
||||||
static routerinfo_t **router_array = NULL;
|
|
||||||
static int rarray_len = 0;
|
|
||||||
|
|
||||||
/********* END VARIABLES ************/
|
/********* END VARIABLES ************/
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -154,44 +150,6 @@ connection_t *connection_get_by_type(int type) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* the next 4 functions should move to routers.c once we get it
|
|
||||||
* cleaned up more. The router_array and rarray_len variables should
|
|
||||||
* move there too.
|
|
||||||
*/
|
|
||||||
|
|
||||||
routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) {
|
|
||||||
int i;
|
|
||||||
routerinfo_t *router;
|
|
||||||
|
|
||||||
assert(router_array);
|
|
||||||
|
|
||||||
for(i=0;i<rarray_len;i++) {
|
|
||||||
router = router_array[i];
|
|
||||||
if ((router->addr == addr) && (router->or_port == port))
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
routerinfo_t *router_get_first_in_route(unsigned int *route, int routelen) {
|
|
||||||
return router_array[route[routelen-1]];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* a wrapper around new_route. put all these in routers.c perhaps? */
|
|
||||||
unsigned int *router_new_route(int *routelen) {
|
|
||||||
return new_route(options.CoinWeight, router_array, rarray_len, routelen);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* a wrapper around create_onion */
|
|
||||||
unsigned char *router_create_onion(unsigned int *route, int routelen, int *len, crypt_path_t **cpath) {
|
|
||||||
return create_onion(router_array,rarray_len,route,routelen,len,cpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* FIXME can we cut this function out? */
|
/* FIXME can we cut this function out? */
|
||||||
connection_t *connect_to_router_as_op(routerinfo_t *router) {
|
connection_t *connect_to_router_as_op(routerinfo_t *router) {
|
||||||
return connection_connect_to_router_as_op(router, options.ORPort);
|
return connection_connect_to_router_as_op(router, options.ORPort);
|
||||||
@ -252,12 +210,13 @@ void check_conn_read(int i) {
|
|||||||
retval = connection_or_handle_listener_read(conn);
|
retval = connection_or_handle_listener_read(conn);
|
||||||
} else if (conn->type == CONN_TYPE_AP_LISTENER) {
|
} else if (conn->type == CONN_TYPE_AP_LISTENER) {
|
||||||
retval = connection_ap_handle_listener_read(conn);
|
retval = connection_ap_handle_listener_read(conn);
|
||||||
|
} else if (conn->type == CONN_TYPE_DIR_LISTENER) {
|
||||||
|
retval = connection_dir_handle_listener_read(conn);
|
||||||
} else {
|
} else {
|
||||||
/* else it's an OP, OR, or exit */
|
|
||||||
retval = connection_read_to_buf(conn);
|
retval = connection_read_to_buf(conn);
|
||||||
if (retval >= 0) { /* all still well */
|
if (retval >= 0) { /* all still well */
|
||||||
retval = connection_process_inbuf(conn);
|
retval = connection_process_inbuf(conn);
|
||||||
// log(LOG_DEBUG,"check_conn_read(): connection_process_inbuf returned %d.",retval);
|
// log(LOG_DEBUG,"check_conn_read(): connection_process_inbuf returned %d.",retval);
|
||||||
if(retval >= 0 && !connection_state_is_open(conn) && conn->receiver_bucket == 0) {
|
if(retval >= 0 && !connection_state_is_open(conn) && conn->receiver_bucket == 0) {
|
||||||
log(LOG_DEBUG,"check_conn_read(): receiver bucket reached 0 before handshake finished. Closing.");
|
log(LOG_DEBUG,"check_conn_read(): receiver bucket reached 0 before handshake finished. Closing.");
|
||||||
retval = -1;
|
retval = -1;
|
||||||
@ -286,8 +245,7 @@ void check_conn_write(int i) {
|
|||||||
conn = connection_array[i];
|
conn = connection_array[i];
|
||||||
// log(LOG_DEBUG,"check_conn_write(): socket %d wants to write.",conn->s);
|
// log(LOG_DEBUG,"check_conn_write(): socket %d wants to write.",conn->s);
|
||||||
|
|
||||||
if(conn->type == CONN_TYPE_OP_LISTENER ||
|
if(connection_is_listener(conn)) {
|
||||||
conn->type == CONN_TYPE_OR_LISTENER) {
|
|
||||||
log(LOG_DEBUG,"check_conn_write(): Got a listener socket. Can't happen!");
|
log(LOG_DEBUG,"check_conn_write(): Got a listener socket. Can't happen!");
|
||||||
retval = -1;
|
retval = -1;
|
||||||
} else {
|
} else {
|
||||||
@ -337,6 +295,8 @@ int prepare_for_poll(int *timeout) {
|
|||||||
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 int current_second = 0; /* from previous calls to gettimeofday */
|
||||||
|
static int time_to_rebuild_directory = 0;
|
||||||
|
static int time_to_fetch_directory = 0;
|
||||||
int ms_until_conn;
|
int ms_until_conn;
|
||||||
|
|
||||||
*timeout = -1; /* set it to never timeout, possibly overridden below */
|
*timeout = -1; /* set it to never timeout, possibly overridden below */
|
||||||
@ -352,6 +312,34 @@ int prepare_for_poll(int *timeout) {
|
|||||||
if(gettimeofday(&now,NULL) < 0)
|
if(gettimeofday(&now,NULL) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if(options.Role & ROLE_DIR_SERVER) {
|
||||||
|
if(time_to_rebuild_directory < now.tv_sec) {
|
||||||
|
/* it's time to rebuild our directory */
|
||||||
|
if(time_to_rebuild_directory == 0) {
|
||||||
|
/* we just started up. if we build a directory now it will be meaningless. */
|
||||||
|
log(LOG_DEBUG,"prepare_for_poll(): Delaying initial dir build for 15 seconds.");
|
||||||
|
time_to_rebuild_directory = now.tv_sec + 15; /* try in 15 seconds */
|
||||||
|
} else {
|
||||||
|
directory_rebuild();
|
||||||
|
time_to_rebuild_directory = now.tv_sec + options.DirRebuildPeriod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*timeout = 1000*(time_to_rebuild_directory - now.tv_sec) + (1000 - (now.tv_usec / 1000));
|
||||||
|
// log(LOG_DEBUG,"prepare_for_poll(): DirBuild timeout is %d",*timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(options.Role & ROLE_DIR_SERVER)) {
|
||||||
|
if(time_to_fetch_directory < now.tv_sec) {
|
||||||
|
/* it's time to fetch a new directory */
|
||||||
|
/* NOTE directory servers do not currently fetch directories.
|
||||||
|
* Hope this doesn't bite us later.
|
||||||
|
*/
|
||||||
|
directory_initiate_fetch(router_pick_directory_server());
|
||||||
|
time_to_fetch_directory = now.tv_sec + options.DirFetchPeriod;
|
||||||
|
}
|
||||||
|
*timeout = 1000*(time_to_fetch_directory - now.tv_sec) + (1000 - (now.tv_usec / 1000));
|
||||||
|
}
|
||||||
|
|
||||||
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.");
|
||||||
@ -359,8 +347,8 @@ 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 */
|
||||||
*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? */
|
||||||
// log(LOG_DEBUG,"prepare_for_poll(): %d milliseconds til next second.",*timeout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(options.LinkPadding) {
|
if(options.LinkPadding) {
|
||||||
@ -406,9 +394,7 @@ int do_main_loop(void) {
|
|||||||
int poll_result;
|
int poll_result;
|
||||||
|
|
||||||
/* load the routers file */
|
/* load the routers file */
|
||||||
router_array = router_get_list_from_file(options.RouterFile,&rarray_len, options.ORPort);
|
if(router_get_list_from_file(options.RouterFile, options.ORPort) < 0) {
|
||||||
if (!router_array)
|
|
||||||
{
|
|
||||||
log(LOG_ERR,"Error loading router list.");
|
log(LOG_ERR,"Error loading router list.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -429,8 +415,8 @@ int do_main_loop(void) {
|
|||||||
|
|
||||||
/* start-up the necessary connections based on global_role. This is where we
|
/* start-up the necessary connections based on global_role. This is where we
|
||||||
* try to connect to all the other ORs, and start the listeners */
|
* try to connect to all the other ORs, and start the listeners */
|
||||||
retry_all_connections(options.Role, router_array, rarray_len, prkey,
|
retry_all_connections(options.Role, prkey, options.ORPort,
|
||||||
options.ORPort, options.OPPort, options.APPort);
|
options.OPPort, options.APPort, options.DirPort);
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
if(please_dumpstats) {
|
if(please_dumpstats) {
|
||||||
@ -496,7 +482,7 @@ void dumpstats (void) { /* dump stats to stdout */
|
|||||||
int i;
|
int i;
|
||||||
connection_t *conn;
|
connection_t *conn;
|
||||||
extern char *conn_type_to_string[];
|
extern char *conn_type_to_string[];
|
||||||
extern char *conn_state_to_string[][10];
|
extern char *conn_state_to_string[][15];
|
||||||
|
|
||||||
printf("Dumping stats:\n");
|
printf("Dumping stats:\n");
|
||||||
|
|
||||||
@ -515,6 +501,53 @@ void dumpstats (void) { /* dump stats to stdout */
|
|||||||
please_dumpstats = 0;
|
please_dumpstats = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dump_directory_to_string(char *s, int maxlen) {
|
||||||
|
int i;
|
||||||
|
connection_t *conn;
|
||||||
|
char *pkey;
|
||||||
|
int pkeylen;
|
||||||
|
int written;
|
||||||
|
routerinfo_t *router;
|
||||||
|
|
||||||
|
for(i=0;i<nfds;i++) {
|
||||||
|
conn = connection_array[i];
|
||||||
|
|
||||||
|
if(conn->type != CONN_TYPE_OR)
|
||||||
|
continue; /* we only want to list ORs */
|
||||||
|
router = router_get_by_addr_port(conn->addr,conn->port);
|
||||||
|
if(!router) {
|
||||||
|
log(LOG_ERR,"dump_directory_to_string(): couldn't find router %d:%d!",conn->addr,conn->port);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(crypto_pk_write_public_key_to_string(router->pkey,&pkey,&pkeylen)<0) {
|
||||||
|
log(LOG_ERR,"dump_directory_to_string(): write pkey to string failed!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
written = snprintf(s, maxlen, "%s %d %d %d %d %d\n%s\n",
|
||||||
|
router->address,
|
||||||
|
router->or_port,
|
||||||
|
router->op_port,
|
||||||
|
router->ap_port,
|
||||||
|
router->dir_port,
|
||||||
|
router->bandwidth,
|
||||||
|
pkey);
|
||||||
|
|
||||||
|
free(pkey);
|
||||||
|
|
||||||
|
if(written < 0 || written > maxlen) {
|
||||||
|
/* apparently different glibcs do different things on error.. so check both */
|
||||||
|
log(LOG_ERR,"dump_directory_to_string(): tried to exceed string length.");
|
||||||
|
s[maxlen-1] = 0; /* make sure it's null terminated */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
maxlen -= written;
|
||||||
|
s += written;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
|
43
src/or/or.h
43
src/or/or.h
@ -58,6 +58,8 @@
|
|||||||
#define ROLE_OR_CONNECT_ALL 2
|
#define ROLE_OR_CONNECT_ALL 2
|
||||||
#define ROLE_OP_LISTEN 4
|
#define ROLE_OP_LISTEN 4
|
||||||
#define ROLE_AP_LISTEN 8
|
#define ROLE_AP_LISTEN 8
|
||||||
|
#define ROLE_DIR_LISTEN 16
|
||||||
|
#define ROLE_DIR_SERVER 32
|
||||||
|
|
||||||
#define ROLE_IS_OR(role) ((role & ROLE_OR_LISTEN) || (role & ROLE_OR_CONNECT_ALL) || (role & ROLE_OP_LISTEN))
|
#define ROLE_IS_OR(role) ((role & ROLE_OR_LISTEN) || (role & ROLE_OR_CONNECT_ALL) || (role & ROLE_OP_LISTEN))
|
||||||
|
|
||||||
@ -68,6 +70,8 @@
|
|||||||
#define CONN_TYPE_EXIT 5
|
#define CONN_TYPE_EXIT 5
|
||||||
#define CONN_TYPE_AP_LISTENER 6
|
#define CONN_TYPE_AP_LISTENER 6
|
||||||
#define CONN_TYPE_AP 7
|
#define CONN_TYPE_AP 7
|
||||||
|
#define CONN_TYPE_DIR_LISTENER 8
|
||||||
|
#define CONN_TYPE_DIR 9
|
||||||
|
|
||||||
#define LISTENER_STATE_READY 0
|
#define LISTENER_STATE_READY 0
|
||||||
|
|
||||||
@ -105,6 +109,12 @@
|
|||||||
#define AP_CONN_STATE_OR_WAIT 1
|
#define AP_CONN_STATE_OR_WAIT 1
|
||||||
#define AP_CONN_STATE_OPEN 2
|
#define AP_CONN_STATE_OPEN 2
|
||||||
|
|
||||||
|
#define DIR_CONN_STATE_CONNECTING 0
|
||||||
|
#define DIR_CONN_STATE_SENDING_COMMAND 1
|
||||||
|
#define DIR_CONN_STATE_READING 2
|
||||||
|
#define DIR_CONN_STATE_COMMAND_WAIT 3
|
||||||
|
#define DIR_CONN_STATE_WRITING 4
|
||||||
|
|
||||||
#define CIRCUIT_STATE_OPEN_WAIT 0 /* receiving/processing the onion */
|
#define CIRCUIT_STATE_OPEN_WAIT 0 /* receiving/processing the onion */
|
||||||
#define CIRCUIT_STATE_OR_WAIT 1 /* I'm at the beginning of the path, my firsthop is still connecting */
|
#define CIRCUIT_STATE_OR_WAIT 1 /* I'm at the beginning of the path, my firsthop is still connecting */
|
||||||
#define CIRCUIT_STATE_OPEN 2 /* onion processed, ready to send data along the connection */
|
#define CIRCUIT_STATE_OPEN 2 /* onion processed, ready to send data along the connection */
|
||||||
@ -342,9 +352,12 @@ typedef struct
|
|||||||
int ORPort;
|
int ORPort;
|
||||||
int OPPort;
|
int OPPort;
|
||||||
int APPort;
|
int APPort;
|
||||||
|
int DirPort;
|
||||||
int MaxConn;
|
int MaxConn;
|
||||||
int TrafficShaping;
|
int TrafficShaping;
|
||||||
int LinkPadding;
|
int LinkPadding;
|
||||||
|
int DirRebuildPeriod;
|
||||||
|
int DirFetchPeriod;
|
||||||
int Role;
|
int Role;
|
||||||
int loglevel;
|
int loglevel;
|
||||||
} or_options_t;
|
} or_options_t;
|
||||||
@ -441,8 +454,8 @@ int connection_create_listener(crypto_pk_env_t *prkey, struct sockaddr_in *local
|
|||||||
int connection_handle_listener_read(connection_t *conn, int new_type, int new_state);
|
int connection_handle_listener_read(connection_t *conn, int new_type, int new_state);
|
||||||
|
|
||||||
/* start all connections that should be up but aren't */
|
/* start all connections that should be up but aren't */
|
||||||
int retry_all_connections(int role, routerinfo_t **router_array, int rarray_len,
|
int retry_all_connections(int role, crypto_pk_env_t *prkey, uint16_t or_listenport,
|
||||||
crypto_pk_env_t *prkey, uint16_t or_port, uint16_t op_port, uint16_t ap_port);
|
uint16_t op_listenport, uint16_t ap_listenport, uint16_t dir_listenport);
|
||||||
connection_t *connection_connect_to_router_as_op(routerinfo_t *router, uint16_t local_or_port);
|
connection_t *connection_connect_to_router_as_op(routerinfo_t *router, uint16_t local_or_port);
|
||||||
|
|
||||||
int connection_read_to_buf(connection_t *conn);
|
int connection_read_to_buf(connection_t *conn);
|
||||||
@ -548,6 +561,18 @@ connection_t *connection_or_connect_as_op(routerinfo_t *router, struct sockaddr_
|
|||||||
int connection_or_create_listener(crypto_pk_env_t *prkey, struct sockaddr_in *local);
|
int connection_or_create_listener(crypto_pk_env_t *prkey, struct sockaddr_in *local);
|
||||||
int connection_or_handle_listener_read(connection_t *conn);
|
int connection_or_handle_listener_read(connection_t *conn);
|
||||||
|
|
||||||
|
/********************************* directory.c ***************************/
|
||||||
|
|
||||||
|
void directory_initiate_fetch(routerinfo_t *router);
|
||||||
|
int directory_send_command(connection_t *conn);
|
||||||
|
void directory_rebuild(void);
|
||||||
|
int connection_dir_process_inbuf(connection_t *conn);
|
||||||
|
int directory_handle_command(connection_t *conn);
|
||||||
|
int directory_handle_reading(connection_t *conn);
|
||||||
|
int connection_dir_finished_flushing(connection_t *conn);
|
||||||
|
int connection_dir_create_listener(crypto_pk_env_t *prkey, struct sockaddr_in *local);
|
||||||
|
int connection_dir_handle_listener_read(connection_t *conn);
|
||||||
|
|
||||||
/********************************* main.c ***************************/
|
/********************************* main.c ***************************/
|
||||||
|
|
||||||
int connection_add(connection_t *conn);
|
int connection_add(connection_t *conn);
|
||||||
@ -559,10 +584,6 @@ connection_t *connection_exact_get_by_addr_port(uint32_t addr, uint16_t port);
|
|||||||
|
|
||||||
connection_t *connection_get_by_type(int type);
|
connection_t *connection_get_by_type(int type);
|
||||||
|
|
||||||
routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port);
|
|
||||||
unsigned int *router_new_route(int *routelen);
|
|
||||||
unsigned char *router_create_onion(unsigned int *route, int routelen, int *len, crypt_path_t **cpath);
|
|
||||||
routerinfo_t *router_get_first_in_route(unsigned int *route, int routelen);
|
|
||||||
connection_t *connect_to_router_as_op(routerinfo_t *router);
|
connection_t *connect_to_router_as_op(routerinfo_t *router);
|
||||||
|
|
||||||
void connection_watch_events(connection_t *conn, short events);
|
void connection_watch_events(connection_t *conn, short events);
|
||||||
@ -582,6 +603,7 @@ int do_main_loop(void);
|
|||||||
void catchint();
|
void catchint();
|
||||||
void catchusr1();
|
void catchusr1();
|
||||||
void dumpstats(void);
|
void dumpstats(void);
|
||||||
|
void dump_directory_to_string(char *s, int maxlen);
|
||||||
|
|
||||||
int main(int argc, char *argv[]);
|
int main(int argc, char *argv[]);
|
||||||
|
|
||||||
@ -625,6 +647,13 @@ tracked_onion_t *id_tracked_onion(unsigned char *onion, uint32_t onionlen, track
|
|||||||
|
|
||||||
/********************************* routers.c ***************************/
|
/********************************* routers.c ***************************/
|
||||||
|
|
||||||
routerinfo_t **router_get_list_from_file(char *routerfile, int *len, uint16_t or_listenport);
|
void router_retry_connections(crypto_pk_env_t *prkey, struct sockaddr_in *local);
|
||||||
|
routerinfo_t *router_pick_directory_server(void);
|
||||||
|
routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port);
|
||||||
|
unsigned int *router_new_route(int *routelen);
|
||||||
|
unsigned char *router_create_onion(unsigned int *route, int routelen, int *len, crypt_path_t **cpath);
|
||||||
|
routerinfo_t *router_get_first_in_route(unsigned int *route, int routelen);
|
||||||
|
int router_get_list_from_file(char *routerfile, uint16_t or_listenport);
|
||||||
|
int router_get_list_from_string(char *s, uint16_t or_listenport);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
137
src/or/routers.c
137
src/or/routers.c
@ -13,7 +13,16 @@
|
|||||||
|
|
||||||
#include "or.h"
|
#include "or.h"
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* router array */
|
||||||
|
static routerinfo_t **router_array = NULL;
|
||||||
|
static int rarray_len = 0;
|
||||||
|
|
||||||
extern int global_role; /* from main.c */
|
extern int global_role; /* from main.c */
|
||||||
|
extern or_options_t options; /* command-line and config-file options */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
/* static function prototypes */
|
/* static function prototypes */
|
||||||
static int router_is_me(uint32_t or_address, uint16_t or_listenport, uint16_t my_or_listenport);
|
static int router_is_me(uint32_t or_address, uint16_t or_listenport, uint16_t my_or_listenport);
|
||||||
@ -23,6 +32,67 @@ static char *eat_whitespace(char *s);
|
|||||||
static char *find_whitespace(char *s);
|
static char *find_whitespace(char *s);
|
||||||
static routerinfo_t *router_get_entry_from_string(char **s);
|
static routerinfo_t *router_get_entry_from_string(char **s);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void router_retry_connections(crypto_pk_env_t *prkey, struct sockaddr_in *local) {
|
||||||
|
int i;
|
||||||
|
routerinfo_t *router;
|
||||||
|
|
||||||
|
for (i=0;i<rarray_len;i++) {
|
||||||
|
router = router_array[i];
|
||||||
|
if(!connection_exact_get_by_addr_port(router->addr,router->or_port)) { /* not in the list */
|
||||||
|
log(LOG_DEBUG,"retry_all_connections(): connecting to OR %s:%u.",router->address,router->or_port);
|
||||||
|
connection_or_connect_as_or(router, prkey, local);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
routerinfo_t *router_pick_directory_server(void) {
|
||||||
|
/* currently, pick the first router with a positive dir_port */
|
||||||
|
int i;
|
||||||
|
routerinfo_t *router;
|
||||||
|
|
||||||
|
if(!router_array)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for(i=0;i<rarray_len;i++) {
|
||||||
|
router = router_array[i];
|
||||||
|
if(router->dir_port > 0)
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) {
|
||||||
|
int i;
|
||||||
|
routerinfo_t *router;
|
||||||
|
|
||||||
|
assert(router_array);
|
||||||
|
|
||||||
|
for(i=0;i<rarray_len;i++) {
|
||||||
|
router = router_array[i];
|
||||||
|
if ((router->addr == addr) && (router->or_port == port))
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
routerinfo_t *router_get_first_in_route(unsigned int *route, int routelen) {
|
||||||
|
return router_array[route[routelen-1]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* a wrapper around new_route. put all these in routers.c perhaps? */
|
||||||
|
unsigned int *router_new_route(int *routelen) {
|
||||||
|
return new_route(options.CoinWeight, router_array, rarray_len, routelen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* a wrapper around create_onion */
|
||||||
|
unsigned char *router_create_onion(unsigned int *route, int routelen, int *len, crypt_path_t **cpath) {
|
||||||
|
return create_onion(router_array,rarray_len,route,routelen,len,cpath);
|
||||||
|
}
|
||||||
|
|
||||||
/* private function, to determine whether the current entry in the router list is actually us */
|
/* private function, to determine whether the current entry in the router list is actually us */
|
||||||
static int router_is_me(uint32_t or_address, uint16_t or_listenport, uint16_t my_or_listenport)
|
static int router_is_me(uint32_t or_address, uint16_t or_listenport, uint16_t my_or_listenport)
|
||||||
{
|
{
|
||||||
@ -58,8 +128,8 @@ static int router_is_me(uint32_t or_address, uint16_t or_listenport, uint16_t my
|
|||||||
a = (struct in_addr *)addr;
|
a = (struct in_addr *)addr;
|
||||||
|
|
||||||
tmp1 = strdup(inet_ntoa(*a)); /* can't call inet_ntoa twice in the same
|
tmp1 = strdup(inet_ntoa(*a)); /* can't call inet_ntoa twice in the same
|
||||||
printf, since it overwrites its static
|
printf, since it overwrites its static
|
||||||
memory each time */
|
memory each time */
|
||||||
log(LOG_DEBUG,"router_is_me(): Comparing '%s' to '%s'.",tmp1,
|
log(LOG_DEBUG,"router_is_me(): Comparing '%s' to '%s'.",tmp1,
|
||||||
inet_ntoa( *((struct in_addr *)&or_address) ) );
|
inet_ntoa( *((struct in_addr *)&or_address) ) );
|
||||||
free(tmp1);
|
free(tmp1);
|
||||||
@ -151,64 +221,87 @@ static routerinfo_t **make_rarray(routerinfo_t* list, int *len)
|
|||||||
|
|
||||||
|
|
||||||
/* load the router list */
|
/* load the router list */
|
||||||
routerinfo_t **router_get_list_from_file(char *routerfile, int *len, uint16_t or_listenport)
|
int router_get_list_from_file(char *routerfile, uint16_t or_listenport)
|
||||||
{
|
{
|
||||||
routerinfo_t *routerlist=NULL;
|
|
||||||
routerinfo_t *router;
|
|
||||||
int fd; /* router file */
|
int fd; /* router file */
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
char *string;
|
char *string;
|
||||||
char *tmps;
|
|
||||||
|
|
||||||
assert(routerfile && len);
|
assert(routerfile);
|
||||||
|
|
||||||
if (strcspn(routerfile,CONFIG_LEGAL_FILENAME_CHARACTERS) != 0) {
|
if (strcspn(routerfile,CONFIG_LEGAL_FILENAME_CHARACTERS) != 0) {
|
||||||
log(LOG_ERR,"router_get_list_from_file(): Filename %s contains illegal characters.",routerfile);
|
log(LOG_ERR,"router_get_list_from_file(): Filename %s contains illegal characters.",routerfile);
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(stat(routerfile, &statbuf) < 0) {
|
if(stat(routerfile, &statbuf) < 0) {
|
||||||
log(LOG_ERR,"router_get_list_from_file(): Could not stat %s.",routerfile);
|
log(LOG_ERR,"router_get_list_from_file(): Could not stat %s.",routerfile);
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* open the router list */
|
/* open the router list */
|
||||||
fd = open(routerfile,O_RDONLY,0);
|
fd = open(routerfile,O_RDONLY,0);
|
||||||
if (fd<0) {
|
if (fd<0) {
|
||||||
log(LOG_ERR,"router_get_list_from_file(): Could not open %s.",routerfile);
|
log(LOG_ERR,"router_get_list_from_file(): Could not open %s.",routerfile);
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
string = malloc(statbuf.st_size+1);
|
string = malloc(statbuf.st_size+1);
|
||||||
if(!string) {
|
if(!string) {
|
||||||
log(LOG_ERR,"router_get_list_from_file(): Out of memory.");
|
log(LOG_ERR,"router_get_list_from_file(): Out of memory.");
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(read(fd,string,statbuf.st_size) != statbuf.st_size) {
|
if(read(fd,string,statbuf.st_size) != statbuf.st_size) {
|
||||||
log(LOG_ERR,"router_get_list_from_file(): Couldn't read all %d bytes of file '%s'.",statbuf.st_size,routerfile);
|
log(LOG_ERR,"router_get_list_from_file(): Couldn't read all %d bytes of file '%s'.",statbuf.st_size,routerfile);
|
||||||
return NULL;
|
free(string);
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
string[statbuf.st_size] = 0; /* null terminate it */
|
string[statbuf.st_size] = 0; /* null terminate it */
|
||||||
tmps = string;
|
|
||||||
while(*tmps) { /* while not at the end of the string */
|
if(router_get_list_from_string(string, or_listenport) < 0) {
|
||||||
router = router_get_entry_from_string(&tmps);
|
log(LOG_ERR,"router_get_list_from_file(): The routerfile itself was corrupt.");
|
||||||
|
free(string);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(string);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int router_get_list_from_string(char *s, uint16_t or_listenport) {
|
||||||
|
routerinfo_t *routerlist=NULL;
|
||||||
|
routerinfo_t *router;
|
||||||
|
routerinfo_t **new_router_array;
|
||||||
|
int new_rarray_len;
|
||||||
|
|
||||||
|
assert(s);
|
||||||
|
|
||||||
|
while(*s) { /* while not at the end of the string */
|
||||||
|
router = router_get_entry_from_string(&s);
|
||||||
if(router == NULL) {
|
if(router == NULL) {
|
||||||
routerlist_free(routerlist);
|
routerlist_free(routerlist);
|
||||||
free(string);
|
return -1;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
if(!router_is_me(router->addr, router->or_port, or_listenport)) {
|
if(!router_is_me(router->addr, router->or_port, or_listenport)) {
|
||||||
router->next = routerlist;
|
router->next = routerlist;
|
||||||
routerlist = router;
|
routerlist = router;
|
||||||
}
|
}
|
||||||
tmps = eat_whitespace(tmps);
|
s = eat_whitespace(s);
|
||||||
}
|
}
|
||||||
free(string);
|
|
||||||
return make_rarray(routerlist, len);
|
new_router_array = make_rarray(routerlist, &new_rarray_len);
|
||||||
}
|
if(new_router_array) { /* success! replace the old one */
|
||||||
|
rarray_free(router_array); /* free the old one first */
|
||||||
|
router_array = new_router_array;
|
||||||
|
rarray_len = new_rarray_len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* return the first char of s that is not whitespace and not a comment */
|
/* return the first char of s that is not whitespace and not a comment */
|
||||||
static char *eat_whitespace(char *s) {
|
static char *eat_whitespace(char *s) {
|
||||||
@ -322,7 +415,7 @@ static routerinfo_t *router_get_entry_from_string(char **s) {
|
|||||||
next = strchr(next, '\n');
|
next = strchr(next, '\n');
|
||||||
assert(next); /* can't fail, we just checked it was here */
|
assert(next); /* can't fail, we just checked it was here */
|
||||||
*next = 0;
|
*next = 0;
|
||||||
log(LOG_DEBUG,"Key about to be read is: '%s'",*s);
|
// log(LOG_DEBUG,"Key about to be read is: '%s'",*s);
|
||||||
if((crypto_pk_read_public_key_from_string(router->pkey, *s, strlen(*s))<0)) {
|
if((crypto_pk_read_public_key_from_string(router->pkey, *s, strlen(*s))<0)) {
|
||||||
log(LOG_ERR,"router_get_entry_from_string(): Couldn't read pk from string");
|
log(LOG_ERR,"router_get_entry_from_string(): Couldn't read pk from string");
|
||||||
goto router_read_failed;
|
goto router_read_failed;
|
||||||
|
Loading…
Reference in New Issue
Block a user