2004-11-07 02:33:06 +01:00
/* Copyright 2001-2004 Roger Dingledine.
2005-04-01 22:15:56 +02:00
* Copyright 2004 - 2005 Roger Dingledine , Nick Mathewson . */
2004-11-07 02:33:06 +01:00
/* See LICENSE for licensing information */
2002-09-26 14:09:10 +02:00
/* $Id$ */
2004-11-29 23:25:31 +01:00
const char directory_c_id [ ] = " $Id$ " ;
2002-09-26 14:09:10 +02:00
# include "or.h"
2004-05-09 18:47:25 +02:00
/**
* \ file directory . c
2005-06-11 07:31:17 +02:00
* \ brief Code to send and fetch directories and router
* descriptors via HTTP . Directories use dirserv . c to generate the
* results ; clients use routers . c to parse them .
2004-05-09 18:47:25 +02:00
* */
2004-05-05 04:50:38 +02:00
2004-05-13 01:48:57 +02:00
/* In-points to directory.c:
*
* - directory_post_to_dirservers ( ) , called from
* router_upload_dir_desc_to_dirservers ( ) in router . c
* upload_service_descriptor ( ) in rendservice . c
* - directory_get_from_dirserver ( ) , called from
* rend_client_refetch_renddesc ( ) in rendclient . c
* run_scheduled_events ( ) in main . c
* do_hup ( ) in main . c
* - connection_dir_process_inbuf ( ) , called from
* connection_process_inbuf ( ) in connection . c
* - connection_dir_finished_flushing ( ) , called from
* connection_finished_flushing ( ) in connection . c
* - connection_dir_finished_connecting ( ) , called from
* connection_finished_connecting ( ) in connection . c
*/
2004-10-12 17:55:20 +02:00
static void
directory_initiate_command_trusted_dir ( trusted_dir_server_t * dirserv ,
2005-02-27 10:47:01 +01:00
uint8_t purpose , int private_connection ,
const char * resource ,
2004-11-12 17:39:03 +01:00
const char * payload , size_t payload_len ) ;
2004-10-12 17:55:20 +02:00
static void
directory_initiate_command ( const char * address , uint32_t addr , uint16_t port ,
const char * platform ,
const char * digest , uint8_t purpose ,
2005-02-27 10:47:01 +01:00
int private_connection , const char * resource ,
2004-10-14 04:47:09 +02:00
const char * payload , size_t payload_len ) ;
2004-10-12 17:55:20 +02:00
2004-10-08 07:53:59 +02:00
static void
2004-10-12 17:55:20 +02:00
directory_send_command ( connection_t * conn , const char * platform ,
2004-11-12 17:39:03 +01:00
int purpose , const char * resource ,
const char * payload , size_t payload_len ) ;
2003-09-16 07:41:49 +02:00
static int directory_handle_command ( connection_t * conn ) ;
2005-01-19 23:47:48 +01:00
static int body_is_plausible ( const char * body , size_t body_len , int purpose ) ;
2005-03-14 04:28:46 +01:00
static int purpose_is_private ( uint8_t purpose ) ;
2005-08-24 00:27:17 +02:00
static char * http_get_header ( const char * headers , const char * which ) ;
static char * http_get_origin ( const char * headers , connection_t * conn ) ;
2005-09-12 08:56:42 +02:00
static void connection_dir_download_networkstatus_failed ( connection_t * conn ) ;
2005-09-15 07:19:38 +02:00
static void connection_dir_download_routerdesc_failed ( connection_t * conn ) ;
2005-09-12 08:56:42 +02:00
static void dir_networkstatus_download_failed ( smartlist_t * failed ) ;
2005-09-15 07:19:38 +02:00
static void dir_routerdesc_download_failed ( smartlist_t * failed ) ;
2003-09-16 07:41:49 +02:00
2002-09-26 14:09:10 +02:00
/********* START VARIABLES **********/
2004-12-04 02:14:36 +01:00
static addr_policy_t * dir_policy = NULL ;
2004-10-25 08:16:26 +02:00
2005-04-07 23:09:19 +02:00
# define ALLOW_DIRECTORY_TIME_SKEW 30*60 /* 30 minutes */
2004-08-15 22:30:15 +02:00
2002-09-26 14:09:10 +02:00
/********* END VARIABLES ************/
2004-11-12 20:39:13 +01:00
/** Parse get_options()->DirPolicy, and put the processed version in
* & dir_policy . Ignore port specifiers .
2004-10-25 08:16:26 +02:00
*/
2004-11-12 20:39:13 +01:00
void
parse_dir_policy ( void )
2004-10-25 08:16:26 +02:00
{
2004-12-04 02:14:36 +01:00
addr_policy_t * n ;
2004-10-25 08:16:26 +02:00
if ( dir_policy ) {
2004-11-12 20:39:13 +01:00
addr_policy_free ( dir_policy ) ;
2004-10-25 08:16:26 +02:00
dir_policy = NULL ;
}
2005-08-08 23:58:48 +02:00
config_parse_addr_policy ( get_options ( ) - > DirPolicy , & dir_policy , - 1 ) ;
2004-10-25 08:16:26 +02:00
/* ports aren't used. */
for ( n = dir_policy ; n ; n = n - > next ) {
n - > prt_min = 1 ;
n - > prt_max = 65535 ;
}
}
2005-06-11 20:52:12 +02:00
/** Free storage used to hold parsed directory policy */
2005-02-11 00:18:39 +01:00
void
free_dir_policy ( void )
{
addr_policy_free ( dir_policy ) ;
dir_policy = NULL ;
}
2004-10-25 08:16:26 +02:00
/** Return 1 if <b>addr</b> is permitted to connect to our dir port,
* based on < b > dir_policy < / b > . Else return 0.
*/
2005-06-11 20:52:12 +02:00
int
dir_policy_permits_address ( uint32_t addr )
2004-10-25 08:16:26 +02:00
{
int a ;
2004-11-28 10:05:49 +01:00
if ( ! dir_policy ) /* 'no dir policy' means 'accept' */
2004-10-25 08:16:26 +02:00
return 1 ;
2004-11-12 20:39:13 +01:00
a = router_compare_addr_to_addr_policy ( addr , 1 , dir_policy ) ;
2005-03-19 07:57:16 +01:00
if ( a = = ADDR_POLICY_REJECTED )
2004-10-25 08:16:26 +02:00
return 0 ;
2005-03-19 07:57:16 +01:00
else if ( a = = ADDR_POLICY_ACCEPTED )
2004-10-25 08:16:26 +02:00
return 1 ;
2005-10-25 10:20:10 +02:00
warn ( LD_BUG , " Bug: got unexpected 'maybe' answer from dir policy " ) ;
2004-10-25 08:16:26 +02:00
return 0 ;
}
2005-06-11 20:52:12 +02:00
/** Return true iff the directory purpose 'purpose' must use an
* anonymous connection to a directory . */
2005-03-14 04:28:46 +01:00
static int
2005-06-11 20:52:12 +02:00
purpose_is_private ( uint8_t purpose )
{
2005-02-27 10:47:01 +01:00
if ( purpose = = DIR_PURPOSE_FETCH_DIR | |
purpose = = DIR_PURPOSE_UPLOAD_DIR | |
2005-09-08 20:14:01 +02:00
purpose = = DIR_PURPOSE_FETCH_RUNNING_LIST | |
purpose = = DIR_PURPOSE_FETCH_NETWORKSTATUS | |
purpose = = DIR_PURPOSE_FETCH_SERVERDESC )
2005-02-27 10:47:01 +01:00
return 0 ;
return 1 ;
}
2004-05-13 01:48:57 +02:00
/** Start a connection to every known directory server, using
* connection purpose ' purpose ' and uploading the payload ' payload '
* ( length ' payload_len ' ) . The purpose should be one of
* ' DIR_PURPOSE_UPLOAD_DIR ' or ' DIR_PURPOSE_UPLOAD_RENDDESC ' .
*/
void
directory_post_to_dirservers ( uint8_t purpose , const char * payload ,
2004-10-14 04:47:09 +02:00
size_t payload_len )
2004-05-13 01:48:57 +02:00
{
2004-10-15 21:04:38 +02:00
smartlist_t * dirservers ;
2004-05-13 01:48:57 +02:00
2004-10-15 21:04:38 +02:00
router_get_trusted_dir_servers ( & dirservers ) ;
tor_assert ( dirservers ) ;
2004-10-15 21:17:36 +02:00
/* This tries dirservers which we believe to be down, but ultimately, that's
* harmless , and we may as well err on the side of getting things uploaded .
*/
2004-10-15 21:04:38 +02:00
SMARTLIST_FOREACH ( dirservers , trusted_dir_server_t * , ds ,
{
/* Pay attention to fascistfirewall when we're uploading a
* router descriptor , but not when uploading a service
* descriptor - - those use Tor . */
2005-08-07 23:24:00 +02:00
if ( purpose = = DIR_PURPOSE_UPLOAD_DIR & & ! get_options ( ) - > HttpProxy ) {
2005-08-08 23:58:48 +02:00
if ( ! fascist_firewall_allows_address ( ds - > addr , ds - > dir_port ) )
2004-10-15 21:04:38 +02:00
continue ;
}
2005-09-30 01:06:48 +02:00
directory_initiate_command_trusted_dir ( ds , purpose ,
purpose_is_private ( purpose ) ,
2005-02-27 10:47:01 +01:00
NULL , payload , payload_len ) ;
2004-10-15 21:04:38 +02:00
} ) ;
2004-05-13 01:48:57 +02:00
}
2004-11-15 04:53:03 +01:00
/** Start a connection to a random running directory server, using
* connection purpose ' purpose ' requesting ' resource ' . The purpose
* should be one of ' DIR_PURPOSE_FETCH_DIR ' ,
* ' DIR_PURPOSE_FETCH_RENDDESC ' , ' DIR_PURPOSE_FETCH_RUNNING_LIST . '
2005-01-03 21:51:24 +01:00
* If < b > retry_if_no_servers < / b > , then if all the possible servers seem
* down , mark them up and try again .
2004-05-13 01:48:57 +02:00
*/
void
2005-01-03 21:51:24 +01:00
directory_get_from_dirserver ( uint8_t purpose , const char * resource ,
int retry_if_no_servers )
2004-05-13 01:48:57 +02:00
{
2004-10-12 17:55:20 +02:00
routerinfo_t * r = NULL ;
trusted_dir_server_t * ds = NULL ;
2005-08-08 23:58:48 +02:00
int fascistfirewall = firewall_is_fascist ( ) ;
2005-09-08 20:14:01 +02:00
or_options_t * options = get_options ( ) ;
int fetch_fresh_first = server_mode ( options ) & & options - > DirPort ! = 0 ;
int directconn = ! purpose_is_private ( purpose ) ;
2005-09-08 08:22:44 +02:00
int need_v1_support = purpose = = DIR_PURPOSE_FETCH_DIR | |
purpose = = DIR_PURPOSE_FETCH_RUNNING_LIST ;
2005-09-08 18:18:28 +02:00
int need_v2_support = purpose = = DIR_PURPOSE_FETCH_NETWORKSTATUS | |
purpose = = DIR_PURPOSE_FETCH_SERVERDESC ;
2004-07-20 08:44:16 +02:00
2005-01-10 18:39:41 +01:00
if ( directconn ) {
2005-09-08 08:22:44 +02:00
if ( fetch_fresh_first & & purpose = = DIR_PURPOSE_FETCH_NETWORKSTATUS & &
2005-09-08 20:46:25 +02:00
! strcmpstart ( resource , " fp/ " ) & & strlen ( resource ) = = HEX_DIGEST_LEN + 3 ) {
2005-09-08 08:22:44 +02:00
/* Try to ask the actual dirserver its opinion. */
char digest [ DIGEST_LEN ] ;
2005-09-08 20:46:25 +02:00
base16_decode ( digest , DIGEST_LEN , resource + 3 , HEX_DIGEST_LEN ) ;
2005-09-08 08:22:44 +02:00
ds = router_get_trusteddirserver_by_digest ( digest ) ;
}
if ( ! ds & & fetch_fresh_first ) {
2004-07-21 02:12:42 +02:00
/* only ask authdirservers, and don't ask myself */
2005-09-08 08:22:44 +02:00
ds = router_pick_trusteddirserver ( need_v1_support , 1 , fascistfirewall ,
2005-01-03 21:51:24 +01:00
retry_if_no_servers ) ;
2005-01-10 18:39:41 +01:00
}
if ( ! ds ) {
2004-07-20 08:44:16 +02:00
/* anybody with a non-zero dirport will do */
2005-09-08 18:18:28 +02:00
r = router_pick_directory_server ( 1 , fascistfirewall , need_v2_support ,
2005-01-03 21:51:24 +01:00
retry_if_no_servers ) ;
2004-10-14 03:44:32 +02:00
if ( ! r ) {
2005-09-08 08:22:44 +02:00
const char * which ;
if ( purpose = = DIR_PURPOSE_FETCH_DIR )
which = " directory " ;
else if ( purpose = = DIR_PURPOSE_FETCH_RUNNING_LIST )
which = " status list " ;
else if ( purpose = = DIR_PURPOSE_FETCH_NETWORKSTATUS )
which = " network status " ;
else // if (purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS)
which = " server descriptors " ;
2005-10-25 10:20:10 +02:00
info ( LD_DIR ,
" No router found for %s; falling back to dirserver list " , which ) ;
2005-09-07 18:42:53 +02:00
ds = router_pick_trusteddirserver ( 1 , 1 , fascistfirewall ,
2005-01-03 21:51:24 +01:00
retry_if_no_servers ) ;
2004-10-14 03:44:32 +02:00
}
2004-07-20 08:44:16 +02:00
}
} else { // (purpose == DIR_PURPOSE_FETCH_RENDDESC)
/* only ask authdirservers, any of them will do */
2004-10-15 06:57:36 +02:00
/* Never use fascistfirewall; we're going via Tor. */
2005-09-07 18:42:53 +02:00
ds = router_pick_trusteddirserver ( 0 , 0 , 0 , retry_if_no_servers ) ;
2004-07-20 08:44:16 +02:00
}
2004-10-12 17:55:20 +02:00
if ( r )
2005-09-30 01:06:48 +02:00
directory_initiate_command_router ( r , purpose , ! directconn ,
resource , NULL , 0 ) ;
2004-10-12 17:55:20 +02:00
else if ( ds )
2005-09-30 01:06:48 +02:00
directory_initiate_command_trusted_dir ( ds , purpose , ! directconn ,
resource , NULL , 0 ) ;
2005-01-03 21:51:24 +01:00
else {
2005-10-25 10:20:10 +02:00
notice ( LD_DIR ,
" No running dirservers known. Will try again later. (purpose %d) " ,
2005-01-10 18:39:41 +01:00
purpose ) ;
2005-02-05 22:42:46 +01:00
if ( directconn ) {
2005-01-10 18:39:41 +01:00
/* remember we tried them all and failed. */
2005-02-05 22:42:46 +01:00
directory_all_unreachable ( time ( NULL ) ) ;
2005-01-10 18:39:41 +01:00
}
2005-01-03 21:51:24 +01:00
}
2004-05-13 01:48:57 +02:00
}
2004-05-10 06:34:48 +02:00
/** Launch a new connection to the directory server <b>router</b> to upload or
* download a service or rendezvous descriptor . < b > purpose < / b > determines what
2004-05-05 04:50:38 +02:00
* kind of directory connection we ' re launching , and must be one of
* DIR_PURPOSE_ { FETCH | UPLOAD } _ { DIR | RENDDESC } .
*
2004-05-10 06:34:48 +02:00
* When uploading , < b > payload < / b > and < b > payload_len < / b > determine the content
2004-11-12 17:39:03 +01:00
* of the HTTP post . Otherwise , < b > payload < / b > should be NULL .
*
* When fetching a rendezvous descriptor , < b > resource < / b > is the service ID we
* want to fetch .
2004-05-05 04:50:38 +02:00
*/
2005-02-27 10:47:01 +01:00
void
2004-10-12 17:55:20 +02:00
directory_initiate_command_router ( routerinfo_t * router , uint8_t purpose ,
2005-02-27 10:47:01 +01:00
int private_connection , const char * resource ,
2004-10-14 04:47:09 +02:00
const char * payload , size_t payload_len )
2004-10-12 17:55:20 +02:00
{
directory_initiate_command ( router - > address , router - > addr , router - > dir_port ,
2005-11-05 21:15:27 +01:00
router - > platform , router - > cache_info . identity_digest ,
purpose , private_connection , resource ,
payload , payload_len ) ;
2004-10-12 17:55:20 +02:00
}
2004-11-12 17:39:03 +01:00
/** As directory_initiate_command_router, but send the command to a trusted
* directory server < b > dirserv < / b > . * */
2004-10-12 17:55:20 +02:00
static void
directory_initiate_command_trusted_dir ( trusted_dir_server_t * dirserv ,
2005-02-27 10:47:01 +01:00
uint8_t purpose , int private_connection ,
const char * resource ,
2004-11-12 17:39:03 +01:00
const char * payload , size_t payload_len )
2004-10-12 17:55:20 +02:00
{
2005-09-30 01:06:48 +02:00
directory_initiate_command ( dirserv - > address , dirserv - > addr ,
dirserv - > dir_port , NULL , dirserv - > digest , purpose ,
private_connection , resource ,
2005-02-27 10:47:01 +01:00
payload , payload_len ) ;
2004-10-12 17:55:20 +02:00
}
2005-09-12 09:36:26 +02:00
/** Called when we are unable to complete the client's request to a
2005-01-03 21:07:07 +01:00
* directory server : Mark the router as down and try again if possible .
*/
2005-01-04 02:16:20 +01:00
void
2005-09-12 09:36:26 +02:00
connection_dir_request_failed ( connection_t * conn )
2005-01-03 21:07:07 +01:00
{
2005-09-14 05:49:17 +02:00
if ( router_digest_is_me ( conn - > identity_digest ) )
return ; /* this was a test fetch. don't retry. */
2005-01-03 21:07:07 +01:00
router_mark_as_down ( conn - > identity_digest ) ; /* don't try him again */
if ( conn - > purpose = = DIR_PURPOSE_FETCH_DIR | |
conn - > purpose = = DIR_PURPOSE_FETCH_RUNNING_LIST ) {
2005-10-25 10:20:10 +02:00
info ( LD_DIR , " Giving up on directory server at '%s:%d'; retrying " ,
2005-09-12 09:36:26 +02:00
conn - > address , conn - > port ) ;
2005-01-03 21:51:24 +01:00
directory_get_from_dirserver ( conn - > purpose , NULL ,
0 /* don't retry_if_no_servers */ ) ;
2005-09-12 08:56:42 +02:00
} else if ( conn - > purpose = = DIR_PURPOSE_FETCH_NETWORKSTATUS ) {
2005-10-25 10:20:10 +02:00
info ( LD_DIR , " Giving up on directory server at '%s'; retrying " ,
2005-09-12 08:56:42 +02:00
conn - > address ) ;
connection_dir_download_networkstatus_failed ( conn ) ;
2005-09-18 04:51:12 +02:00
} else if ( conn - > purpose = = DIR_PURPOSE_FETCH_SERVERDESC ) {
2005-10-25 10:20:10 +02:00
info ( LD_DIR , " Giving up on directory server at '%s'; retrying " ,
2005-09-15 07:19:38 +02:00
conn - > address ) ;
connection_dir_download_routerdesc_failed ( conn ) ;
2005-01-03 21:07:07 +01:00
}
}
2005-09-30 01:26:42 +02:00
/** Called when an attempt to download one or more network status
* documents on connection < b > conn < / b > failed . Decide whether to
* retry the fetch now , later , or never .
2005-09-13 23:14:55 +02:00
*/
2005-09-12 08:56:42 +02:00
static void
connection_dir_download_networkstatus_failed ( connection_t * conn )
{
2005-09-26 18:37:39 +02:00
if ( ! conn - > requested_resource ) {
/* We never reached directory_send_command, which means that we never
* opened a network connection . Either we ' re out of sockets , or the
* network is down . Either way , retrying would be pointless . */
return ;
}
2005-09-13 23:14:55 +02:00
if ( ! strcmpstart ( conn - > requested_resource , " all " ) ) {
/* We're a non-authoritative directory cache; try again. */
directory_get_from_dirserver ( conn - > purpose , " all.z " ,
0 /* don't retry_if_no_servers */ ) ;
} else if ( ! strcmpstart ( conn - > requested_resource , " fp/ " ) ) {
/* We were trying to download by fingerprint; mark them all has having
* failed , and possibly retry them later . */
smartlist_t * failed = smartlist_create ( ) ;
2005-09-16 06:42:45 +02:00
dir_split_resource_into_fingerprints ( conn - > requested_resource + 3 ,
2005-10-14 06:56:20 +02:00
failed , NULL , 0 ) ;
2005-09-13 23:14:55 +02:00
if ( smartlist_len ( failed ) ) {
dir_networkstatus_download_failed ( failed ) ;
SMARTLIST_FOREACH ( failed , char * , cp , tor_free ( cp ) ) ;
2005-09-12 08:56:42 +02:00
}
2005-09-13 23:14:55 +02:00
smartlist_free ( failed ) ;
}
2005-09-12 08:56:42 +02:00
}
2005-09-30 01:26:42 +02:00
/** Called when an attempt to download one or more router descriptors
2005-09-15 07:19:38 +02:00
* on connection < b > conn < / b > failed .
*/
static void
connection_dir_download_routerdesc_failed ( connection_t * conn )
{
2005-09-22 08:34:29 +02:00
/* Try again. No need to increment the failure count for routerdescs, since
* it ' s not their fault . */
2005-09-23 20:05:14 +02:00
/* update_router_descriptor_downloads(time(NULL)); */
2005-09-15 07:19:38 +02:00
}
2005-01-12 05:58:23 +01:00
/** Helper for directory_initiate_command_(router|trusted_dir): send the
2004-11-12 17:39:03 +01:00
* command to a server whose address is < b > address < / b > , whose IP is
* < b > addr < / b > , whose directory port is < b > dir_port < / b > , whose tor version is
* < b > platform < / b > , and whose identity key digest is < b > digest < / b > . The
* < b > platform < / b > argument is optional ; the others are required . */
2004-10-12 17:55:20 +02:00
static void
directory_initiate_command ( const char * address , uint32_t addr ,
uint16_t dir_port , const char * platform ,
const char * digest , uint8_t purpose ,
2005-02-27 10:47:01 +01:00
int private_connection , const char * resource ,
2004-10-14 04:47:09 +02:00
const char * payload , size_t payload_len )
2004-05-13 01:48:57 +02:00
{
2002-09-26 14:09:10 +02:00
connection_t * conn ;
2004-10-17 00:14:52 +02:00
tor_assert ( address ) ;
tor_assert ( addr ) ;
tor_assert ( dir_port ) ;
tor_assert ( digest ) ;
2004-07-20 08:44:16 +02:00
2004-10-08 07:53:59 +02:00
switch ( purpose ) {
2004-05-05 04:50:38 +02:00
case DIR_PURPOSE_FETCH_DIR :
2005-10-25 10:20:10 +02:00
debug ( LD_DIR , " initiating directory fetch " ) ;
2004-05-05 04:50:38 +02:00
break ;
case DIR_PURPOSE_FETCH_RENDDESC :
2005-10-25 10:20:10 +02:00
debug ( LD_DIR , " initiating hidden-service descriptor fetch " ) ;
2004-05-05 04:50:38 +02:00
break ;
case DIR_PURPOSE_UPLOAD_DIR :
2005-10-25 10:20:10 +02:00
debug ( LD_OR , " initiating server descriptor upload " ) ;
2004-05-05 04:50:38 +02:00
break ;
case DIR_PURPOSE_UPLOAD_RENDDESC :
2005-10-25 10:20:10 +02:00
debug ( LD_REND , " initiating hidden-service descriptor upload " ) ;
2004-05-05 04:50:38 +02:00
break ;
2004-11-14 22:35:30 +01:00
case DIR_PURPOSE_FETCH_RUNNING_LIST :
2005-10-25 10:20:10 +02:00
debug ( LD_DIR , " initiating running-routers fetch " ) ;
2004-11-14 22:35:30 +01:00
break ;
2005-09-07 22:03:02 +02:00
case DIR_PURPOSE_FETCH_NETWORKSTATUS :
2005-10-25 10:20:10 +02:00
debug ( LD_DIR , " initiating network-status fetch " ) ;
2005-09-07 22:03:02 +02:00
break ;
case DIR_PURPOSE_FETCH_SERVERDESC :
2005-10-25 10:20:10 +02:00
debug ( LD_DIR , " initiating server descriptor fetch " ) ;
2005-09-07 22:03:02 +02:00
break ;
2004-05-05 04:50:38 +02:00
default :
2005-10-25 10:20:10 +02:00
err ( LD_BUG , " Unrecognized directory connection purpose. " ) ;
2004-05-05 04:50:38 +02:00
tor_assert ( 0 ) ;
2004-10-08 07:53:59 +02:00
}
2002-09-28 07:53:00 +02:00
2002-09-26 14:09:10 +02:00
conn = connection_new ( CONN_TYPE_DIR ) ;
/* set up conn so it's got all the data we need to remember */
2004-10-17 06:06:48 +02:00
conn - > addr = addr ;
conn - > port = dir_port ;
2004-10-12 17:55:20 +02:00
conn - > address = tor_strdup ( address ) ;
memcpy ( conn - > identity_digest , digest , DIGEST_LEN ) ;
2002-09-26 14:09:10 +02:00
2004-03-31 00:57:49 +02:00
conn - > purpose = purpose ;
2004-03-26 23:07:45 +01:00
2004-04-17 22:19:43 +02:00
/* give it an initial state */
conn - > state = DIR_CONN_STATE_CONNECTING ;
2005-02-27 10:47:01 +01:00
if ( ! private_connection ) {
2004-03-31 00:57:49 +02:00
/* then we want to connect directly */
2005-02-27 10:47:01 +01:00
if ( get_options ( ) - > HttpProxy ) {
addr = get_options ( ) - > HttpProxyAddr ;
dir_port = get_options ( ) - > HttpProxyPort ;
}
2004-11-28 10:05:49 +01:00
switch ( connection_connect ( conn , conn - > address , addr , dir_port ) ) {
2004-03-31 00:57:49 +02:00
case - 1 :
2005-09-12 09:36:26 +02:00
connection_dir_request_failed ( conn ) ; /* retry if we want */
2004-05-05 03:26:57 +02:00
connection_free ( conn ) ;
2004-03-31 00:57:49 +02:00
return ;
case 1 :
conn - > state = DIR_CONN_STATE_CLIENT_SENDING ; /* start flushing conn */
/* fall through */
case 0 :
2004-05-09 18:33:04 +02:00
/* queue the command on the outbuf */
2004-11-12 17:39:03 +01:00
directory_send_command ( conn , platform , purpose , resource ,
payload , payload_len ) ;
2005-01-12 07:42:32 +01:00
connection_watch_events ( conn , EV_READ | EV_WRITE ) ;
2004-03-31 00:57:49 +02:00
/* writable indicates finish, readable indicates broken link,
error indicates broken link in windowsland . */
}
} else { /* we want to connect via tor */
/* make an AP connection
2004-07-20 08:44:16 +02:00
* populate it and add it at the right state
2004-03-31 00:57:49 +02:00
* socketpair and hook up both sides
*/
2004-04-01 00:02:13 +02:00
conn - > s = connection_ap_make_bridge ( conn - > address , conn - > port ) ;
2004-11-28 10:05:49 +01:00
if ( conn - > s < 0 ) {
2005-10-25 10:20:10 +02:00
warn ( LD_NET , " Making AP bridge to dirserver failed. " ) ;
2004-05-12 23:12:33 +02:00
connection_mark_for_close ( conn ) ;
2004-04-01 00:02:13 +02:00
return ;
}
2004-03-31 00:57:49 +02:00
2004-04-07 21:57:40 +02:00
conn - > state = DIR_CONN_STATE_CLIENT_SENDING ;
2004-05-05 03:26:57 +02:00
connection_add ( conn ) ;
2004-05-09 18:33:04 +02:00
/* queue the command on the outbuf */
2004-11-12 17:39:03 +01:00
directory_send_command ( conn , platform , purpose , resource ,
payload , payload_len ) ;
2005-01-12 07:42:32 +01:00
connection_watch_events ( conn , EV_READ | EV_WRITE ) ;
2002-09-26 14:09:10 +02:00
}
}
2004-11-12 22:59:27 +01:00
/** Queue an appropriate HTTP command on conn-\>outbuf. The other args
* are as in directory_initiate_command .
2004-05-05 04:50:38 +02:00
*/
2004-10-08 07:53:59 +02:00
static void
2004-10-12 17:55:20 +02:00
directory_send_command ( connection_t * conn , const char * platform ,
2004-11-12 17:39:03 +01:00
int purpose , const char * resource ,
2005-06-11 20:52:12 +02:00
const char * payload , size_t payload_len )
{
2005-05-20 10:51:45 +02:00
char proxystring [ 256 ] ;
char proxyauthstring [ 256 ] ;
2004-10-08 07:53:59 +02:00
char hoststring [ 128 ] ;
2005-09-07 22:03:02 +02:00
char * url ;
char request [ 8192 ] ;
2004-10-27 23:14:11 +02:00
const char * httpcommand = NULL ;
2005-09-07 22:03:02 +02:00
size_t len ;
2002-09-26 14:09:10 +02:00
2004-10-17 00:14:52 +02:00
tor_assert ( conn ) ;
tor_assert ( conn - > type = = CONN_TYPE_DIR ) ;
2004-09-27 05:39:30 +02:00
2005-09-08 22:18:15 +02:00
tor_free ( conn - > requested_resource ) ;
2005-09-08 22:36:40 +02:00
if ( resource )
conn - > requested_resource = tor_strdup ( resource ) ;
2005-09-08 22:18:15 +02:00
2005-05-20 10:51:45 +02:00
/* come up with a string for which Host: we want */
2004-11-28 10:05:49 +01:00
if ( conn - > port = = 80 ) {
2004-10-12 17:55:20 +02:00
strlcpy ( hoststring , conn - > address , sizeof ( hoststring ) ) ;
2004-10-08 07:53:59 +02:00
} else {
2004-10-27 08:37:34 +02:00
tor_snprintf ( hoststring , sizeof ( hoststring ) , " %s:%d " , conn - > address , conn - > port ) ;
2004-10-08 07:53:59 +02:00
}
2005-05-20 10:51:45 +02:00
/* come up with some proxy lines, if we're using one. */
2004-11-28 10:05:49 +01:00
if ( get_options ( ) - > HttpProxy ) {
2005-05-20 10:51:45 +02:00
char * base64_authenticator = NULL ;
const char * authenticator = get_options ( ) - > HttpProxyAuthenticator ;
2004-10-27 08:37:34 +02:00
tor_snprintf ( proxystring , sizeof ( proxystring ) , " http://%s " , hoststring ) ;
2005-05-20 10:51:45 +02:00
if ( authenticator ) {
base64_authenticator = alloc_http_authenticator ( authenticator ) ;
if ( ! base64_authenticator )
2005-10-25 10:20:10 +02:00
warn ( LD_BUG , " Encoding http authenticator failed " ) ;
2005-05-20 10:51:45 +02:00
}
if ( base64_authenticator ) {
tor_snprintf ( proxyauthstring , sizeof ( proxyauthstring ) ,
" \r \n Proxy-Authorization: Basic %s " ,
base64_authenticator ) ;
tor_free ( base64_authenticator ) ;
} else {
proxyauthstring [ 0 ] = 0 ;
}
2004-10-08 07:53:59 +02:00
} else {
proxystring [ 0 ] = 0 ;
2005-05-20 10:51:45 +02:00
proxyauthstring [ 0 ] = 0 ;
2004-10-08 07:53:59 +02:00
}
2004-11-28 10:05:49 +01:00
switch ( purpose ) {
2004-03-31 00:57:49 +02:00
case DIR_PURPOSE_FETCH_DIR :
2004-11-12 17:39:03 +01:00
tor_assert ( ! resource ) ;
tor_assert ( ! payload ) ;
2005-10-25 10:20:10 +02:00
debug ( LD_DIR , " Asking for compressed directory from server running %s " ,
2005-05-03 12:12:08 +02:00
platform ? platform : " <unknown version> " ) ;
2004-10-08 07:53:59 +02:00
httpcommand = " GET " ;
2005-09-07 22:03:02 +02:00
url = tor_strdup ( " /tor/dir.z " ) ;
2004-06-16 23:08:29 +02:00
break ;
case DIR_PURPOSE_FETCH_RUNNING_LIST :
2004-11-12 17:39:03 +01:00
tor_assert ( ! resource ) ;
tor_assert ( ! payload ) ;
2004-10-08 07:53:59 +02:00
httpcommand = " GET " ;
2005-09-07 22:03:02 +02:00
url = tor_strdup ( " /tor/running-routers " ) ;
break ;
case DIR_PURPOSE_FETCH_NETWORKSTATUS :
2005-09-08 22:36:40 +02:00
httpcommand = " GET " ;
2005-09-07 22:03:02 +02:00
len = strlen ( resource ) + 32 ;
url = tor_malloc ( len ) ;
tor_snprintf ( url , len , " /tor/status/%s " , resource ) ;
break ;
case DIR_PURPOSE_FETCH_SERVERDESC :
2005-09-08 22:36:40 +02:00
httpcommand = " GET " ;
2005-09-07 22:03:02 +02:00
len = strlen ( resource ) + 32 ;
url = tor_malloc ( len ) ;
tor_snprintf ( url , len , " /tor/server/%s " , resource ) ;
2003-09-17 22:09:06 +02:00
break ;
2004-03-31 00:57:49 +02:00
case DIR_PURPOSE_UPLOAD_DIR :
2004-11-12 17:39:03 +01:00
tor_assert ( ! resource ) ;
2004-04-25 22:37:37 +02:00
tor_assert ( payload ) ;
2004-10-08 07:53:59 +02:00
httpcommand = " POST " ;
2005-09-07 22:03:02 +02:00
url = tor_strdup ( " /tor/ " ) ;
2004-03-31 00:57:49 +02:00
break ;
2004-04-01 23:32:01 +02:00
case DIR_PURPOSE_FETCH_RENDDESC :
2004-11-12 17:39:03 +01:00
tor_assert ( resource ) ;
tor_assert ( ! payload ) ;
2004-04-01 23:32:01 +02:00
/* this must be true or we wouldn't be doing the lookup */
2004-11-12 22:59:27 +01:00
tor_assert ( strlen ( resource ) < = REND_SERVICE_ID_LEN ) ;
2004-05-05 04:50:38 +02:00
/* This breaks the function abstraction. */
2004-11-12 17:39:03 +01:00
strlcpy ( conn - > rend_query , resource , sizeof ( conn - > rend_query ) ) ;
2004-04-01 23:32:01 +02:00
2004-10-08 07:53:59 +02:00
httpcommand = " GET " ;
2005-08-12 17:05:05 +02:00
/* Request the most recent versioned descriptor. */
2005-09-06 08:14:38 +02:00
// XXXX011
//tor_snprintf(url, sizeof(url), "/tor/rendezvous1/%s", resource);
2005-09-07 22:03:02 +02:00
len = strlen ( resource ) + 32 ;
url = tor_malloc ( len ) ;
tor_snprintf ( url , len , " /tor/rendezvous/%s " , resource ) ;
2004-03-31 00:57:49 +02:00
break ;
2004-04-01 23:32:01 +02:00
case DIR_PURPOSE_UPLOAD_RENDDESC :
2004-11-12 17:39:03 +01:00
tor_assert ( ! resource ) ;
2004-04-25 22:37:37 +02:00
tor_assert ( payload ) ;
2004-10-08 07:53:59 +02:00
httpcommand = " POST " ;
2005-09-07 22:03:02 +02:00
url = tor_strdup ( " /tor/rendezvous/publish " ) ;
2003-09-17 22:09:06 +02:00
break ;
2005-09-08 08:22:44 +02:00
default :
tor_assert ( 0 ) ;
return ;
2002-09-26 14:09:10 +02:00
}
2005-09-07 22:03:02 +02:00
tor_snprintf ( request , sizeof ( request ) , " %s %s " , httpcommand , proxystring ) ;
connection_write_to_buf ( request , strlen ( request ) , conn ) ;
connection_write_to_buf ( url , strlen ( url ) , conn ) ;
tor_free ( url ) ;
2004-10-08 07:53:59 +02:00
2005-09-08 08:22:44 +02:00
tor_snprintf ( request , sizeof ( request ) , " HTTP/1.0 \r \n Content-Length: %lu \r \n Host: %s%s \r \n \r \n " ,
2004-11-12 22:59:27 +01:00
payload ? ( unsigned long ) payload_len : 0 ,
2005-05-20 10:51:45 +02:00
hoststring ,
proxyauthstring ) ;
2005-09-07 22:03:02 +02:00
connection_write_to_buf ( request , strlen ( request ) , conn ) ;
2004-11-28 10:05:49 +01:00
if ( payload ) {
2004-10-08 07:53:59 +02:00
/* then send the payload afterwards too */
connection_write_to_buf ( payload , payload_len , conn ) ;
}
2004-03-31 00:57:49 +02:00
}
2004-10-08 07:53:59 +02:00
/** Parse an HTTP request string <b>headers</b> of the form
2005-05-17 19:01:36 +02:00
* \ verbatim
2004-10-08 07:53:59 +02:00
* " \ %s [http[s]://] \ %s HTTP/1... "
2005-05-17 19:01:36 +02:00
* \ endverbatim
2004-09-27 05:39:30 +02:00
* If it ' s well - formed , strdup the second \ % s into * < b > url < / b > , and
* null - terminate it . If the url doesn ' t start with " /tor/ " , rewrite it
* so it does . Return 0.
2004-03-31 00:57:49 +02:00
* Otherwise , return - 1.
*/
2004-05-13 01:48:57 +02:00
static int
parse_http_url ( char * headers , char * * url )
{
2004-10-08 07:53:59 +02:00
char * s , * start , * tmp ;
2004-03-31 00:57:49 +02:00
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 ;
2004-09-27 05:39:30 +02:00
start = s ; /* this is it, assuming it's valid */
2004-09-27 08:45:32 +02:00
s = ( char * ) find_whitespace ( start ) ;
2004-03-31 00:57:49 +02:00
if ( ! * s ) return - 1 ;
2004-10-08 07:53:59 +02:00
/* tolerate the http[s] proxy style of putting the hostname in the url */
2004-11-28 10:05:49 +01:00
if ( s - start > = 4 & & ! strcmpstart ( start , " http " ) ) {
2004-10-08 07:53:59 +02:00
tmp = start + 4 ;
2004-11-28 10:05:49 +01:00
if ( * tmp = = ' s ' )
2004-10-08 07:53:59 +02:00
tmp + + ;
2004-11-28 10:05:49 +01:00
if ( s - tmp > = 3 & & ! strcmpstart ( tmp , " :// " ) ) {
2004-10-08 07:53:59 +02:00
tmp = strchr ( tmp + 3 , ' / ' ) ;
2004-11-28 10:05:49 +01:00
if ( tmp & & tmp < s ) {
2005-10-25 10:20:10 +02:00
debug ( LD_DIR , " Skipping over 'http[s]://hostname' string " ) ;
2004-10-08 07:53:59 +02:00
start = tmp ;
}
}
}
2004-11-28 10:05:49 +01:00
if ( s - start < 5 | | strcmpstart ( start , " /tor/ " ) ) { /* need to rewrite it */
2004-09-27 05:39:30 +02:00
* url = tor_malloc ( s - start + 5 ) ;
2004-10-27 08:48:16 +02:00
strlcpy ( * url , " /tor " , s - start + 5 ) ;
strlcat ( ( * url ) + 4 , start , s - start + 1 ) ;
2004-09-27 05:39:30 +02:00
} else {
* url = tor_strndup ( start , s - start ) ;
}
2002-09-26 14:09:10 +02:00
return 0 ;
}
2005-08-24 00:27:17 +02:00
/** Return a copy of the first HTTP header in <b>headers</b> whose key is
* < b > which < / b > . The key should be given with a terminating colon and space ;
* this function copies everything after , up to but not including the
2005-09-09 04:02:20 +02:00
* following \ \ r \ \ n . */
2005-08-24 00:27:17 +02:00
static char *
http_get_header ( const char * headers , const char * which )
{
const char * cp = headers ;
while ( cp ) {
if ( ! strcmpstart ( cp , which ) ) {
char * eos ;
cp + = strlen ( which ) ;
2005-09-09 04:02:20 +02:00
if ( ( eos = strchr ( cp , ' \r ' ) ) )
2005-08-24 00:27:17 +02:00
return tor_strndup ( cp , eos - cp ) ;
else
return tor_strdup ( cp ) ;
}
2005-08-24 14:14:44 +02:00
cp = strchr ( cp , ' \n ' ) ;
2005-08-24 00:27:17 +02:00
if ( cp )
+ + cp ;
}
return NULL ;
}
/** Allocate and return a string describing the source of an HTTP request with
* headers < b > headers < / b > received on < b > conn < / b > . The format is either
* " '1.2.3.4' " , or " '1.2.3.4' (forwarded for '5.6.7.8') " .
*/
static char *
http_get_origin ( const char * headers , connection_t * conn )
{
char * fwd ;
fwd = http_get_header ( headers , " Forwarded-For: " ) ;
if ( ! fwd )
fwd = http_get_header ( headers , " X-Forwarded-For: " ) ;
if ( fwd ) {
size_t len = strlen ( fwd ) + strlen ( conn - > address ) + 32 ;
char * result = tor_malloc ( len ) ;
tor_snprintf ( result , len , " '%s' (forwarded for '%s') " , conn - > address , fwd ) ;
tor_free ( fwd ) ;
return result ;
} else {
size_t len = strlen ( conn - > address ) + 3 ;
char * result = tor_malloc ( len ) ;
tor_snprintf ( result , len , " '%s' " , conn - > address ) ;
return result ;
}
}
2004-05-10 06:34:48 +02:00
/** Parse an HTTP response string <b>headers</b> of the form
2005-05-17 19:01:36 +02:00
* \ verbatim
2004-05-10 06:34:48 +02:00
* " HTTP/1. \ %d \ %d \ %s \r \n ... " .
2005-05-17 19:01:36 +02:00
* \ endverbatim
2005-03-22 19:43:24 +01:00
*
* If it ' s well - formed , assign the status code to * < b > code < / b > and
* return 0. Otherwise , return - 1.
*
* On success : If < b > date < / b > is provided , set * date to the Date
* header in the http headers , or 0 if no such header is found . If
* < b > compression < / b > is provided , set * < b > compression < / b > to the
* compression method given in the Content - Encoding header , or 0 if no
* such header is found , or - 1 if the value of the header is not
* recognized . If < b > reason < / b > is provided , strdup the reason string
* into it .
2004-03-12 13:43:13 +01:00
*/
2005-02-24 11:56:55 +01:00
int
2004-11-12 17:39:03 +01:00
parse_http_response ( const char * headers , int * code , time_t * date ,
2005-03-22 19:43:24 +01:00
int * compression , char * * reason )
2004-05-13 01:48:57 +02:00
{
2004-03-12 13:43:13 +01:00
int n1 , n2 ;
2004-08-15 22:30:15 +02:00
char datestr [ RFC1123_TIME_LEN + 1 ] ;
2004-09-08 08:52:33 +02:00
smartlist_t * parsed_headers ;
2004-10-17 00:14:52 +02:00
tor_assert ( headers ) ;
tor_assert ( code ) ;
2004-03-12 13:43:13 +01:00
2004-12-08 01:42:50 +01:00
while ( TOR_ISSPACE ( * headers ) ) headers + + ; /* tolerate leading whitespace */
2004-03-12 13:43:13 +01:00
2004-11-28 10:05:49 +01:00
if ( sscanf ( headers , " HTTP/1.%d %d " , & n1 , & n2 ) < 2 | |
2004-11-28 12:39:53 +01:00
( n1 ! = 0 & & n1 ! = 1 ) | |
( n2 < 100 | | n2 > = 600 ) ) {
2005-10-25 10:20:10 +02:00
warn ( LD_HTTP , " Failed to parse header '%s' " , headers ) ;
2004-03-12 13:43:13 +01:00
return - 1 ;
}
* code = n2 ;
2004-11-12 17:39:03 +01:00
2004-09-08 08:52:33 +02:00
parsed_headers = smartlist_create ( ) ;
smartlist_split_string ( parsed_headers , headers , " \n " ,
SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK , - 1 ) ;
2005-03-22 19:43:24 +01:00
if ( reason ) {
smartlist_t * status_line_elements = smartlist_create ( ) ;
tor_assert ( smartlist_len ( parsed_headers ) ) ;
smartlist_split_string ( status_line_elements ,
smartlist_get ( parsed_headers , 0 ) ,
" " , SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK , 3 ) ;
tor_assert ( smartlist_len ( status_line_elements ) < = 3 ) ;
if ( smartlist_len ( status_line_elements ) = = 3 ) {
* reason = smartlist_get ( status_line_elements , 2 ) ;
smartlist_set ( status_line_elements , 2 , NULL ) ; /* Prevent free */
}
SMARTLIST_FOREACH ( status_line_elements , char * , cp , tor_free ( cp ) ) ;
smartlist_free ( status_line_elements ) ;
}
2004-08-15 22:30:15 +02:00
if ( date ) {
* date = 0 ;
2004-09-08 08:52:33 +02:00
SMARTLIST_FOREACH ( parsed_headers , const char * , s ,
if ( ! strcmpstart ( s , " Date: " ) ) {
strlcpy ( datestr , s + 6 , sizeof ( datestr ) ) ;
2004-08-15 22:30:15 +02:00
/* This will do nothing on failure, so we don't need to check
the result . We shouldn ' t warn , since there are many other valid
date formats besides the one we use . */
parse_rfc1123_time ( datestr , date ) ;
break ;
2004-09-08 08:52:33 +02:00
} ) ;
}
if ( compression ) {
const char * enc = NULL ;
SMARTLIST_FOREACH ( parsed_headers , const char * , s ,
if ( ! strcmpstart ( s , " Content-Encoding: " ) ) {
2004-10-01 06:45:14 +02:00
enc = s + 18 ; break ;
2004-09-08 08:52:33 +02:00
} ) ;
2004-10-01 06:45:14 +02:00
if ( ! enc | | ! strcmp ( enc , " identity " ) ) {
2004-09-08 08:52:33 +02:00
* compression = 0 ;
} else if ( ! strcmp ( enc , " deflate " ) | | ! strcmp ( enc , " x-deflate " ) ) {
* compression = ZLIB_METHOD ;
} else if ( ! strcmp ( enc , " gzip " ) | | ! strcmp ( enc , " x-gzip " ) ) {
* compression = GZIP_METHOD ;
} else {
2005-10-25 10:20:10 +02:00
info ( LD_HTTP , " Unrecognized content encoding: '%s'. Trying to deal. " , enc ) ;
2005-01-19 23:40:33 +01:00
* compression = - 1 ;
2004-08-15 22:30:15 +02:00
}
}
2004-09-08 08:52:33 +02:00
SMARTLIST_FOREACH ( parsed_headers , char * , s , tor_free ( s ) ) ;
smartlist_free ( parsed_headers ) ;
2004-08-15 22:30:15 +02:00
2004-03-12 13:43:13 +01:00
return 0 ;
}
2005-01-19 23:40:33 +01:00
/** Return true iff <b>body</b> doesn't start with a plausible router or
* running - list or directory opening . This is a sign of possible compression .
* */
static int
2005-01-19 23:47:48 +01:00
body_is_plausible ( const char * body , size_t len , int purpose )
2005-01-19 23:40:33 +01:00
{
int i ;
2005-01-21 04:18:49 +01:00
if ( len = = 0 )
return 1 ; /* empty bodies don't need decompression */
2005-01-19 23:40:33 +01:00
if ( len < 32 )
return 0 ;
2005-01-19 23:47:48 +01:00
if ( purpose ! = DIR_PURPOSE_FETCH_RENDDESC ) {
if ( ! strcmpstart ( body , " router " ) | |
! strcmpstart ( body , " signed-directory " ) | |
! strcmpstart ( body , " network-status " ) | |
! strcmpstart ( body , " running-routers " ) )
return 1 ;
for ( i = 0 ; i < 32 ; + + i ) {
2005-01-22 01:42:58 +01:00
if ( ! TOR_ISPRINT ( body [ i ] ) & & ! TOR_ISSPACE ( body [ i ] ) )
2005-01-19 23:47:48 +01:00
return 0 ;
}
return 1 ;
} else {
2005-01-19 23:40:33 +01:00
return 1 ;
}
}
2004-07-20 04:44:26 +02:00
/** We are a client, and we've finished reading the server's
* response . Parse and it and act appropriately .
*
2005-09-12 09:36:26 +02:00
* If we ' re happy with the result ( we get it and it ' s useful ) ,
* return 0. Otherwise return - 1 , and the caller should consider
* trying the request again .
*
* The caller will take care of marking the connection for close .
2004-05-05 04:50:38 +02:00
*/
2004-07-20 04:44:26 +02:00
static int
2004-07-20 08:44:16 +02:00
connection_dir_client_reached_eof ( connection_t * conn )
2004-07-20 04:44:26 +02:00
{
2004-04-01 23:32:01 +02:00
char * body ;
2004-03-12 13:43:13 +01:00
char * headers ;
2005-03-22 19:43:24 +01:00
char * reason = NULL ;
2004-10-14 04:47:09 +02:00
size_t body_len = 0 ;
2004-03-12 13:43:13 +01:00
int status_code ;
2004-08-15 22:30:15 +02:00
time_t now , date_header = 0 ;
int delta ;
2004-09-08 08:52:33 +02:00
int compression ;
2005-01-19 23:40:33 +01:00
int plausible ;
2005-01-29 12:48:37 +01:00
int skewed = 0 ;
2005-10-14 04:26:13 +02:00
int allow_partial = conn - > purpose = = DIR_PURPOSE_FETCH_SERVERDESC ;
2002-09-26 14:09:10 +02:00
2004-11-28 10:05:49 +01:00
switch ( fetch_from_buf_http ( conn - > inbuf ,
2004-11-28 12:39:53 +01:00
& headers , MAX_HEADERS_SIZE ,
2005-10-14 04:26:13 +02:00
& body , & body_len , MAX_DIR_SIZE ,
allow_partial ) ) {
2004-07-20 04:44:26 +02:00
case - 1 : /* overflow */
2005-11-01 07:13:12 +01:00
warn ( LD_PROTOCOL , " 'fetch' response too large (server '%s:%d'). Closing. " , conn - > address , conn - > port ) ;
2004-07-20 04:44:26 +02:00
return - 1 ;
case 0 :
2005-10-25 10:20:10 +02:00
info ( LD_HTTP , " 'fetch' response not all here, but we're at eof. Closing. " ) ;
2004-07-20 04:44:26 +02:00
return - 1 ;
/* case 1, fall through */
}
2002-09-26 14:09:10 +02:00
2004-11-28 10:05:49 +01:00
if ( parse_http_response ( headers , & status_code , & date_header ,
2005-03-22 19:43:24 +01:00
& compression , & reason ) < 0 ) {
2005-10-25 10:20:10 +02:00
warn ( LD_HTTP , " Unparseable headers (server '%s:%d'). Closing. " , conn - > address , conn - > port ) ;
2004-09-29 08:52:36 +02:00
tor_free ( body ) ; tor_free ( headers ) ;
2004-07-20 04:44:26 +02:00
return - 1 ;
}
2005-03-22 19:43:24 +01:00
if ( ! reason ) reason = tor_strdup ( " [no reason given] " ) ;
2005-10-25 10:20:10 +02:00
debug ( LD_DIR ,
" Received response from directory server '%s:%d': %d \" %s \" " ,
conn - > address , conn - > port , status_code , reason ) ;
2005-03-22 19:43:24 +01:00
2004-08-15 22:30:15 +02:00
if ( date_header > 0 ) {
now = time ( NULL ) ;
delta = now - date_header ;
if ( abs ( delta ) > ALLOW_DIRECTORY_TIME_SKEW ) {
2005-04-07 23:09:19 +02:00
log_fn ( router_digest_is_trusted_dir ( conn - > identity_digest ) ? LOG_WARN : LOG_INFO ,
2005-10-25 10:20:10 +02:00
LD_HTTP ,
2005-09-08 21:21:48 +02:00
" Received directory with skewed time (server '%s:%d'): we are %d minutes %s, or the directory is %d minutes %s. " ,
conn - > address , conn - > port ,
2004-08-15 22:30:15 +02:00
abs ( delta ) / 60 , delta > 0 ? " ahead " : " behind " ,
abs ( delta ) / 60 , delta > 0 ? " behind " : " ahead " ) ;
2005-01-29 12:48:37 +01:00
skewed = 1 ; /* don't check the recommended-versions line */
2004-08-15 22:30:15 +02:00
} else {
2005-10-25 10:20:10 +02:00
debug ( LD_HTTP , " Time on received directory is within tolerance; we are %d seconds skewed. (That's okay.) " , delta ) ;
2004-08-15 22:30:15 +02:00
}
}
2004-07-20 04:44:26 +02:00
2005-01-19 23:47:48 +01:00
plausible = body_is_plausible ( body , body_len , conn - > purpose ) ;
2005-01-19 23:40:33 +01:00
if ( compression | | ! plausible ) {
char * new_body = NULL ;
size_t new_len = 0 ;
int guessed = detect_compression_method ( body , body_len ) ;
if ( compression < = 0 | | guessed ! = compression ) {
/* Tell the user if we don't believe what we're told about compression.*/
const char * description1 , * description2 ;
if ( compression = = ZLIB_METHOD )
description1 = " as deflated " ;
2005-01-19 23:47:48 +01:00
else if ( compression = = GZIP_METHOD )
2005-01-19 23:40:33 +01:00
description1 = " as gzipped " ;
else if ( compression = = 0 )
description1 = " as uncompressed " ;
else
description1 = " with an unknown Content-Encoding " ;
if ( guessed = = ZLIB_METHOD )
description2 = " deflated " ;
else if ( guessed = = GZIP_METHOD )
description2 = " gzipped " ;
else if ( ! plausible )
description2 = " confusing binary junk " ;
else
description2 = " uncompressed " ;
2005-10-25 10:20:10 +02:00
info ( LD_HTTP , " HTTP body from server '%s:%d' was labeled %s, "
2005-01-19 23:40:33 +01:00
" but it seems to be %s.%s " ,
2005-09-08 21:21:48 +02:00
conn - > address , conn - > port , description1 , description2 ,
2005-01-19 23:40:33 +01:00
( compression > 0 & & guessed > 0 ) ? " Trying both. " : " " ) ;
}
/* Try declared compression first if we can. */
if ( compression > 0 )
2005-10-14 04:26:13 +02:00
tor_gzip_uncompress ( & new_body , & new_len , body , body_len , compression ,
allow_partial ) ;
2005-01-19 23:40:33 +01:00
/* Okay, if that didn't work, and we think that it was compressed
* differently , try that . */
if ( ! new_body & & guessed > 0 & & compression ! = guessed )
2005-10-14 04:26:13 +02:00
tor_gzip_uncompress ( & new_body , & new_len , body , body_len , guessed ,
allow_partial ) ;
2005-01-19 23:40:33 +01:00
/* If we're pretty sure that we have a compressed directory, and
* we didn ' t manage to uncompress it , then warn and bail . */
if ( ! plausible & & ! new_body ) {
2005-10-25 10:20:10 +02:00
warn ( LD_HTTP , " Unable to decompress HTTP body (server '%s:%d'). " ,
conn - > address , conn - > port ) ;
2005-03-22 19:43:24 +01:00
tor_free ( body ) ; tor_free ( headers ) ; tor_free ( reason ) ;
2004-09-08 08:52:33 +02:00
return - 1 ;
}
2005-01-19 23:40:33 +01:00
if ( new_body ) {
tor_free ( body ) ;
body = new_body ;
body_len = new_len ;
}
2004-09-08 08:52:33 +02:00
}
2004-11-28 10:05:49 +01:00
if ( conn - > purpose = = DIR_PURPOSE_FETCH_DIR ) {
2004-07-20 04:44:26 +02:00
/* fetch/process the directory to learn about new routers. */
2005-10-25 10:20:10 +02:00
info ( LD_DIR , " Received directory (size %d) from server '%s:%d' " ,
2005-09-08 21:21:48 +02:00
( int ) body_len , conn - > address , conn - > port ) ;
2004-11-28 10:05:49 +01:00
if ( status_code = = 503 | | body_len = = 0 ) {
2005-10-25 10:20:10 +02:00
info ( LD_DIR , " Empty directory; status %d ( \" %s \" ) Ignoring. " ,
2005-03-22 19:43:24 +01:00
status_code , reason ) ;
tor_free ( body ) ; tor_free ( headers ) ; tor_free ( reason ) ;
2005-09-12 09:36:26 +02:00
return - 1 ;
2004-07-20 04:44:26 +02:00
}
2004-11-28 10:05:49 +01:00
if ( status_code ! = 200 ) {
2005-10-25 10:20:10 +02:00
warn ( LD_DIR , " Received http status code %d ( \" %s \" ) from server '%s:%d'. I'll try again soon. " ,
2005-09-08 21:21:48 +02:00
status_code , reason , conn - > address , conn - > port ) ;
2005-03-22 19:43:24 +01:00
tor_free ( body ) ; tor_free ( headers ) ; tor_free ( reason ) ;
2004-03-12 13:43:13 +01:00
return - 1 ;
}
2005-09-15 07:19:38 +02:00
if ( router_parse_directory ( body ) < 0 ) {
2005-10-25 10:20:10 +02:00
notice ( LD_DIR , " I failed to parse the directory I fetched from '%s:%d'. Ignoring. " , conn - > address , conn - > port ) ;
2005-09-15 07:19:38 +02:00
}
2004-07-20 04:44:26 +02:00
}
2004-03-12 13:43:13 +01:00
2004-11-28 10:05:49 +01:00
if ( conn - > purpose = = DIR_PURPOSE_FETCH_RUNNING_LIST ) {
2004-07-20 04:44:26 +02:00
/* just update our list of running routers, if this list is new info */
2005-10-25 10:20:10 +02:00
info ( LD_DIR , " Received running-routers list (size %d) " , ( int ) body_len ) ;
2004-11-28 10:05:49 +01:00
if ( status_code ! = 200 ) {
2005-10-25 10:20:10 +02:00
warn ( LD_DIR , " Received http status code %d ( \" %s \" ) from server '%s:%d'. I'll try again soon. " ,
2005-09-08 21:21:48 +02:00
status_code , reason , conn - > address , conn - > port ) ;
2005-03-22 19:43:24 +01:00
tor_free ( body ) ; tor_free ( headers ) ; tor_free ( reason ) ;
2004-03-12 13:43:13 +01:00
return - 1 ;
}
2005-09-14 23:09:25 +02:00
if ( router_parse_runningrouters ( body ) < 0 ) {
2005-10-25 10:20:10 +02:00
warn ( LD_DIR , " Bad running-routers from server '%s:%d'. I'll try again soon. " ,
2005-09-14 23:09:25 +02:00
conn - > address , conn - > port ) ;
tor_free ( body ) ; tor_free ( headers ) ; tor_free ( reason ) ;
return - 1 ;
}
2004-07-20 04:44:26 +02:00
}
2004-03-12 13:43:13 +01:00
2005-09-08 08:22:44 +02:00
if ( conn - > purpose = = DIR_PURPOSE_FETCH_NETWORKSTATUS ) {
2005-09-08 22:36:40 +02:00
smartlist_t * which = NULL ;
2005-09-08 23:28:45 +02:00
char * cp ;
2005-10-25 10:20:10 +02:00
info ( LD_DIR , " Received networkstatus objects (size %d) from server '%s:%d' " , ( int ) body_len , conn - > address , conn - > port ) ;
2005-09-08 08:22:44 +02:00
if ( status_code ! = 200 ) {
2005-10-25 10:20:10 +02:00
warn ( LD_DIR , " Received http status code %d ( \" %s \" ) from server '%s:%d' while fetching \" /tor/status/%s \" . I'll try again soon. " ,
2005-09-09 21:37:12 +02:00
status_code , reason , conn - > address , conn - > port ,
conn - > requested_resource ) ;
2005-09-08 08:22:44 +02:00
tor_free ( body ) ; tor_free ( headers ) ; tor_free ( reason ) ;
2005-09-12 08:56:42 +02:00
connection_dir_download_networkstatus_failed ( conn ) ;
2005-09-08 08:22:44 +02:00
return - 1 ;
}
2005-09-08 22:36:40 +02:00
if ( conn - > requested_resource & &
! strcmpstart ( conn - > requested_resource , " fp/ " ) ) {
which = smartlist_create ( ) ;
2005-09-16 06:42:45 +02:00
dir_split_resource_into_fingerprints ( conn - > requested_resource + 3 ,
2005-10-14 06:56:20 +02:00
which , NULL , 0 ) ;
2005-09-08 22:36:40 +02:00
}
2005-09-08 23:28:45 +02:00
cp = body ;
while ( * cp ) {
char * next = strstr ( cp , " \n network-status-version " ) ;
2005-09-08 08:22:44 +02:00
if ( next )
2005-09-08 23:28:45 +02:00
next [ 1 ] = ' \0 ' ;
2005-09-30 01:26:42 +02:00
/* learn from it, and then remove it from 'which' */
2005-09-08 23:28:45 +02:00
if ( router_set_networkstatus ( cp , time ( NULL ) , NS_FROM_DIR , which ) < 0 )
2005-09-08 08:22:44 +02:00
break ;
2005-09-08 23:28:45 +02:00
if ( next ) {
next [ 1 ] = ' n ' ;
cp = next + 1 ;
}
2005-09-08 08:22:44 +02:00
else
break ;
}
2005-09-30 01:26:42 +02:00
routers_update_all_from_networkstatus ( ) ; /*launches router downloads*/
2005-09-30 01:06:48 +02:00
directory_info_has_arrived ( time ( NULL ) , 0 ) ;
2005-09-08 22:36:40 +02:00
if ( which ) {
2005-09-12 08:56:42 +02:00
if ( smartlist_len ( which ) ) {
dir_networkstatus_download_failed ( which ) ;
}
2005-09-08 22:36:40 +02:00
SMARTLIST_FOREACH ( which , char * , cp , tor_free ( cp ) ) ;
smartlist_free ( which ) ;
}
2005-09-08 08:22:44 +02:00
}
if ( conn - > purpose = = DIR_PURPOSE_FETCH_SERVERDESC ) {
2005-09-15 07:19:38 +02:00
smartlist_t * which = NULL ;
2005-09-15 23:11:48 +02:00
int n_asked_for = 0 ;
2005-10-25 10:20:10 +02:00
info ( LD_DIR , " Received server info (size %d) from server '%s:%d' " ,
2005-09-15 07:19:38 +02:00
( int ) body_len , conn - > address , conn - > port ) ;
if ( conn - > requested_resource & &
! strcmpstart ( conn - > requested_resource , " fp/ " ) ) {
which = smartlist_create ( ) ;
2005-09-16 06:42:45 +02:00
dir_split_resource_into_fingerprints ( conn - > requested_resource + 3 ,
2005-10-14 06:56:20 +02:00
which , NULL , 0 ) ;
2005-09-15 23:11:48 +02:00
n_asked_for = smartlist_len ( which ) ;
2005-09-18 06:15:39 +02:00
}
if ( status_code ! = 200 ) {
2005-10-05 03:27:08 +02:00
int no_warn = status_code = = 404 | |
( status_code = = 400 & & ! strcmp ( reason , " Servers unavailable. " ) ) ;
/* 404 means that it didn't have them; no big deal.
* Older ( pre - 0.1 .1 .8 ) servers said 400 Servers unavailable instead . */
2005-10-25 10:20:10 +02:00
log_fn ( no_warn ? LOG_INFO : LOG_WARN , LD_DIR ,
2005-09-23 23:25:29 +02:00
" Received http status code %d ( \" %s \" ) from server '%s:%d' while fetching \" /tor/server/%s \" . I'll try again soon. " ,
2005-09-18 06:15:39 +02:00
status_code , reason , conn - > address , conn - > port ,
conn - > requested_resource ) ;
if ( ! which ) {
connection_dir_download_routerdesc_failed ( conn ) ;
} else {
dir_routerdesc_download_failed ( which ) ;
SMARTLIST_FOREACH ( which , char * , cp , tor_free ( cp ) ) ;
smartlist_free ( which ) ;
}
2005-09-30 01:06:48 +02:00
tor_free ( body ) ; tor_free ( headers ) ; tor_free ( reason ) ;
return - 1 ;
2005-09-18 06:15:39 +02:00
}
2005-09-30 22:04:55 +02:00
/* Learn the routers, assuming we requested by fingerprint or "all".
* Right now , we only use " authority " to fetch ourself , so we don ' t want
* to risk replacing ourself with a router running at the addr : port we
* think we have .
*/
if ( which | | ( conn - > requested_resource & &
! strcmpstart ( conn - > requested_resource , " all " ) ) ) {
/* as we learn from them, we remove them from 'which' */
router_load_routers_from_string ( body , 0 , which ) ;
directory_info_has_arrived ( time ( NULL ) , 0 ) ;
}
2005-09-30 04:08:57 +02:00
if ( which ) { /* mark remaining ones as failed */
2005-10-25 10:20:10 +02:00
info ( LD_DIR , " Received %d/%d routers requested from %s:%d " ,
2005-10-05 03:27:08 +02:00
n_asked_for - smartlist_len ( which ) , n_asked_for ,
conn - > address , ( int ) conn - > port ) ;
2005-09-15 07:19:38 +02:00
if ( smartlist_len ( which ) ) {
dir_routerdesc_download_failed ( which ) ;
}
SMARTLIST_FOREACH ( which , char * , cp , tor_free ( cp ) ) ;
smartlist_free ( which ) ;
}
2005-09-30 01:59:36 +02:00
if ( conn - > requested_resource & &
! strcmpstart ( conn - > requested_resource , " authority " ) ) {
/* this might have been a dirport reachability test. see if it is. */
routerinfo_t * me = router_get_my_routerinfo ( ) ;
if ( me & &
2005-11-05 21:15:27 +01:00
router_digest_is_me ( conn - > identity_digest ) & &
2005-09-30 01:59:36 +02:00
me - > addr = = conn - > addr & &
me - > dir_port = = conn - > port )
router_dirport_found_reachable ( ) ;
}
2005-09-08 08:22:44 +02:00
}
2004-11-28 10:05:49 +01:00
if ( conn - > purpose = = DIR_PURPOSE_UPLOAD_DIR ) {
switch ( status_code ) {
2004-07-20 04:44:26 +02:00
case 200 :
2005-10-25 10:20:10 +02:00
info ( LD_GENERAL , " eof (status 200) after uploading server descriptor: finished. " ) ;
2004-07-20 04:44:26 +02:00
break ;
case 400 :
2005-10-25 10:20:10 +02:00
warn ( LD_GENERAL , " http status 400 ( \" %s \" ) response from dirserver '%s:%d'. Please correct. " , reason , conn - > address , conn - > port ) ;
2004-07-20 04:44:26 +02:00
break ;
case 403 :
2005-10-25 10:20:10 +02:00
warn ( LD_GENERAL , " http status 403 ( \" %s \" ) response from dirserver '%s:%d'. Is your clock skewed? Have you mailed us your key fingerprint? Are you using the right key? Are you using a private IP address? See http://tor.eff.org/doc/tor-doc-server.html " , reason , conn - > address , conn - > port ) ;
2004-07-20 04:44:26 +02:00
break ;
default :
2005-10-25 10:20:10 +02:00
warn ( LD_GENERAL , " http status %d ( \" %s \" ) reason unexpected (server '%s:%d'). " , status_code , reason , conn - > address , conn - > port ) ;
2004-07-20 04:44:26 +02:00
break ;
2004-06-16 23:08:29 +02:00
}
2005-09-12 09:36:26 +02:00
/* return 0 in all cases, since we don't want to mark any
* dirservers down just because they don ' t like us . */
2004-07-20 04:44:26 +02:00
}
2004-06-16 23:08:29 +02:00
2004-11-28 10:05:49 +01:00
if ( conn - > purpose = = DIR_PURPOSE_FETCH_RENDDESC ) {
2005-10-25 10:20:10 +02:00
info ( LD_REND , " Received rendezvous descriptor (size %d, status %d ( \" %s \" )) " ,
2005-03-22 19:43:24 +01:00
( int ) body_len , status_code , reason ) ;
2004-11-28 10:05:49 +01:00
switch ( status_code ) {
2004-07-20 04:44:26 +02:00
case 200 :
2004-11-28 10:05:49 +01:00
if ( rend_cache_store ( body , body_len ) < 0 ) {
2005-10-25 10:20:10 +02:00
warn ( LD_REND , " Failed to store rendezvous descriptor. " ) ;
2004-07-20 04:44:26 +02:00
/* alice's ap_stream will notice when connection_mark_for_close
* cleans it up */
} else {
/* success. notify pending connections about this. */
conn - > purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC ;
2005-01-20 00:15:59 +01:00
rend_client_desc_here ( conn - > rend_query ) ;
2004-07-20 04:44:26 +02:00
}
break ;
case 404 :
/* not there. pending connections will be notified when
* connection_mark_for_close cleans it up . */
break ;
case 400 :
2005-10-25 10:20:10 +02:00
warn ( LD_REND , " http status 400 ( \" %s \" ). Dirserver didn't like our rendezvous query? " , reason ) ;
2005-03-22 19:43:24 +01:00
break ;
default :
2005-10-25 10:20:10 +02:00
warn ( LD_REND , " http status %d ( \" %s \" ) response unexpected (server '%s:%d'). " , status_code , reason , conn - > address , conn - > port ) ;
2004-07-20 04:44:26 +02:00
break ;
2002-09-28 02:52:59 +02:00
}
2004-07-20 04:44:26 +02:00
}
2004-03-31 00:57:49 +02:00
2004-11-28 10:05:49 +01:00
if ( conn - > purpose = = DIR_PURPOSE_UPLOAD_RENDDESC ) {
switch ( status_code ) {
2004-07-20 04:44:26 +02:00
case 200 :
2005-10-25 10:20:10 +02:00
info ( LD_REND , " Uploading rendezvous descriptor: finished with status 200 ( \" %s \" ) " , reason ) ;
2004-07-20 04:44:26 +02:00
break ;
case 400 :
2005-10-25 10:20:10 +02:00
warn ( LD_REND , " http status 400 ( \" %s \" ) response from dirserver '%s:%d'. Malformed rendezvous descriptor? " , reason , conn - > address , conn - > port ) ;
2004-07-20 04:44:26 +02:00
break ;
default :
2005-10-25 10:20:10 +02:00
warn ( LD_REND , " http status %d ( \" %s \" ) response unexpected (server '%s:%d'). " , status_code , reason , conn - > address , conn - > port ) ;
2004-07-20 04:44:26 +02:00
break ;
2004-03-31 00:57:49 +02:00
}
2004-07-20 04:44:26 +02:00
}
2005-03-22 19:43:24 +01:00
tor_free ( body ) ; tor_free ( headers ) ; tor_free ( reason ) ;
2004-07-20 04:44:26 +02:00
return 0 ;
}
2005-06-11 20:52:12 +02:00
/** Called when a directory connection reaches EOF */
int
connection_dir_reached_eof ( connection_t * conn )
{
2004-11-21 11:14:57 +01:00
int retval ;
2004-11-28 10:05:49 +01:00
if ( conn - > state ! = DIR_CONN_STATE_CLIENT_READING ) {
2005-10-25 10:20:10 +02:00
info ( LD_HTTP , " conn reached eof, not reading. Closing. " ) ;
2005-10-05 00:34:09 +02:00
/* This check is temporary; it's to let us know whether we should consider
* parsing partial serverdesc responses . */
2005-10-05 02:22:56 +02:00
if ( conn - > purpose = = DIR_PURPOSE_FETCH_SERVERDESC & &
buf_datalen ( conn - > inbuf ) > = ( 24 * 1024 ) ) {
2005-10-25 10:20:10 +02:00
notice ( LD_DIR , " Directory connection closed early after downloading %d bytes of descriptors. If this happens often, please file a bug report. " ,
2005-10-05 06:52:55 +02:00
( int ) buf_datalen ( conn - > inbuf ) ) ;
2005-10-05 00:34:09 +02:00
}
2004-11-21 11:14:57 +01:00
connection_close_immediate ( conn ) ; /* it was an error; give up on flushing */
connection_mark_for_close ( conn ) ;
return - 1 ;
}
retval = connection_dir_client_reached_eof ( conn ) ;
2005-09-12 09:36:26 +02:00
if ( retval = = 0 ) /* success */
conn - > state = DIR_CONN_STATE_CLIENT_FINISHED ;
2004-11-21 11:14:57 +01:00
connection_mark_for_close ( conn ) ;
return retval ;
}
2004-07-20 04:44:26 +02:00
/** Read handler for directory connections. (That's connections <em>to</em>
* directory servers and connections < em > at < / em > directory servers . )
*/
2005-09-30 03:09:52 +02:00
int
connection_dir_process_inbuf ( connection_t * conn )
2005-06-11 20:52:12 +02:00
{
2004-10-17 00:14:52 +02:00
tor_assert ( conn ) ;
tor_assert ( conn - > type = = CONN_TYPE_DIR ) ;
2004-07-20 04:44:26 +02:00
/* Directory clients write, then read data until they receive EOF;
* directory servers read data until they get an HTTP command , then
* write their response ( when it ' s finished flushing , they mark for
* close ) .
*/
2002-09-26 14:09:10 +02:00
2004-05-05 04:50:38 +02:00
/* If we're on the dirserver side, look for a command. */
2004-11-28 10:05:49 +01:00
if ( conn - > state = = DIR_CONN_STATE_SERVER_COMMAND_WAIT ) {
2004-03-31 00:57:49 +02:00
if ( directory_handle_command ( conn ) < 0 ) {
2004-05-12 23:12:33 +02:00
connection_mark_for_close ( conn ) ;
2004-03-31 00:57:49 +02:00
return - 1 ;
}
2004-03-31 07:01:30 +02:00
return 0 ;
2004-03-31 00:57:49 +02:00
}
2003-09-17 22:09:06 +02:00
/* XXX for READ states, might want to make sure inbuf isn't too big */
2002-09-26 14:09:10 +02:00
2005-10-25 10:20:10 +02:00
debug ( LD_HTTP , " Got data, not eof. Leaving on inbuf. " ) ;
2002-09-26 14:09:10 +02:00
return 0 ;
}
2005-01-20 21:07:36 +01:00
/** Create an http response for the client <b>conn</b> out of
* < b > status < / b > and < b > reason_phrase < / b > . Write it to < b > conn < / b > .
*/
2005-01-20 20:46:02 +01:00
static void
write_http_status_line ( connection_t * conn , int status ,
const char * reason_phrase )
{
2005-01-20 21:07:36 +01:00
char buf [ 256 ] ;
if ( tor_snprintf ( buf , sizeof ( buf ) , " HTTP/1.0 %d %s \r \n \r \n " ,
status , reason_phrase ) < 0 ) {
2005-10-25 10:20:10 +02:00
warn ( LD_BUG , " Bug: status line too long. " ) ;
2005-01-20 20:46:02 +01:00
return ;
2005-01-20 21:07:36 +01:00
}
2005-01-20 20:46:02 +01:00
connection_write_to_buf ( buf , strlen ( buf ) , conn ) ;
}
2004-03-12 13:43:13 +01:00
2005-05-23 07:20:52 +02:00
/** Helper function: return 1 if there are any dir conns of purpose
* < b > purpose < / b > that are going elsewhere than our own ORPort / Dirport .
* Else return 0.
*/
static int
2005-06-11 20:52:12 +02:00
already_fetching_directory ( int purpose )
{
2005-05-23 07:20:52 +02:00
int i , n ;
connection_t * conn ;
connection_t * * carray ;
get_connection_array ( & carray , & n ) ;
for ( i = 0 ; i < n ; i + + ) {
conn = carray [ i ] ;
if ( conn - > type = = CONN_TYPE_DIR & &
conn - > purpose = = purpose & &
! conn - > marked_for_close & &
! router_digest_is_me ( conn - > identity_digest ) )
return 1 ;
}
return 0 ;
}
2004-05-09 18:47:25 +02:00
/** Helper function: called when a dirserver gets a complete HTTP GET
2004-05-06 13:08:04 +02:00
* request . Look for a request for a directory or for a rendezvous
* service descriptor . On finding one , write a response into
2004-09-27 05:39:30 +02:00
* conn - \ > outbuf . If the request is unrecognized , send a 400.
2004-05-06 13:08:04 +02:00
* Always return 0. */
2004-05-13 01:48:57 +02:00
static int
directory_handle_command_get ( connection_t * conn , char * headers ,
2004-10-14 04:47:09 +02:00
char * body , size_t body_len )
2004-05-13 01:48:57 +02:00
{
2003-09-28 10:06:18 +02:00
size_t dlen ;
2003-09-27 23:30:10 +02:00
const char * cp ;
2005-08-24 00:27:17 +02:00
char * url = NULL ;
2004-03-31 07:01:30 +02:00
char tmp [ 8192 ] ;
2004-08-04 03:15:57 +02:00
char date [ RFC1123_TIME_LEN + 1 ] ;
2002-09-26 14:09:10 +02:00
2005-10-25 10:20:10 +02:00
debug ( LD_DIRSERV , " Received GET command. " ) ;
2003-12-17 10:42:28 +01:00
2004-03-31 00:57:49 +02:00
conn - > state = DIR_CONN_STATE_SERVER_WRITING ;
2003-12-17 10:42:28 +01:00
2004-03-31 00:57:49 +02:00
if ( parse_http_url ( headers , & url ) < 0 ) {
2005-01-20 20:46:02 +01:00
write_http_status_line ( conn , 400 , " Bad request " ) ;
2004-03-12 13:43:13 +01:00
return 0 ;
2003-12-17 10:42:28 +01:00
}
2005-10-25 10:20:10 +02:00
debug ( LD_DIRSERV , " rewritten url as '%s'. " , url ) ;
2003-12-17 10:42:28 +01:00
2004-11-28 10:05:49 +01:00
if ( ! strcmp ( url , " /tor/ " ) | | ! strcmp ( url , " /tor/dir.z " ) ) { /* directory fetch */
2004-09-27 05:39:30 +02:00
int deflated = ! strcmp ( url , " /tor/dir.z " ) ;
2004-09-21 20:09:38 +02:00
dlen = dirserv_get_directory ( & cp , deflated ) ;
2004-03-31 00:57:49 +02:00
2004-09-27 05:39:30 +02:00
tor_free ( url ) ;
2004-11-28 10:05:49 +01:00
if ( dlen = = 0 ) {
2005-10-25 10:20:10 +02:00
notice ( LD_DIRSERV , " Client asked for the mirrored directory, but we don't have a good one yet. Sending 503 Dir not available. " ) ;
2005-01-20 20:46:02 +01:00
write_http_status_line ( conn , 503 , " Directory unavailable " ) ;
2005-02-10 07:31:34 +01:00
/* try to get a new one now */
2005-05-23 07:20:52 +02:00
if ( ! already_fetching_directory ( DIR_PURPOSE_FETCH_DIR ) )
2005-02-10 07:31:34 +01:00
directory_get_from_dirserver ( DIR_PURPOSE_FETCH_DIR , NULL , 1 ) ;
2004-03-31 00:57:49 +02:00
return 0 ;
}
2005-10-25 10:20:10 +02:00
debug ( LD_DIRSERV , " Dumping %sdirectory to client. " ,
deflated ? " deflated " : " " ) ;
2004-08-15 22:30:15 +02:00
format_rfc1123_time ( date , time ( NULL ) ) ;
2005-09-22 02:17:41 +02:00
tor_snprintf ( tmp , sizeof ( tmp ) , " HTTP/1.0 200 OK \r \n Date: %s \r \n Content-Length: %d \r \n Content-Type: %s \r \n Content-Encoding: %s \r \n \r \n " ,
2004-08-15 22:30:15 +02:00
date ,
2004-09-08 08:52:33 +02:00
( int ) dlen ,
2005-09-22 02:17:41 +02:00
deflated ? " application/octet-stream " : " text/plain " ,
2004-09-21 20:09:38 +02:00
deflated ? " deflate " : " identity " ) ;
2004-03-31 07:01:30 +02:00
connection_write_to_buf ( tmp , strlen ( tmp ) , conn ) ;
2004-09-29 07:48:25 +02:00
connection_write_to_buf ( cp , dlen , conn ) ;
2004-03-31 00:57:49 +02:00
return 0 ;
}
2004-11-28 10:05:49 +01:00
if ( ! strcmp ( url , " /tor/running-routers " ) | |
2004-11-28 12:39:53 +01:00
! strcmp ( url , " /tor/running-routers.z " ) ) { /* running-routers fetch */
2005-07-13 00:56:22 +02:00
int deflated = ! strcmp ( url , " /tor/running-routers.z " ) ;
2004-09-27 05:39:30 +02:00
tor_free ( url ) ;
2004-11-15 05:04:20 +01:00
dlen = dirserv_get_runningrouters ( & cp , deflated ) ;
2004-11-28 10:05:49 +01:00
if ( ! dlen ) { /* we failed to create/cache cp */
2005-01-20 20:46:02 +01:00
write_http_status_line ( conn , 503 , " Directory unavailable " ) ;
2005-02-10 07:31:34 +01:00
/* try to get a new one now */
2005-05-23 07:20:52 +02:00
if ( ! already_fetching_directory ( DIR_PURPOSE_FETCH_RUNNING_LIST ) )
2005-02-10 07:31:34 +01:00
directory_get_from_dirserver ( DIR_PURPOSE_FETCH_RUNNING_LIST , NULL , 1 ) ;
2004-06-30 23:48:02 +02:00
return 0 ;
}
2004-06-16 23:08:29 +02:00
2004-08-07 04:46:16 +02:00
format_rfc1123_time ( date , time ( NULL ) ) ;
2005-09-22 02:17:41 +02:00
tor_snprintf ( tmp , sizeof ( tmp ) , " HTTP/1.0 200 OK \r \n Date: %s \r \n Content-Length: %d \r \n Content-Type: %s \r \n Content-Encoding: %s \r \n \r \n " ,
2004-11-15 05:04:20 +01:00
date ,
( int ) dlen ,
2005-09-22 02:17:41 +02:00
deflated ? " application/octet-stream " : " text/plain " ,
2004-11-15 05:04:20 +01:00
deflated ? " deflate " : " identity " ) ;
2004-06-16 23:08:29 +02:00
connection_write_to_buf ( tmp , strlen ( tmp ) , conn ) ;
connection_write_to_buf ( cp , strlen ( cp ) , conn ) ;
return 0 ;
}
2005-08-25 22:33:17 +02:00
if ( ! strcmpstart ( url , " /tor/status/ " ) ) {
/* v2 network status fetch. */
size_t url_len = strlen ( url ) ;
int deflated = ! strcmp ( url + url_len - 2 , " .z " ) ;
2005-09-07 18:42:53 +02:00
smartlist_t * dir_objs = smartlist_create ( ) ;
2005-08-25 22:33:17 +02:00
const char * key = url + strlen ( " /tor/status/ " ) ;
if ( deflated )
url [ url_len - 2 ] = ' \0 ' ;
2005-09-07 18:42:53 +02:00
if ( dirserv_get_networkstatus_v2 ( dir_objs , key ) ) {
smartlist_free ( dir_objs ) ;
return 0 ;
}
2005-08-25 22:33:17 +02:00
tor_free ( url ) ;
2005-09-07 18:42:53 +02:00
if ( ! smartlist_len ( dir_objs ) ) { /* we failed to create/cache cp */
2005-08-25 22:33:17 +02:00
write_http_status_line ( conn , 503 , " Network status object unavailable " ) ;
2005-09-07 18:42:53 +02:00
smartlist_free ( dir_objs ) ;
2005-08-25 22:33:17 +02:00
return 0 ;
}
2005-09-07 18:42:53 +02:00
dlen = 0 ;
SMARTLIST_FOREACH ( dir_objs , cached_dir_t * , d ,
dlen + = deflated ? d - > dir_z_len : d - > dir_len ) ;
2005-08-25 22:33:17 +02:00
format_rfc1123_time ( date , time ( NULL ) ) ;
2005-09-22 02:17:41 +02:00
tor_snprintf ( tmp , sizeof ( tmp ) , " HTTP/1.0 200 OK \r \n Date: %s \r \n Content-Length: %d \r \n Content-Type: %s \r \n Content-Encoding: %s \r \n \r \n " ,
2005-08-25 22:33:17 +02:00
date ,
( int ) dlen ,
2005-09-22 02:17:41 +02:00
deflated ? " application/octet-stream " : " text/plain " ,
2005-08-25 22:33:17 +02:00
deflated ? " deflate " : " identity " ) ;
connection_write_to_buf ( tmp , strlen ( tmp ) , conn ) ;
2005-09-07 18:42:53 +02:00
SMARTLIST_FOREACH ( dir_objs , cached_dir_t * , d ,
{
if ( deflated )
connection_write_to_buf ( d - > dir_z , d - > dir_z_len , conn ) ;
else
connection_write_to_buf ( d - > dir , d - > dir_len , conn ) ;
} ) ;
smartlist_free ( dir_objs ) ;
2005-08-25 22:33:17 +02:00
return 0 ;
}
if ( ! strcmpstart ( url , " /tor/server/ " ) ) {
size_t url_len = strlen ( url ) ;
int deflated = ! strcmp ( url + url_len - 2 , " .z " ) ;
2005-10-18 19:09:57 +02:00
int res ;
const char * msg ;
2005-08-25 22:33:17 +02:00
smartlist_t * descs = smartlist_create ( ) ;
if ( deflated )
url [ url_len - 2 ] = ' \0 ' ;
2005-10-18 19:09:57 +02:00
res = dirserv_get_routerdescs ( descs , url , & msg ) ;
2005-08-25 22:33:17 +02:00
tor_free ( url ) ;
2005-10-18 19:09:57 +02:00
if ( res < 0 )
write_http_status_line ( conn , 404 , msg ) ;
else {
2005-08-25 22:33:17 +02:00
size_t len = 0 ;
format_rfc1123_time ( date , time ( NULL ) ) ;
2005-11-05 21:15:27 +01:00
SMARTLIST_FOREACH ( descs , signed_descriptor_t * , ri ,
2005-08-25 22:33:17 +02:00
len + = ri - > signed_descriptor_len ) ;
2005-09-07 18:42:53 +02:00
if ( deflated ) {
size_t compressed_len ;
char * compressed ;
char * inp = tor_malloc ( len + smartlist_len ( descs ) + 1 ) ;
char * cp = inp ;
2005-11-05 21:15:27 +01:00
SMARTLIST_FOREACH ( descs , signed_descriptor_t * , ri ,
2005-09-07 18:42:53 +02:00
{
memcpy ( cp , ri - > signed_descriptor ,
ri - > signed_descriptor_len ) ;
cp + = ri - > signed_descriptor_len ;
* cp + + = ' \n ' ;
} ) ;
* cp = ' \0 ' ;
2005-09-16 18:41:45 +02:00
/* XXXX This could be way more efficiently handled; let's see if it
* shows up under oprofile . */
2005-09-07 18:42:53 +02:00
if ( tor_gzip_compress ( & compressed , & compressed_len ,
2005-09-07 19:15:46 +02:00
inp , cp - inp , ZLIB_METHOD ) < 0 ) {
2005-09-09 00:00:29 +02:00
tor_free ( inp ) ;
2005-09-07 18:42:53 +02:00
smartlist_free ( descs ) ;
return - 1 ;
}
2005-09-09 00:00:29 +02:00
tor_free ( inp ) ;
2005-10-17 04:32:33 +02:00
tor_snprintf ( tmp , sizeof ( tmp ) , " HTTP/1.0 200 OK \r \n Date: %s \r \n Content-Length: %d \r \n Content-Type: application/octet-stream \r \n Content-Encoding: deflate \r \n \r \n " ,
2005-09-07 18:42:53 +02:00
date ,
( int ) compressed_len ) ;
connection_write_to_buf ( tmp , strlen ( tmp ) , conn ) ;
connection_write_to_buf ( compressed , compressed_len , conn ) ;
2005-09-09 00:00:29 +02:00
tor_free ( compressed ) ;
2005-09-07 18:42:53 +02:00
} else {
2005-09-22 02:17:41 +02:00
tor_snprintf ( tmp , sizeof ( tmp ) , " HTTP/1.0 200 OK \r \n Date: %s \r \n Content-Length: %d \r \n Content-Type: text/plain \r \n \r \n " ,
2005-09-07 18:42:53 +02:00
date ,
( int ) len ) ;
connection_write_to_buf ( tmp , strlen ( tmp ) , conn ) ;
2005-11-05 21:15:27 +01:00
SMARTLIST_FOREACH ( descs , signed_descriptor_t * , ri ,
2005-09-07 18:42:53 +02:00
connection_write_to_buf ( ri - > signed_descriptor ,
ri - > signed_descriptor_len ,
conn ) ) ;
}
2005-08-25 22:33:17 +02:00
}
smartlist_free ( descs ) ;
return 0 ;
}
2005-06-29 23:46:55 +02:00
if ( ! strcmpstart ( url , " /tor/rendezvous/ " ) | |
! strcmpstart ( url , " /tor/rendezvous1/ " ) ) {
2004-03-31 07:01:30 +02:00
/* rendezvous descriptor fetch */
2004-03-31 05:42:56 +02:00
const char * descp ;
2004-10-14 04:47:09 +02:00
size_t desc_len ;
2005-06-29 23:46:55 +02:00
int versioned = ! strcmpstart ( url , " /tor/rendezvous1/ " ) ;
const char * query = url + strlen ( " /tor/rendezvous/ " ) + ( versioned ? 1 : 0 ) ;
2004-03-31 00:57:49 +02:00
2004-11-28 10:05:49 +01:00
if ( ! authdir_mode ( get_options ( ) ) ) {
2004-07-21 10:40:57 +02:00
/* We don't hand out rend descs. In fact, it could be a security
* risk , since rend_cache_lookup_desc ( ) below would provide it
* if we ' re gone to the site recently , and 404 if we haven ' t .
*
* Reject . */
2005-10-18 16:57:46 +02:00
write_http_status_line ( conn , 400 , " Nonauthoritative directory does not not store rendezvous descriptors " ) ;
2004-09-27 05:39:30 +02:00
tor_free ( url ) ;
2004-07-21 10:40:57 +02:00
return 0 ;
}
2005-06-29 23:46:55 +02:00
switch ( rend_cache_lookup_desc ( query , versioned ? - 1 : 0 , & descp , & desc_len ) ) {
2004-03-31 01:41:24 +02:00
case 1 : /* valid */
2004-08-07 04:46:16 +02:00
format_rfc1123_time ( date , time ( NULL ) ) ;
2004-10-27 08:37:34 +02:00
tor_snprintf ( tmp , sizeof ( tmp ) , " HTTP/1.0 200 OK \r \n Date: %s \r \n Content-Length: %d \r \n Content-Type: application/octet-stream \r \n \r \n " ,
2004-08-04 03:15:57 +02:00
date ,
2004-10-14 04:47:09 +02:00
( int ) desc_len ) ; /* can't include descp here, because it's got nuls */
2004-03-31 07:01:30 +02:00
connection_write_to_buf ( tmp , strlen ( tmp ) , conn ) ;
connection_write_to_buf ( descp , desc_len , conn ) ;
2004-03-31 01:41:24 +02:00
break ;
case 0 : /* well-formed but not present */
2005-01-20 20:46:02 +01:00
write_http_status_line ( conn , 404 , " Not found " ) ;
2004-03-31 01:41:24 +02:00
break ;
case - 1 : /* not well-formed */
2005-01-20 20:46:02 +01:00
write_http_status_line ( conn , 400 , " Bad request " ) ;
2004-03-31 01:41:24 +02:00
break ;
}
2004-09-27 05:39:30 +02:00
tor_free ( url ) ;
2004-03-31 01:41:24 +02:00
return 0 ;
2004-03-31 00:57:49 +02:00
}
/* we didn't recognize the url */
2005-01-20 20:46:02 +01:00
write_http_status_line ( conn , 404 , " Not found " ) ;
2004-09-27 05:39:30 +02:00
tor_free ( url ) ;
2003-12-17 10:42:28 +01:00
return 0 ;
}
2004-05-09 18:47:25 +02:00
/** Helper function: called when a dirserver gets a complete HTTP POST
2004-05-06 13:08:04 +02:00
* request . Look for an uploaded server descriptor or rendezvous
* service descriptor . On finding one , process it and write a
2004-05-10 06:34:48 +02:00
* response into conn - \ > outbuf . If the request is unrecognized , send a
2004-09-27 05:39:30 +02:00
* 400. Always return 0. */
2004-05-13 01:48:57 +02:00
static int
directory_handle_command_post ( connection_t * conn , char * headers ,
2005-06-11 20:52:12 +02:00
char * body , size_t body_len )
2004-05-13 01:48:57 +02:00
{
2003-12-17 10:42:28 +01:00
const char * cp ;
2005-08-24 00:27:17 +02:00
char * origin = NULL ;
char * url = NULL ;
2003-12-17 10:42:28 +01:00
2005-10-25 10:20:10 +02:00
debug ( LD_DIRSERV , " Received POST command. " ) ;
2004-03-31 00:57:49 +02:00
2003-12-17 10:42:28 +01:00
conn - > state = DIR_CONN_STATE_SERVER_WRITING ;
2004-03-31 00:57:49 +02:00
2004-11-28 10:05:49 +01:00
if ( ! authdir_mode ( get_options ( ) ) ) {
2004-07-21 10:40:57 +02:00
/* we just provide cached directories; we don't want to
* receive anything . */
2005-10-18 16:57:46 +02:00
write_http_status_line ( conn , 400 , " Nonauthoritative directory does not accept posted server descriptors " ) ;
2004-07-21 10:40:57 +02:00
return 0 ;
}
2004-03-31 00:57:49 +02:00
if ( parse_http_url ( headers , & url ) < 0 ) {
2005-01-20 20:46:02 +01:00
write_http_status_line ( conn , 400 , " Bad request " ) ;
2004-03-31 00:57:49 +02:00
return 0 ;
}
2005-10-25 10:20:10 +02:00
debug ( LD_DIRSERV , " rewritten url as '%s'. " , url ) ;
2005-08-24 00:27:17 +02:00
origin = http_get_origin ( headers , conn ) ;
2004-03-31 00:57:49 +02:00
2004-11-28 10:05:49 +01:00
if ( ! strcmp ( url , " /tor/ " ) ) { /* server descriptor post */
2005-01-20 21:18:32 +01:00
const char * msg ;
2005-08-31 08:14:37 +02:00
int r = dirserv_add_descriptor ( body , & msg ) ;
tor_assert ( msg ) ;
if ( r > 0 )
dirserv_get_directory ( & cp , 0 ) ; /* rebuild and write to disk */
switch ( r ) {
2005-01-29 12:23:34 +01:00
case - 2 :
2004-03-31 00:57:49 +02:00
case - 1 :
2005-08-31 08:14:37 +02:00
case 1 :
2005-10-25 10:20:10 +02:00
notice ( LD_DIRSERV , " Rejected descriptor from %s. " , origin ) ;
2005-08-31 08:14:37 +02:00
/* malformed descriptor, or something wrong */
write_http_status_line ( conn , 400 , msg ) ;
2004-03-31 00:57:49 +02:00
break ;
2005-08-31 08:14:37 +02:00
case 0 : /* accepted but discarded */
case 2 : /* accepted */
write_http_status_line ( conn , 200 , msg ) ;
2004-03-31 00:57:49 +02:00
break ;
}
2005-08-24 00:27:17 +02:00
goto done ;
2004-03-31 00:57:49 +02:00
}
2004-11-28 10:05:49 +01:00
if ( ! strcmpstart ( url , " /tor/rendezvous/publish " ) ) {
2004-03-31 07:01:30 +02:00
/* rendezvous descriptor post */
2004-11-28 10:05:49 +01:00
if ( rend_cache_store ( body , body_len ) < 0 )
2005-01-20 20:46:02 +01:00
write_http_status_line ( conn , 400 , " Invalid service descriptor rejected " ) ;
2004-03-31 01:41:24 +02:00
else
2005-01-20 20:46:02 +01:00
write_http_status_line ( conn , 200 , " Service descriptor stored " ) ;
2005-08-24 00:27:17 +02:00
goto done ;
2004-03-31 00:57:49 +02:00
}
/* we didn't recognize the url */
2005-01-20 20:46:02 +01:00
write_http_status_line ( conn , 404 , " Not found " ) ;
2005-08-24 00:27:17 +02:00
done :
2004-09-27 05:39:30 +02:00
tor_free ( url ) ;
2005-08-24 00:27:17 +02:00
tor_free ( origin ) ;
2003-12-17 10:42:28 +01:00
return 0 ;
2005-08-24 00:27:17 +02:00
2003-12-17 10:42:28 +01:00
}
2004-05-09 18:47:25 +02:00
/** Called when a dirserver receives data on a directory connection;
2004-05-05 04:50:38 +02:00
* looks for an HTTP request . If the request is complete , remove it
* from the inbuf , try to process it ; otherwise , leave it on the
* buffer . Return a 0 on success , or - 1 on error .
*/
2005-06-11 20:52:12 +02:00
static int
directory_handle_command ( connection_t * conn )
{
2003-12-17 10:42:28 +01:00
char * headers = NULL , * body = NULL ;
2004-10-14 04:47:09 +02:00
size_t body_len = 0 ;
2003-12-17 10:42:28 +01:00
int r ;
2004-10-17 00:14:52 +02:00
tor_assert ( conn ) ;
tor_assert ( conn - > type = = CONN_TYPE_DIR ) ;
2002-09-26 14:09:10 +02:00
2004-11-28 10:05:49 +01:00
switch ( fetch_from_buf_http ( conn - > inbuf ,
2004-11-28 12:39:53 +01:00
& headers , MAX_HEADERS_SIZE ,
2005-10-14 04:26:13 +02:00
& body , & body_len , MAX_BODY_SIZE , 0 ) ) {
2003-09-17 22:09:06 +02:00
case - 1 : /* overflow */
2005-10-25 10:20:10 +02:00
warn ( LD_DIRSERV ,
" Invalid input from address '%s'. Closing. " , conn - > address ) ;
2003-09-17 22:09:06 +02:00
return - 1 ;
case 0 :
2005-10-25 10:20:10 +02:00
debug ( LD_DIRSERV , " command not all here yet. " ) ;
2003-09-17 22:09:06 +02:00
return 0 ;
/* case 1, fall through */
2002-09-26 14:09:10 +02:00
}
2005-10-25 10:20:10 +02:00
debug ( LD_DIRSERV , " headers '%s', body '%s'. " , headers , body ) ;
2002-09-26 14:09:10 +02:00
2004-11-28 10:05:49 +01:00
if ( ! strncasecmp ( headers , " GET " , 3 ) )
2004-03-31 07:01:30 +02:00
r = directory_handle_command_get ( conn , headers , body , body_len ) ;
2003-12-17 10:42:28 +01:00
else if ( ! strncasecmp ( headers , " POST " , 4 ) )
2004-03-31 07:01:30 +02:00
r = directory_handle_command_post ( conn , headers , body , body_len ) ;
2003-12-17 10:42:28 +01:00
else {
2005-10-25 10:20:10 +02:00
warn ( LD_PROTOCOL , " Got headers '%s' with unknown command. Closing. " , headers ) ;
2003-12-17 10:42:28 +01:00
r = - 1 ;
2002-09-26 14:09:10 +02:00
}
2003-12-17 10:42:28 +01:00
tor_free ( headers ) ; tor_free ( body ) ;
return r ;
2002-09-26 14:09:10 +02:00
}
2004-05-09 18:47:25 +02:00
/** Write handler for directory connections; called when all data has
2004-05-12 21:17:09 +02:00
* been flushed . Close the connection or wait for a response as
* appropriate .
2004-05-05 04:50:38 +02:00
*/
2005-06-11 20:52:12 +02:00
int
connection_dir_finished_flushing ( connection_t * conn )
{
2004-10-17 00:14:52 +02:00
tor_assert ( conn ) ;
tor_assert ( conn - > type = = CONN_TYPE_DIR ) ;
2002-09-26 14:09:10 +02:00
2004-11-28 10:05:49 +01:00
switch ( conn - > state ) {
2004-03-31 00:57:49 +02:00
case DIR_CONN_STATE_CLIENT_SENDING :
2005-10-25 10:20:10 +02:00
debug ( LD_DIR , " client finished sending command. " ) ;
2004-03-31 00:57:49 +02:00
conn - > state = DIR_CONN_STATE_CLIENT_READING ;
connection_stop_writing ( conn ) ;
2002-09-26 14:09:10 +02:00
return 0 ;
2003-09-17 22:09:06 +02:00
case DIR_CONN_STATE_SERVER_WRITING :
2005-10-25 10:20:10 +02:00
debug ( LD_DIRSERV , " Finished writing server response. Closing. " ) ;
2004-05-12 23:12:33 +02:00
connection_mark_for_close ( conn ) ;
2004-02-28 05:11:53 +01:00
return 0 ;
2002-09-26 14:09:10 +02:00
default :
2005-10-25 10:20:10 +02:00
warn ( LD_BUG , " Bug: called in unexpected state %d. " , conn - > state ) ;
2005-04-26 20:52:16 +02:00
tor_fragile_assert ( ) ;
2003-09-26 12:03:50 +02:00
return - 1 ;
2002-09-26 14:09:10 +02:00
}
return 0 ;
}
2004-05-12 21:17:09 +02:00
/** Connected handler for directory connections: begin sending data to the
* server */
2005-06-11 20:52:12 +02:00
int
connection_dir_finished_connecting ( connection_t * conn )
2004-05-12 21:17:09 +02:00
{
2004-10-17 00:14:52 +02:00
tor_assert ( conn ) ;
tor_assert ( conn - > type = = CONN_TYPE_DIR ) ;
2004-05-12 21:17:09 +02:00
tor_assert ( conn - > state = = DIR_CONN_STATE_CONNECTING ) ;
2005-10-25 10:20:10 +02:00
debug ( LD_HTTP , " Dir connection to router %s:%u established. " ,
conn - > address , conn - > port ) ;
2004-05-12 21:17:09 +02:00
conn - > state = DIR_CONN_STATE_CLIENT_SENDING ; /* start flushing conn */
return 0 ;
}
2005-06-09 21:03:31 +02:00
2005-09-13 23:14:55 +02:00
/** Called when one or more networkstatus fetches have failed (with uppercase
2005-09-15 08:15:31 +02:00
* fingerprints listed in < b > failed < / > ) . Mark those fingerprints has having
2005-09-13 23:14:55 +02:00
* failed once . */
2005-09-12 08:56:42 +02:00
static void
dir_networkstatus_download_failed ( smartlist_t * failed )
{
SMARTLIST_FOREACH ( failed , const char * , fp ,
{
char digest [ DIGEST_LEN ] ;
trusted_dir_server_t * dir ;
base16_decode ( digest , DIGEST_LEN , fp , strlen ( fp ) ) ;
dir = router_get_trusteddirserver_by_digest ( digest ) ;
2005-11-08 23:30:17 +01:00
if ( dir )
+ + dir - > n_networkstatus_failures ;
2005-09-12 08:56:42 +02:00
} ) ;
}
2005-09-15 08:15:31 +02:00
/** Called when one or more networkstatus fetches have failed (with uppercase
* fingerprints listed in < b > failed < / > ) . */
2005-09-15 07:19:38 +02:00
static void
dir_routerdesc_download_failed ( smartlist_t * failed )
{
2005-09-18 06:15:39 +02:00
char digest [ DIGEST_LEN ] ;
2005-09-22 03:51:14 +02:00
local_routerstatus_t * rs ;
2005-09-22 08:34:29 +02:00
time_t now = time ( NULL ) ;
int server = server_mode ( get_options ( ) ) & & get_options ( ) - > DirPort ;
2005-09-18 04:51:12 +02:00
SMARTLIST_FOREACH ( failed , const char * , cp ,
{
2005-09-18 06:15:39 +02:00
base16_decode ( digest , DIGEST_LEN , cp , strlen ( cp ) ) ;
rs = router_get_combined_status_by_digest ( digest ) ;
2005-09-18 04:51:12 +02:00
if ( ! rs | | rs - > n_download_failures > = MAX_ROUTERDESC_DOWNLOAD_FAILURES )
continue ;
+ + rs - > n_download_failures ;
2005-09-22 08:34:29 +02:00
if ( server ) {
switch ( rs - > n_download_failures ) {
case 1 : rs - > next_attempt_at = 0 ; break ;
case 2 : rs - > next_attempt_at = 0 ; break ;
case 3 : rs - > next_attempt_at = now + 60 ; break ;
case 4 : rs - > next_attempt_at = now + 60 ; break ;
case 5 : rs - > next_attempt_at = now + 60 * 2 ; break ;
case 6 : rs - > next_attempt_at = now + 60 * 5 ; break ;
case 7 : rs - > next_attempt_at = now + 60 * 15 ; break ;
default : rs - > next_attempt_at = TIME_MAX ; break ;
}
} else {
switch ( rs - > n_download_failures ) {
case 1 : rs - > next_attempt_at = 0 ; break ;
case 2 : rs - > next_attempt_at = now + 60 ; break ;
case 3 : rs - > next_attempt_at = now + 60 * 5 ; break ;
case 4 : rs - > next_attempt_at = now + 60 * 10 ; break ;
default : rs - > next_attempt_at = TIME_MAX ; break ;
}
}
if ( rs - > next_attempt_at = = 0 )
2005-10-25 10:20:10 +02:00
debug ( LD_DIR , " %s failed %d time(s); I'll try again immediately. " ,
2005-09-22 08:34:29 +02:00
cp , ( int ) rs - > n_download_failures ) ;
else if ( rs - > next_attempt_at < TIME_MAX )
2005-10-25 10:20:10 +02:00
debug ( LD_DIR , " %s failed %d time(s); I'll try again in %d seconds. " ,
2005-09-22 08:34:29 +02:00
cp , ( int ) rs - > n_download_failures , ( int ) ( rs - > next_attempt_at - now ) ) ;
else
2005-10-25 10:20:10 +02:00
debug ( LD_DIR , " %s failed %d time(s); Giving up for a while. " ,
2005-09-22 08:34:29 +02:00
cp , ( int ) rs - > n_download_failures ) ;
2005-09-18 04:51:12 +02:00
} ) ;
2005-09-22 08:34:29 +02:00
2005-09-23 20:05:14 +02:00
/* update_router_descriptor_downloads(time(NULL)); */
2005-09-15 07:19:38 +02:00
}
2005-09-30 22:04:55 +02:00
/* Given a directory <b>resource</b> request generated by us, containing zero
* or more strings separated by plus signs , followed optionally by " .z " , store
* the strings , in order , into < b > fp_out < / b > . If < b > compressed_out < / b > is
2005-10-14 06:56:20 +02:00
* non - NULL , set it to 1 if the resource ends in " .z " , else set it to 0. If
* decode_hex is true , then delete all elements that aren ' t hex digests , and
* decode the rest .
2005-09-30 22:04:55 +02:00
*/
2005-09-16 06:42:45 +02:00
int
dir_split_resource_into_fingerprints ( const char * resource ,
2005-10-14 06:56:20 +02:00
smartlist_t * fp_out , int * compressed_out ,
int decode_hex )
2005-09-16 06:42:45 +02:00
{
2005-10-28 01:16:08 +02:00
int old_len ;
tor_assert ( fp_out ) ;
old_len = smartlist_len ( fp_out ) ;
2005-09-16 06:42:45 +02:00
smartlist_split_string ( fp_out , resource , " + " , 0 , 0 ) ;
if ( compressed_out )
* compressed_out = 0 ;
2005-10-28 01:16:08 +02:00
if ( smartlist_len ( fp_out ) > old_len ) {
2005-09-16 06:42:45 +02:00
char * last = smartlist_get ( fp_out , smartlist_len ( fp_out ) - 1 ) ;
size_t last_len = strlen ( last ) ;
if ( last_len > 2 & & ! strcmp ( last + last_len - 2 , " .z " ) ) {
last [ last_len - 2 ] = ' \0 ' ;
if ( compressed_out )
* compressed_out = 1 ;
}
}
2005-10-14 06:56:20 +02:00
if ( decode_hex ) {
int i ;
2005-10-25 09:03:22 +02:00
char * cp , * d = NULL ;
2005-10-28 01:16:08 +02:00
for ( i = old_len ; i < smartlist_len ( fp_out ) ; + + i ) {
2005-10-14 06:56:20 +02:00
cp = smartlist_get ( fp_out , i ) ;
if ( strlen ( cp ) ! = HEX_DIGEST_LEN ) {
2005-10-28 01:16:08 +02:00
info ( LD_DIR , " Skipping digest \" %s \" with non-standard length. " , cp ) ;
2005-10-14 06:56:20 +02:00
smartlist_del ( fp_out , i - - ) ;
2005-10-25 09:03:22 +02:00
goto again ;
2005-10-14 06:56:20 +02:00
}
d = tor_malloc_zero ( DIGEST_LEN ) ;
if ( base16_decode ( d , DIGEST_LEN , cp , HEX_DIGEST_LEN ) < 0 ) {
2005-10-28 01:16:08 +02:00
info ( LD_DIR , " Skipping non-decodable digest \" %s \" " , cp ) ;
2005-10-14 06:56:20 +02:00
smartlist_del ( fp_out , i - - ) ;
2005-10-25 09:03:22 +02:00
goto again ;
2005-10-14 06:56:20 +02:00
}
smartlist_set ( fp_out , i , d ) ;
2005-10-25 09:03:22 +02:00
d = NULL ;
again :
tor_free ( cp ) ;
tor_free ( d ) ;
2005-10-14 06:56:20 +02:00
}
}
2005-09-16 06:52:53 +02:00
return 0 ;
2005-09-16 06:42:45 +02:00
}