mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-28 14:23:30 +01:00
Refactor directory servers
* read all the time (before we would ignore eof sometimes, oops) * we can handle different urls now * send back 404 for an un-handled url * commands initiated by the client can handle payloads now * introduce conn->purpose to avoid exponential state-space explosion svn:r1400
This commit is contained in:
parent
919a8f236e
commit
2d3ac08633
@ -49,14 +49,11 @@ char *conn_state_to_string[][_CONN_TYPE_MAX+1] = {
|
|||||||
"open" }, /* 8 */
|
"open" }, /* 8 */
|
||||||
{ "ready" }, /* dir listener, 0 */
|
{ "ready" }, /* dir listener, 0 */
|
||||||
{ "", /* dir, 0 */
|
{ "", /* dir, 0 */
|
||||||
"connecting (fetch)", /* 1 */
|
"connecting", /* 1 */
|
||||||
"connecting (upload)", /* 2 */
|
"client sending", /* 2 */
|
||||||
"client sending fetch", /* 3 */
|
"client reading", /* 3 */
|
||||||
"client sending upload", /* 4 */
|
"awaiting command", /* 4 */
|
||||||
"client reading fetch", /* 5 */
|
"writing" }, /* 5 */
|
||||||
"client reading upload", /* 6 */
|
|
||||||
"awaiting command", /* 7 */
|
|
||||||
"writing" }, /* 8 */
|
|
||||||
{ "", /* dns worker, 0 */
|
{ "", /* dns worker, 0 */
|
||||||
"idle", /* 1 */
|
"idle", /* 1 */
|
||||||
"busy" }, /* 2 */
|
"busy" }, /* 2 */
|
||||||
@ -373,6 +370,7 @@ static int connection_init_accepted_conn(connection_t *conn) {
|
|||||||
conn->state = AP_CONN_STATE_SOCKS_WAIT;
|
conn->state = AP_CONN_STATE_SOCKS_WAIT;
|
||||||
break;
|
break;
|
||||||
case CONN_TYPE_DIR:
|
case CONN_TYPE_DIR:
|
||||||
|
conn->purpose = DIR_PURPOSE_SERVER;
|
||||||
conn->state = DIR_CONN_STATE_SERVER_COMMAND_WAIT;
|
conn->state = DIR_CONN_STATE_SERVER_COMMAND_WAIT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -599,8 +597,7 @@ int connection_handle_read(connection_t *conn) {
|
|||||||
|
|
||||||
if(connection_read_to_buf(conn) < 0) {
|
if(connection_read_to_buf(conn) < 0) {
|
||||||
if(conn->type == CONN_TYPE_DIR &&
|
if(conn->type == CONN_TYPE_DIR &&
|
||||||
(conn->state == DIR_CONN_STATE_CONNECTING_FETCH ||
|
conn->state == DIR_CONN_STATE_CONNECTING) {
|
||||||
conn->state == DIR_CONN_STATE_CONNECTING_UPLOAD)) {
|
|
||||||
/* it's a directory server and connecting failed: forget about this router */
|
/* it's a directory server and connecting failed: forget about this router */
|
||||||
/* XXX I suspect pollerr may make Windows not get to this point. :( */
|
/* XXX I suspect pollerr may make Windows not get to this point. :( */
|
||||||
router_mark_as_down(conn->nickname);
|
router_mark_as_down(conn->nickname);
|
||||||
@ -1029,6 +1026,9 @@ void assert_connection_ok(connection_t *conn, time_t now)
|
|||||||
} else {
|
} else {
|
||||||
assert(!conn->socks_request);
|
assert(!conn->socks_request);
|
||||||
}
|
}
|
||||||
|
if(conn->type != CONN_TYPE_DIR) {
|
||||||
|
assert(!conn->purpose); /* only used for dir types currently */
|
||||||
|
}
|
||||||
|
|
||||||
switch(conn->type)
|
switch(conn->type)
|
||||||
{
|
{
|
||||||
@ -1053,6 +1053,8 @@ void assert_connection_ok(connection_t *conn, time_t now)
|
|||||||
case CONN_TYPE_DIR:
|
case CONN_TYPE_DIR:
|
||||||
assert(conn->state >= _DIR_CONN_STATE_MIN &&
|
assert(conn->state >= _DIR_CONN_STATE_MIN &&
|
||||||
conn->state <= _DIR_CONN_STATE_MAX);
|
conn->state <= _DIR_CONN_STATE_MAX);
|
||||||
|
assert(conn->purpose >= _DIR_PURPOSE_MIN &&
|
||||||
|
conn->purpose <= _DIR_PURPOSE_MAX);
|
||||||
break;
|
break;
|
||||||
case CONN_TYPE_DNSWORKER:
|
case CONN_TYPE_DNSWORKER:
|
||||||
assert(conn->state == DNSWORKER_STATE_IDLE ||
|
assert(conn->state == DNSWORKER_STATE_IDLE ||
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
#include "or.h"
|
#include "or.h"
|
||||||
|
|
||||||
static int directory_send_command(connection_t *conn, int command);
|
static void directory_send_command(connection_t *conn,
|
||||||
|
int purpose, const char *payload);
|
||||||
static int directory_handle_command(connection_t *conn);
|
static int directory_handle_command(connection_t *conn);
|
||||||
|
|
||||||
/********* START VARIABLES **********/
|
/********* START VARIABLES **********/
|
||||||
@ -17,20 +18,26 @@ extern int has_fetched_directory;
|
|||||||
|
|
||||||
/********* END VARIABLES ************/
|
/********* END VARIABLES ************/
|
||||||
|
|
||||||
void directory_initiate_command(routerinfo_t *router, int command) {
|
void directory_initiate_command(routerinfo_t *router, int purpose, const char *payload) {
|
||||||
connection_t *conn;
|
connection_t *conn;
|
||||||
|
|
||||||
switch(command) {
|
switch(purpose) {
|
||||||
case DIR_CONN_STATE_CONNECTING_FETCH:
|
case DIR_PURPOSE_FETCH_DIR:
|
||||||
log_fn(LOG_DEBUG,"initiating directory fetch");
|
log_fn(LOG_DEBUG,"initiating directory fetch");
|
||||||
break;
|
break;
|
||||||
case DIR_CONN_STATE_CONNECTING_UPLOAD:
|
case DIR_PURPOSE_FETCH_HIDSERV:
|
||||||
log_fn(LOG_DEBUG,"initiating directory upload");
|
log_fn(LOG_DEBUG,"initiating hidden-service descriptor fetch");
|
||||||
|
break;
|
||||||
|
case DIR_PURPOSE_UPLOAD_DIR:
|
||||||
|
log_fn(LOG_DEBUG,"initiating server descriptor upload");
|
||||||
|
break;
|
||||||
|
case DIR_PURPOSE_UPLOAD_HIDSERV:
|
||||||
|
log_fn(LOG_DEBUG,"initiating hidden-service descriptor upload");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!router) { /* i guess they didn't have one in mind for me to use */
|
if (!router) { /* i guess they didn't have one in mind for me to use */
|
||||||
log_fn(LOG_WARN,"No running dirservers known. Not trying.");
|
log_fn(LOG_WARN,"No running dirservers known. Not trying. (purpose %d)", purpose);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,57 +51,99 @@ void directory_initiate_command(routerinfo_t *router, int command) {
|
|||||||
assert(router->identity_pkey);
|
assert(router->identity_pkey);
|
||||||
conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey);
|
conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey);
|
||||||
|
|
||||||
conn->state = command;
|
conn->purpose = purpose;
|
||||||
|
|
||||||
if(connection_add(conn) < 0) { /* no space, forget it */
|
if(connection_add(conn) < 0) { /* no space, forget it */
|
||||||
connection_free(conn);
|
connection_free(conn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(connection_connect(conn, router->address, router->addr, router->dir_port)) {
|
/* queue the command on the outbuf */
|
||||||
case -1:
|
directory_send_command(conn, purpose, payload);
|
||||||
router_mark_as_down(conn->nickname); /* don't try him again */
|
|
||||||
connection_mark_for_close(conn, 0);
|
|
||||||
return;
|
|
||||||
case 0:
|
|
||||||
connection_set_poll_socket(conn);
|
|
||||||
connection_watch_events(conn, POLLIN | POLLOUT | POLLERR);
|
|
||||||
/* writable indicates finish, readable indicates broken link,
|
|
||||||
error indicates broken link in windowsland. */
|
|
||||||
return;
|
|
||||||
/* case 1: fall through */
|
|
||||||
}
|
|
||||||
|
|
||||||
connection_set_poll_socket(conn);
|
if(purpose == DIR_PURPOSE_FETCH_DIR ||
|
||||||
if(directory_send_command(conn, command) < 0) {
|
purpose == DIR_PURPOSE_UPLOAD_DIR) {
|
||||||
connection_mark_for_close(conn, 0);
|
|
||||||
|
/* then we want to connect directly */
|
||||||
|
conn->state = DIR_CONN_STATE_CONNECTING;
|
||||||
|
|
||||||
|
switch(connection_connect(conn, conn->address, conn->addr, conn->port)) {
|
||||||
|
case -1:
|
||||||
|
router_mark_as_down(conn->nickname); /* don't try him again */
|
||||||
|
connection_mark_for_close(conn, 0);
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
|
||||||
|
/* fall through */
|
||||||
|
case 0:
|
||||||
|
connection_set_poll_socket(conn);
|
||||||
|
connection_watch_events(conn, POLLIN | POLLOUT | POLLERR);
|
||||||
|
/* writable indicates finish, readable indicates broken link,
|
||||||
|
error indicates broken link in windowsland. */
|
||||||
|
}
|
||||||
|
} else { /* we want to connect via tor */
|
||||||
|
/* make an AP connection
|
||||||
|
* populate it and add it at the right state
|
||||||
|
* socketpair and hook up both sides
|
||||||
|
*/
|
||||||
|
|
||||||
|
conn->state = DIR_CONN_STATE_CLIENT_SENDING;
|
||||||
|
connection_set_poll_socket(conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int directory_send_command(connection_t *conn, int command) {
|
static void directory_send_command(connection_t *conn,
|
||||||
|
int purpose, const char *payload) {
|
||||||
char fetchstring[] = "GET / HTTP/1.0\r\n\r\n";
|
char fetchstring[] = "GET / HTTP/1.0\r\n\r\n";
|
||||||
const char *s;
|
|
||||||
char tmp[8192];
|
char tmp[8192];
|
||||||
|
|
||||||
assert(conn && conn->type == CONN_TYPE_DIR);
|
assert(conn && conn->type == CONN_TYPE_DIR);
|
||||||
|
|
||||||
switch(command) {
|
switch(purpose) {
|
||||||
case DIR_CONN_STATE_CONNECTING_FETCH:
|
case DIR_PURPOSE_FETCH_DIR:
|
||||||
|
assert(payload == NULL);
|
||||||
connection_write_to_buf(fetchstring, strlen(fetchstring), conn);
|
connection_write_to_buf(fetchstring, strlen(fetchstring), conn);
|
||||||
conn->state = DIR_CONN_STATE_CLIENT_SENDING_FETCH;
|
|
||||||
break;
|
break;
|
||||||
case DIR_CONN_STATE_CONNECTING_UPLOAD:
|
case DIR_PURPOSE_UPLOAD_DIR:
|
||||||
s = router_get_my_descriptor();
|
assert(payload);
|
||||||
if(!s) {
|
|
||||||
log_fn(LOG_WARN,"Failed to get my descriptor.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
snprintf(tmp, sizeof(tmp), "POST / HTTP/1.0\r\nContent-Length: %d\r\n\r\n%s",
|
snprintf(tmp, sizeof(tmp), "POST / HTTP/1.0\r\nContent-Length: %d\r\n\r\n%s",
|
||||||
(int)strlen(s), s);
|
(int)strlen(payload), payload);
|
||||||
|
connection_write_to_buf(tmp, strlen(tmp), conn);
|
||||||
|
break;
|
||||||
|
case DIR_PURPOSE_FETCH_HIDSERV:
|
||||||
|
assert(payload);
|
||||||
|
snprintf(tmp, sizeof(tmp), "GET /hidserv/%s HTTP/1.0\r\n\r\n", payload);
|
||||||
|
connection_write_to_buf(tmp, strlen(tmp), conn);
|
||||||
|
break;
|
||||||
|
case DIR_PURPOSE_UPLOAD_HIDSERV:
|
||||||
|
assert(payload);
|
||||||
|
snprintf(tmp, sizeof(tmp),
|
||||||
|
"POST /hidserv/ HTTP/1.0\r\nContent-Length: %d\r\n\r\n%s",
|
||||||
|
(int)strlen(payload), payload);
|
||||||
connection_write_to_buf(tmp, strlen(tmp), conn);
|
connection_write_to_buf(tmp, strlen(tmp), conn);
|
||||||
conn->state = DIR_CONN_STATE_CLIENT_SENDING_UPLOAD;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse "%s %s HTTP/1..."
|
||||||
|
* If it's well-formed, point *url to the second %s,
|
||||||
|
* null-terminate it (this modifies headers!) and return 0.
|
||||||
|
* Otherwise, return -1.
|
||||||
|
*/
|
||||||
|
int parse_http_url(char *headers, char **url) {
|
||||||
|
char *s, *tmp;
|
||||||
|
|
||||||
|
s = (char *)eat_whitespace_no_nl(headers);
|
||||||
|
if (!*s) return -1;
|
||||||
|
s = (char *)find_whitespace(s); /* get past GET/POST */
|
||||||
|
if (!*s) return -1;
|
||||||
|
s = (char *)eat_whitespace_no_nl(s);
|
||||||
|
if (!*s) return -1;
|
||||||
|
tmp = s; /* this is it, assuming it's valid */
|
||||||
|
s = (char *)find_whitespace(s);
|
||||||
|
if (!*s) return -1;
|
||||||
|
*s = 0;
|
||||||
|
*url = tmp;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,8 +180,7 @@ int connection_dir_process_inbuf(connection_t *conn) {
|
|||||||
assert(conn && conn->type == CONN_TYPE_DIR);
|
assert(conn && conn->type == CONN_TYPE_DIR);
|
||||||
|
|
||||||
if(conn->inbuf_reached_eof) {
|
if(conn->inbuf_reached_eof) {
|
||||||
if(conn->state != DIR_CONN_STATE_CLIENT_READING_FETCH &&
|
if(conn->state != DIR_CONN_STATE_CLIENT_READING) {
|
||||||
conn->state != DIR_CONN_STATE_CLIENT_READING_UPLOAD) {
|
|
||||||
log_fn(LOG_INFO,"conn reached eof, not reading. Closing.");
|
log_fn(LOG_INFO,"conn reached eof, not reading. Closing.");
|
||||||
connection_close_immediate(conn); /* it was an error; give up on flushing */
|
connection_close_immediate(conn); /* it was an error; give up on flushing */
|
||||||
connection_mark_for_close(conn,0);
|
connection_mark_for_close(conn,0);
|
||||||
@ -160,7 +208,7 @@ int connection_dir_process_inbuf(connection_t *conn) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(conn->state == DIR_CONN_STATE_CLIENT_READING_FETCH) {
|
if(conn->purpose == DIR_PURPOSE_FETCH_DIR) {
|
||||||
/* fetch/process the directory to learn about new routers. */
|
/* fetch/process the directory to learn about new routers. */
|
||||||
int directorylen;
|
int directorylen;
|
||||||
directorylen = strlen(directory);
|
directorylen = strlen(directory);
|
||||||
@ -192,7 +240,7 @@ int connection_dir_process_inbuf(connection_t *conn) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(conn->state == DIR_CONN_STATE_CLIENT_READING_UPLOAD) {
|
if(conn->purpose == DIR_PURPOSE_UPLOAD_DIR) {
|
||||||
switch(status_code) {
|
switch(status_code) {
|
||||||
case 200:
|
case 200:
|
||||||
log_fn(LOG_INFO,"eof (status 200) while reading upload response: finished.");
|
log_fn(LOG_INFO,"eof (status 200) while reading upload response: finished.");
|
||||||
@ -203,16 +251,36 @@ int connection_dir_process_inbuf(connection_t *conn) {
|
|||||||
case 403:
|
case 403:
|
||||||
log_fn(LOG_WARN,"http status 403 (unapproved server) response from dirserver. Is your clock skewed? Have you mailed arma your identity fingerprint? Are you using the right key?");
|
log_fn(LOG_WARN,"http status 403 (unapproved server) response from dirserver. Is your clock skewed? Have you mailed arma your identity fingerprint? Are you using the right key?");
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log_fn(LOG_WARN,"http status %d response unrecognized.", status_code);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
free(directory); free(headers);
|
free(directory); free(headers);
|
||||||
connection_mark_for_close(conn,0);
|
connection_mark_for_close(conn,0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(conn->purpose == DIR_PURPOSE_FETCH_HIDSERV) {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(conn->purpose == DIR_PURPOSE_UPLOAD_HIDSERV) {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
assert(0); /* never reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
if(conn->state == DIR_CONN_STATE_SERVER_COMMAND_WAIT)
|
if(conn->state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
|
||||||
return directory_handle_command(conn);
|
if (directory_handle_command(conn) < 0) {
|
||||||
|
connection_mark_for_close(conn,0);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX for READ states, might want to make sure inbuf isn't too big */
|
/* XXX for READ states, might want to make sure inbuf isn't too big */
|
||||||
|
|
||||||
@ -223,54 +291,94 @@ int connection_dir_process_inbuf(connection_t *conn) {
|
|||||||
static char answer200[] = "HTTP/1.0 200 OK\r\n\r\n";
|
static char answer200[] = "HTTP/1.0 200 OK\r\n\r\n";
|
||||||
static char answer400[] = "HTTP/1.0 400 Bad request\r\n\r\n";
|
static char answer400[] = "HTTP/1.0 400 Bad request\r\n\r\n";
|
||||||
static char answer403[] = "HTTP/1.0 403 Unapproved server\r\n\r\n";
|
static char answer403[] = "HTTP/1.0 403 Unapproved server\r\n\r\n";
|
||||||
|
static char answer404[] = "HTTP/1.0 404 Not found\r\n\r\n";
|
||||||
static char answer503[] = "HTTP/1.0 503 Directory unavailable\r\n\r\n";
|
static char answer503[] = "HTTP/1.0 503 Directory unavailable\r\n\r\n";
|
||||||
|
|
||||||
|
/* always returns 0 */
|
||||||
static int directory_handle_command_get(connection_t *conn,
|
static int directory_handle_command_get(connection_t *conn,
|
||||||
char *headers, char *body) {
|
char *headers, char *body) {
|
||||||
size_t dlen;
|
size_t dlen;
|
||||||
const char *cp;
|
const char *cp;
|
||||||
|
char *url;
|
||||||
|
|
||||||
/* XXX should check url and http version */
|
|
||||||
log_fn(LOG_DEBUG,"Received GET command.");
|
log_fn(LOG_DEBUG,"Received GET command.");
|
||||||
|
|
||||||
dlen = dirserv_get_directory(&cp);
|
conn->state = DIR_CONN_STATE_SERVER_WRITING;
|
||||||
|
|
||||||
if(dlen == 0) {
|
if (parse_http_url(headers, &url) < 0) {
|
||||||
log_fn(LOG_WARN,"My directory is empty. Closing.");
|
connection_write_to_buf(answer400, strlen(answer400), conn);
|
||||||
connection_write_to_buf(answer503, strlen(answer503), conn);
|
|
||||||
conn->state = DIR_CONN_STATE_SERVER_WRITING;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_fn(LOG_DEBUG,"Dumping directory to client.");
|
if(!strcmp(url,"/")) { /* directory fetch */
|
||||||
connection_write_to_buf(answer200, strlen(answer200), conn);
|
dlen = dirserv_get_directory(&cp);
|
||||||
connection_write_to_buf(cp, dlen, conn);
|
|
||||||
conn->state = DIR_CONN_STATE_SERVER_WRITING;
|
if(dlen == 0) {
|
||||||
|
log_fn(LOG_WARN,"My directory is empty. Closing.");
|
||||||
|
connection_write_to_buf(answer503, strlen(answer503), conn);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_fn(LOG_DEBUG,"Dumping directory to client.");
|
||||||
|
connection_write_to_buf(answer200, strlen(answer200), conn);
|
||||||
|
connection_write_to_buf(cp, dlen, conn);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!strncmp(url,"/hidserv/",9)) { /* hidserv descriptor fetch */
|
||||||
|
/* ask back-end for the hidden-services descriptor in
|
||||||
|
* url+9, and return it with a 200 if valid, or give a 404
|
||||||
|
* otherwise
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we didn't recognize the url */
|
||||||
|
connection_write_to_buf(answer404, strlen(answer404), conn);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* always returns 0 */
|
||||||
static int directory_handle_command_post(connection_t *conn,
|
static int directory_handle_command_post(connection_t *conn,
|
||||||
char *headers, char *body) {
|
char *headers, char *body) {
|
||||||
const char *cp;
|
const char *cp;
|
||||||
|
char *url;
|
||||||
|
|
||||||
/* XXX should check url and http version */
|
|
||||||
log_fn(LOG_DEBUG,"Received POST command.");
|
log_fn(LOG_DEBUG,"Received POST command.");
|
||||||
cp = body;
|
|
||||||
switch(dirserv_add_descriptor(&cp)) {
|
|
||||||
case -1:
|
|
||||||
/* malformed descriptor, or something wrong */
|
|
||||||
connection_write_to_buf(answer400, strlen(answer400), conn);
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
/* descriptor was well-formed but server has not been approved */
|
|
||||||
connection_write_to_buf(answer403, strlen(answer403), conn);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
dirserv_get_directory(&cp); /* rebuild and write to disk */
|
|
||||||
connection_write_to_buf(answer200, strlen(answer200), conn);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
conn->state = DIR_CONN_STATE_SERVER_WRITING;
|
conn->state = DIR_CONN_STATE_SERVER_WRITING;
|
||||||
|
|
||||||
|
if (parse_http_url(headers, &url) < 0) {
|
||||||
|
connection_write_to_buf(answer400, strlen(answer400), conn);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!strcmp(url,"/")) { /* server descriptor post */
|
||||||
|
cp = body;
|
||||||
|
switch(dirserv_add_descriptor(&cp)) {
|
||||||
|
case -1:
|
||||||
|
/* malformed descriptor, or something wrong */
|
||||||
|
connection_write_to_buf(answer400, strlen(answer400), conn);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
/* descriptor was well-formed but server has not been approved */
|
||||||
|
connection_write_to_buf(answer403, strlen(answer403), conn);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
dirserv_get_directory(&cp); /* rebuild and write to disk */
|
||||||
|
connection_write_to_buf(answer200, strlen(answer200), conn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!strncmp(url,"/hidserv/",9)) { /* hidserv descriptor post */
|
||||||
|
/* pass 'body' to the backend */
|
||||||
|
/* return 400, 403, or 200 as appropriate */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we didn't recognize the url */
|
||||||
|
connection_write_to_buf(answer404, strlen(answer404), conn);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,8 +420,7 @@ int connection_dir_finished_flushing(connection_t *conn) {
|
|||||||
assert(conn && conn->type == CONN_TYPE_DIR);
|
assert(conn && conn->type == CONN_TYPE_DIR);
|
||||||
|
|
||||||
switch(conn->state) {
|
switch(conn->state) {
|
||||||
case DIR_CONN_STATE_CONNECTING_FETCH:
|
case DIR_CONN_STATE_CONNECTING:
|
||||||
case DIR_CONN_STATE_CONNECTING_UPLOAD:
|
|
||||||
if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { /* not yet */
|
if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { /* not yet */
|
||||||
if(!ERRNO_CONN_EINPROGRESS(errno)) {
|
if(!ERRNO_CONN_EINPROGRESS(errno)) {
|
||||||
log_fn(LOG_DEBUG,"in-progress connect failed. Removing.");
|
log_fn(LOG_DEBUG,"in-progress connect failed. Removing.");
|
||||||
@ -329,16 +436,12 @@ int connection_dir_finished_flushing(connection_t *conn) {
|
|||||||
log_fn(LOG_INFO,"Dir connection to router %s:%u established.",
|
log_fn(LOG_INFO,"Dir connection to router %s:%u established.",
|
||||||
conn->address,conn->port);
|
conn->address,conn->port);
|
||||||
|
|
||||||
return directory_send_command(conn, conn->state);
|
conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
|
||||||
case DIR_CONN_STATE_CLIENT_SENDING_FETCH:
|
|
||||||
log_fn(LOG_DEBUG,"client finished sending fetch command.");
|
|
||||||
conn->state = DIR_CONN_STATE_CLIENT_READING_FETCH;
|
|
||||||
connection_watch_events(conn, POLLIN);
|
|
||||||
return 0;
|
return 0;
|
||||||
case DIR_CONN_STATE_CLIENT_SENDING_UPLOAD:
|
case DIR_CONN_STATE_CLIENT_SENDING:
|
||||||
log_fn(LOG_DEBUG,"client finished sending upload command.");
|
log_fn(LOG_DEBUG,"client finished sending command.");
|
||||||
conn->state = DIR_CONN_STATE_CLIENT_READING_UPLOAD;
|
conn->state = DIR_CONN_STATE_CLIENT_READING;
|
||||||
connection_watch_events(conn, POLLIN);
|
connection_stop_writing(conn);
|
||||||
return 0;
|
return 0;
|
||||||
case DIR_CONN_STATE_SERVER_WRITING:
|
case DIR_CONN_STATE_SERVER_WRITING:
|
||||||
log_fn(LOG_INFO,"Finished writing server response. Closing.");
|
log_fn(LOG_INFO,"Finished writing server response. Closing.");
|
||||||
|
@ -329,7 +329,7 @@ static void run_scheduled_events(time_t now) {
|
|||||||
/* NOTE directory servers do not currently fetch directories.
|
/* NOTE directory servers do not currently fetch directories.
|
||||||
* Hope this doesn't bite us later. */
|
* Hope this doesn't bite us later. */
|
||||||
directory_initiate_command(router_pick_directory_server(),
|
directory_initiate_command(router_pick_directory_server(),
|
||||||
DIR_CONN_STATE_CONNECTING_FETCH);
|
DIR_PURPOSE_FETCH_DIR, NULL);
|
||||||
} else {
|
} else {
|
||||||
/* We're a directory; dump any old descriptors. */
|
/* We're a directory; dump any old descriptors. */
|
||||||
dirserv_remove_old_servers();
|
dirserv_remove_old_servers();
|
||||||
@ -519,7 +519,8 @@ static int do_hup(void) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* fetch a new directory */
|
/* fetch a new directory */
|
||||||
directory_initiate_command(router_pick_directory_server(), DIR_CONN_STATE_CONNECTING_FETCH);
|
directory_initiate_command(router_pick_directory_server(),
|
||||||
|
DIR_PURPOSE_FETCH_DIR, NULL);
|
||||||
}
|
}
|
||||||
if(options.ORPort) {
|
if(options.ORPort) {
|
||||||
router_rebuild_descriptor();
|
router_rebuild_descriptor();
|
||||||
|
26
src/or/or.h
26
src/or/or.h
@ -171,15 +171,20 @@
|
|||||||
#define _AP_CONN_STATE_MAX 8
|
#define _AP_CONN_STATE_MAX 8
|
||||||
|
|
||||||
#define _DIR_CONN_STATE_MIN 1
|
#define _DIR_CONN_STATE_MIN 1
|
||||||
#define DIR_CONN_STATE_CONNECTING_FETCH 1
|
#define DIR_CONN_STATE_CONNECTING 1
|
||||||
#define DIR_CONN_STATE_CONNECTING_UPLOAD 2
|
#define DIR_CONN_STATE_CLIENT_SENDING 2
|
||||||
#define DIR_CONN_STATE_CLIENT_SENDING_FETCH 3
|
#define DIR_CONN_STATE_CLIENT_READING 3
|
||||||
#define DIR_CONN_STATE_CLIENT_SENDING_UPLOAD 4
|
#define DIR_CONN_STATE_SERVER_COMMAND_WAIT 4
|
||||||
#define DIR_CONN_STATE_CLIENT_READING_FETCH 5
|
#define DIR_CONN_STATE_SERVER_WRITING 5
|
||||||
#define DIR_CONN_STATE_CLIENT_READING_UPLOAD 6
|
#define _DIR_CONN_STATE_MAX 5
|
||||||
#define DIR_CONN_STATE_SERVER_COMMAND_WAIT 7
|
|
||||||
#define DIR_CONN_STATE_SERVER_WRITING 8
|
#define _DIR_PURPOSE_MIN 1
|
||||||
#define _DIR_CONN_STATE_MAX 8
|
#define DIR_PURPOSE_FETCH_DIR 1
|
||||||
|
#define DIR_PURPOSE_FETCH_HIDSERV 2
|
||||||
|
#define DIR_PURPOSE_UPLOAD_DIR 3
|
||||||
|
#define DIR_PURPOSE_UPLOAD_HIDSERV 4
|
||||||
|
#define DIR_PURPOSE_SERVER 5
|
||||||
|
#define _DIR_PURPOSE_MAX 5
|
||||||
|
|
||||||
#define CIRCUIT_STATE_BUILDING 0 /* I'm the OP, still haven't done all my handshakes */
|
#define CIRCUIT_STATE_BUILDING 0 /* I'm the OP, still haven't done all my handshakes */
|
||||||
#define CIRCUIT_STATE_ONIONSKIN_PENDING 1 /* waiting to process the onionskin */
|
#define CIRCUIT_STATE_ONIONSKIN_PENDING 1 /* waiting to process the onionskin */
|
||||||
@ -331,6 +336,7 @@ struct connection_t {
|
|||||||
|
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint8_t state;
|
uint8_t state;
|
||||||
|
uint8_t purpose; /* only used for DIR types currently */
|
||||||
uint8_t wants_to_read; /* should we start reading again once
|
uint8_t wants_to_read; /* should we start reading again once
|
||||||
* the bandwidth throttler allows it?
|
* the bandwidth throttler allows it?
|
||||||
*/
|
*/
|
||||||
@ -830,7 +836,7 @@ int assign_to_cpuworker(connection_t *cpuworker, unsigned char question_type,
|
|||||||
|
|
||||||
/********************************* directory.c ***************************/
|
/********************************* directory.c ***************************/
|
||||||
|
|
||||||
void directory_initiate_command(routerinfo_t *router, int command);
|
void directory_initiate_command(routerinfo_t *router, int purpose, const char *payload);
|
||||||
int connection_dir_process_inbuf(connection_t *conn);
|
int connection_dir_process_inbuf(connection_t *conn);
|
||||||
int connection_dir_finished_flushing(connection_t *conn);
|
int connection_dir_finished_flushing(connection_t *conn);
|
||||||
|
|
||||||
|
@ -236,12 +236,14 @@ void router_upload_desc_to_dirservers(void) {
|
|||||||
int i;
|
int i;
|
||||||
routerinfo_t *router;
|
routerinfo_t *router;
|
||||||
routerlist_t *rl;
|
routerlist_t *rl;
|
||||||
|
const char *s;
|
||||||
|
|
||||||
router_get_routerlist(&rl);
|
router_get_routerlist(&rl);
|
||||||
if(!rl)
|
if(!rl)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!router_get_my_descriptor()) {
|
s = router_get_my_descriptor();
|
||||||
|
if (!s) {
|
||||||
log_fn(LOG_WARN, "No descriptor; skipping upload");
|
log_fn(LOG_WARN, "No descriptor; skipping upload");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -249,7 +251,7 @@ void router_upload_desc_to_dirservers(void) {
|
|||||||
for(i=0;i<rl->n_routers;i++) {
|
for(i=0;i<rl->n_routers;i++) {
|
||||||
router = rl->routers[i];
|
router = rl->routers[i];
|
||||||
if(router->dir_port > 0)
|
if(router->dir_port > 0)
|
||||||
directory_initiate_command(router, DIR_CONN_STATE_CONNECTING_UPLOAD);
|
directory_initiate_command(router, DIR_PURPOSE_UPLOAD_DIR, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user