directory.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /* Copyright 2001,2002,2003 Roger Dingledine. */
  2. /* See LICENSE for licensing information */
  3. /* $Id$ */
  4. #include "or.h"
  5. static int directory_send_command(connection_t *conn, int command);
  6. static int directory_handle_command(connection_t *conn);
  7. /********* START VARIABLES **********/
  8. extern or_options_t options; /* command-line and config-file options */
  9. extern int has_fetched_directory;
  10. #define MAX_HEADERS_SIZE 2048
  11. #define MAX_BODY_SIZE 500000
  12. /********* END VARIABLES ************/
  13. void directory_initiate_command(routerinfo_t *router, int command) {
  14. connection_t *conn;
  15. switch(command) {
  16. case DIR_CONN_STATE_CONNECTING_FETCH:
  17. log_fn(LOG_DEBUG,"initiating directory fetch");
  18. break;
  19. case DIR_CONN_STATE_CONNECTING_UPLOAD:
  20. log_fn(LOG_DEBUG,"initiating directory upload");
  21. break;
  22. }
  23. if (!router) { /* i guess they didn't have one in mind for me to use */
  24. log_fn(LOG_WARN,"No running dirservers known. Not trying.");
  25. return;
  26. }
  27. conn = connection_new(CONN_TYPE_DIR);
  28. /* set up conn so it's got all the data we need to remember */
  29. conn->addr = router->addr;
  30. conn->port = router->dir_port;
  31. conn->address = tor_strdup(router->address);
  32. conn->nickname = tor_strdup(router->nickname);
  33. assert(router->identity_pkey);
  34. conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey);
  35. conn->state = command;
  36. if(connection_add(conn) < 0) { /* no space, forget it */
  37. connection_free(conn);
  38. return;
  39. }
  40. switch(connection_connect(conn, router->address, router->addr, router->dir_port)) {
  41. case -1:
  42. router_mark_as_down(conn->nickname); /* don't try him again */
  43. connection_mark_for_close(conn, 0);
  44. return;
  45. case 0:
  46. connection_set_poll_socket(conn);
  47. connection_watch_events(conn, POLLIN | POLLOUT | POLLERR);
  48. /* writable indicates finish, readable indicates broken link,
  49. error indicates broken link in windowsland. */
  50. return;
  51. /* case 1: fall through */
  52. }
  53. connection_set_poll_socket(conn);
  54. if(directory_send_command(conn, command) < 0) {
  55. connection_mark_for_close(conn, 0);
  56. }
  57. }
  58. static int directory_send_command(connection_t *conn, int command) {
  59. char fetchstring[] = "GET / HTTP/1.0\r\n\r\n";
  60. const char *s;
  61. char tmp[8192];
  62. assert(conn && conn->type == CONN_TYPE_DIR);
  63. switch(command) {
  64. case DIR_CONN_STATE_CONNECTING_FETCH:
  65. connection_write_to_buf(fetchstring, strlen(fetchstring), conn);
  66. conn->state = DIR_CONN_STATE_CLIENT_SENDING_FETCH;
  67. break;
  68. case DIR_CONN_STATE_CONNECTING_UPLOAD:
  69. s = router_get_my_descriptor();
  70. if(!s) {
  71. log_fn(LOG_WARN,"Failed to get my descriptor.");
  72. return -1;
  73. }
  74. snprintf(tmp, sizeof(tmp), "POST / HTTP/1.0\r\nContent-Length: %d\r\n\r\n%s",
  75. (int)strlen(s), s);
  76. connection_write_to_buf(tmp, strlen(tmp), conn);
  77. conn->state = DIR_CONN_STATE_CLIENT_SENDING_UPLOAD;
  78. break;
  79. }
  80. return 0;
  81. }
  82. /* Parse "HTTP/1.%d %d%s\r\n".
  83. * If it's well-formed, assign *code, point *message to the first
  84. * non-space character after code if there is one and message is non-NULL
  85. * (else leave it alone), and return 0.
  86. * Otherwise, return -1.
  87. */
  88. int parse_http_response(char *headers, int *code, char **message) {
  89. int n1, n2;
  90. assert(headers && code);
  91. while(isspace((int)*headers)) headers++; /* tolerate leading whitespace */
  92. if(sscanf(headers, "HTTP/1.%d %d", &n1, &n2) < 2 ||
  93. (n1 != 0 && n1 != 1) ||
  94. (n2 < 100 || n2 >= 600)) {
  95. log_fn(LOG_WARN,"Failed to parse header '%s'",headers);
  96. return -1;
  97. }
  98. *code = n2;
  99. if(message) {
  100. /* XXX should set *message correctly */
  101. }
  102. return 0;
  103. }
  104. int connection_dir_process_inbuf(connection_t *conn) {
  105. char *directory;
  106. char *headers;
  107. int status_code;
  108. assert(conn && conn->type == CONN_TYPE_DIR);
  109. if(conn->inbuf_reached_eof) {
  110. if(conn->state != DIR_CONN_STATE_CLIENT_READING_FETCH &&
  111. conn->state != DIR_CONN_STATE_CLIENT_READING_UPLOAD) {
  112. log_fn(LOG_INFO,"conn reached eof, not reading. Closing.");
  113. connection_close_immediate(conn); /* it was an error; give up on flushing */
  114. connection_mark_for_close(conn,0);
  115. return -1;
  116. }
  117. switch(fetch_from_buf_http(conn->inbuf,
  118. &headers, MAX_HEADERS_SIZE,
  119. &directory, MAX_DIR_SIZE)) {
  120. case -1: /* overflow */
  121. log_fn(LOG_WARN,"'fetch' response too large. Failing.");
  122. connection_mark_for_close(conn,0);
  123. return -1;
  124. case 0:
  125. log_fn(LOG_INFO,"'fetch' response not all here, but we're at eof. Closing.");
  126. connection_mark_for_close(conn,0);
  127. return -1;
  128. /* case 1, fall through */
  129. }
  130. if(parse_http_response(headers, &status_code, NULL) < 0) {
  131. log_fn(LOG_WARN,"Unparseable headers. Closing.");
  132. free(directory); free(headers);
  133. connection_mark_for_close(conn,0);
  134. return -1;
  135. }
  136. if(conn->state == DIR_CONN_STATE_CLIENT_READING_FETCH) {
  137. /* fetch/process the directory to learn about new routers. */
  138. int directorylen;
  139. directorylen = strlen(directory);
  140. log_fn(LOG_INFO,"Received directory (size %d):\n%s", directorylen, directory);
  141. if(status_code == 503 || directorylen == 0) {
  142. log_fn(LOG_INFO,"Empty directory. Ignoring.");
  143. free(directory); free(headers);
  144. connection_mark_for_close(conn,0);
  145. return 0;
  146. }
  147. if(status_code != 200) {
  148. log_fn(LOG_WARN,"Received http status code %d from dirserver. Failing.",
  149. status_code);
  150. free(directory); free(headers);
  151. connection_mark_for_close(conn,0);
  152. return -1;
  153. }
  154. if(router_set_routerlist_from_directory(directory, conn->identity_pkey) < 0){
  155. log_fn(LOG_INFO,"...but parsing failed. Ignoring.");
  156. } else {
  157. log_fn(LOG_INFO,"updated routers.");
  158. }
  159. has_fetched_directory=1;
  160. if(options.ORPort) { /* connect to them all */
  161. router_retry_connections();
  162. }
  163. free(directory); free(headers);
  164. connection_mark_for_close(conn,0);
  165. return 0;
  166. }
  167. if(conn->state == DIR_CONN_STATE_CLIENT_READING_UPLOAD) {
  168. switch(status_code) {
  169. case 200:
  170. log_fn(LOG_INFO,"eof (status 200) while reading upload response: finished.");
  171. break;
  172. case 400:
  173. log_fn(LOG_WARN,"http status 400 (bad request) response from dirserver.");
  174. break;
  175. case 403:
  176. 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?");
  177. break;
  178. }
  179. free(directory); free(headers);
  180. connection_mark_for_close(conn,0);
  181. return 0;
  182. }
  183. }
  184. if(conn->state == DIR_CONN_STATE_SERVER_COMMAND_WAIT)
  185. return directory_handle_command(conn);
  186. /* XXX for READ states, might want to make sure inbuf isn't too big */
  187. log_fn(LOG_DEBUG,"Got data, not eof. Leaving on inbuf.");
  188. return 0;
  189. }
  190. static char answer200[] = "HTTP/1.0 200 OK\r\n\r\n";
  191. static char answer400[] = "HTTP/1.0 400 Bad request\r\n\r\n";
  192. static char answer403[] = "HTTP/1.0 403 Unapproved server\r\n\r\n";
  193. static char answer503[] = "HTTP/1.0 503 Directory unavailable\r\n\r\n";
  194. static int directory_handle_command_get(connection_t *conn,
  195. char *headers, char *body) {
  196. size_t dlen;
  197. const char *cp;
  198. /* XXX should check url and http version */
  199. log_fn(LOG_DEBUG,"Received GET command.");
  200. dlen = dirserv_get_directory(&cp);
  201. if(dlen == 0) {
  202. log_fn(LOG_WARN,"My directory is empty. Closing.");
  203. connection_write_to_buf(answer503, strlen(answer503), conn);
  204. conn->state = DIR_CONN_STATE_SERVER_WRITING;
  205. return 0;
  206. }
  207. log_fn(LOG_DEBUG,"Dumping directory to client.");
  208. connection_write_to_buf(answer200, strlen(answer200), conn);
  209. connection_write_to_buf(cp, dlen, conn);
  210. conn->state = DIR_CONN_STATE_SERVER_WRITING;
  211. return 0;
  212. }
  213. static int directory_handle_command_post(connection_t *conn,
  214. char *headers, char *body) {
  215. const char *cp;
  216. /* XXX should check url and http version */
  217. log_fn(LOG_DEBUG,"Received POST command.");
  218. cp = body;
  219. switch(dirserv_add_descriptor(&cp)) {
  220. case -1:
  221. /* malformed descriptor, or something wrong */
  222. connection_write_to_buf(answer400, strlen(answer400), conn);
  223. break;
  224. case 0:
  225. /* descriptor was well-formed but server has not been approved */
  226. connection_write_to_buf(answer403, strlen(answer403), conn);
  227. break;
  228. case 1:
  229. dirserv_get_directory(&cp); /* rebuild and write to disk */
  230. connection_write_to_buf(answer200, strlen(answer200), conn);
  231. break;
  232. }
  233. conn->state = DIR_CONN_STATE_SERVER_WRITING;
  234. return 0;
  235. }
  236. static int directory_handle_command(connection_t *conn) {
  237. char *headers=NULL, *body=NULL;
  238. int r;
  239. assert(conn && conn->type == CONN_TYPE_DIR);
  240. switch(fetch_from_buf_http(conn->inbuf,
  241. &headers, MAX_HEADERS_SIZE, &body, MAX_BODY_SIZE)) {
  242. case -1: /* overflow */
  243. log_fn(LOG_WARN,"input too large. Failing.");
  244. return -1;
  245. case 0:
  246. log_fn(LOG_DEBUG,"command not all here yet.");
  247. return 0;
  248. /* case 1, fall through */
  249. }
  250. log_fn(LOG_DEBUG,"headers '%s', body '%s'.", headers, body);
  251. if(!strncasecmp(headers,"GET",3))
  252. r = directory_handle_command_get(conn, headers, body);
  253. else if (!strncasecmp(headers,"POST",4))
  254. r = directory_handle_command_post(conn, headers, body);
  255. else {
  256. log_fn(LOG_WARN,"Got headers '%s' with unknown command. Closing.", headers);
  257. r = -1;
  258. }
  259. tor_free(headers); tor_free(body);
  260. return r;
  261. }
  262. int connection_dir_finished_flushing(connection_t *conn) {
  263. int e, len=sizeof(e);
  264. assert(conn && conn->type == CONN_TYPE_DIR);
  265. switch(conn->state) {
  266. case DIR_CONN_STATE_CONNECTING_FETCH:
  267. case DIR_CONN_STATE_CONNECTING_UPLOAD:
  268. if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { /* not yet */
  269. if(!ERRNO_CONN_EINPROGRESS(errno)) {
  270. log_fn(LOG_DEBUG,"in-progress connect failed. Removing.");
  271. router_mark_as_down(conn->nickname); /* don't try him again */
  272. connection_mark_for_close(conn,0);
  273. return -1;
  274. } else {
  275. return 0; /* no change, see if next time is better */
  276. }
  277. }
  278. /* the connect has finished. */
  279. log_fn(LOG_INFO,"Dir connection to router %s:%u established.",
  280. conn->address,conn->port);
  281. return directory_send_command(conn, conn->state);
  282. case DIR_CONN_STATE_CLIENT_SENDING_FETCH:
  283. log_fn(LOG_DEBUG,"client finished sending fetch command.");
  284. conn->state = DIR_CONN_STATE_CLIENT_READING_FETCH;
  285. connection_watch_events(conn, POLLIN);
  286. return 0;
  287. case DIR_CONN_STATE_CLIENT_SENDING_UPLOAD:
  288. log_fn(LOG_DEBUG,"client finished sending upload command.");
  289. conn->state = DIR_CONN_STATE_CLIENT_READING_UPLOAD;
  290. connection_watch_events(conn, POLLIN);
  291. return 0;
  292. case DIR_CONN_STATE_SERVER_WRITING:
  293. log_fn(LOG_INFO,"Finished writing server response. Closing.");
  294. connection_mark_for_close(conn,0);
  295. return 0;
  296. default:
  297. log_fn(LOG_WARN,"BUG: called in unexpected state %d.", conn->state);
  298. return -1;
  299. }
  300. return 0;
  301. }
  302. /*
  303. Local Variables:
  304. mode:c
  305. indent-tabs-mode:nil
  306. c-basic-offset:2
  307. End:
  308. */