when a client asks us for a dir mirror and we don't have one,
[tor.git] / src / or / directory.c
blob6cb6b64c9321dbbbc632fa84bd01930d9ba022c1
1 /* Copyright 2001-2004 Roger Dingledine.
2 * Copyright 2004 Roger Dingledine, Nick Mathewson. */
3 /* See LICENSE for licensing information */
4 /* $Id$ */
5 const char directory_c_id[] = "$Id$";
7 #include "or.h"
9 /**
10 * \file directory.c
11 * \brief Implement directory HTTP protocol.
12 **/
14 /* In-points to directory.c:
16 * - directory_post_to_dirservers(), called from
17 * router_upload_dir_desc_to_dirservers() in router.c
18 * upload_service_descriptor() in rendservice.c
19 * - directory_get_from_dirserver(), called from
20 * rend_client_refetch_renddesc() in rendclient.c
21 * run_scheduled_events() in main.c
22 * do_hup() in main.c
23 * - connection_dir_process_inbuf(), called from
24 * connection_process_inbuf() in connection.c
25 * - connection_dir_finished_flushing(), called from
26 * connection_finished_flushing() in connection.c
27 * - connection_dir_finished_connecting(), called from
28 * connection_finished_connecting() in connection.c
31 static void
32 directory_initiate_command_router(routerinfo_t *router, uint8_t purpose,
33 const char *resource,
34 const char *payload, size_t payload_len);
35 static void
36 directory_initiate_command_trusted_dir(trusted_dir_server_t *dirserv,
37 uint8_t purpose, const char *resource,
38 const char *payload, size_t payload_len);
39 static void
40 directory_initiate_command(const char *address, uint32_t addr, uint16_t port,
41 const char *platform,
42 const char *digest, uint8_t purpose,
43 const char *resource,
44 const char *payload, size_t payload_len);
46 static void
47 directory_send_command(connection_t *conn, const char *platform,
48 int purpose, const char *resource,
49 const char *payload, size_t payload_len);
50 static int directory_handle_command(connection_t *conn);
51 static int body_is_plausible(const char *body, size_t body_len, int purpose);
53 /********* START VARIABLES **********/
55 static addr_policy_t *dir_policy = NULL;
57 #if 0 /* commented out for now, since for now what clients send is
58 different from what servers want to receive */
59 /** URL for publishing rendezvous descriptors. */
60 char rend_publish_string[] = "/tor/rendezvous/publish";
61 /** Prefix for downloading rendezvous descriptors. */
62 char rend_fetch_url[] = "/tor/rendezvous/";
63 #endif
65 #define MAX_HEADERS_SIZE 50000
66 #define MAX_BODY_SIZE 500000
68 #define ALLOW_DIRECTORY_TIME_SKEW 30*60
70 /********* END VARIABLES ************/
72 /** Parse get_options()->DirPolicy, and put the processed version in
73 * &dir_policy. Ignore port specifiers.
75 void
76 parse_dir_policy(void)
78 addr_policy_t *n;
79 if (dir_policy) {
80 addr_policy_free(dir_policy);
81 dir_policy = NULL;
83 config_parse_addr_policy(get_options()->DirPolicy, &dir_policy);
84 /* ports aren't used. */
85 for (n=dir_policy; n; n = n->next) {
86 n->prt_min = 1;
87 n->prt_max = 65535;
91 /** Return 1 if <b>addr</b> is permitted to connect to our dir port,
92 * based on <b>dir_policy</b>. Else return 0.
94 int dir_policy_permits_address(uint32_t addr)
96 int a;
98 if (!dir_policy) /* 'no dir policy' means 'accept' */
99 return 1;
100 a = router_compare_addr_to_addr_policy(addr, 1, dir_policy);
101 if (a==-1)
102 return 0;
103 else if (a==0)
104 return 1;
105 tor_assert(a==1);
106 log_fn(LOG_WARN, "Bug: got unexpected 'maybe' answer from dir policy");
107 return 0;
110 /** Start a connection to every known directory server, using
111 * connection purpose 'purpose' and uploading the payload 'payload'
112 * (length 'payload_len'). The purpose should be one of
113 * 'DIR_PURPOSE_UPLOAD_DIR' or 'DIR_PURPOSE_UPLOAD_RENDDESC'.
115 void
116 directory_post_to_dirservers(uint8_t purpose, const char *payload,
117 size_t payload_len)
119 smartlist_t *dirservers;
121 router_get_trusted_dir_servers(&dirservers);
122 tor_assert(dirservers);
123 /* This tries dirservers which we believe to be down, but ultimately, that's
124 * harmless, and we may as well err on the side of getting things uploaded.
126 SMARTLIST_FOREACH(dirservers, trusted_dir_server_t *, ds,
128 /* Pay attention to fascistfirewall when we're uploading a
129 * router descriptor, but not when uploading a service
130 * descriptor -- those use Tor. */
131 if (get_options()->FascistFirewall && purpose == DIR_PURPOSE_UPLOAD_DIR &&
132 !get_options()->HttpProxy) {
133 if (!smartlist_string_num_isin(get_options()->FirewallPorts, ds->dir_port))
134 continue;
136 directory_initiate_command_trusted_dir(ds, purpose, NULL,
137 payload, payload_len);
141 /** Start a connection to a random running directory server, using
142 * connection purpose 'purpose' requesting 'resource'. The purpose
143 * should be one of 'DIR_PURPOSE_FETCH_DIR',
144 * 'DIR_PURPOSE_FETCH_RENDDESC', 'DIR_PURPOSE_FETCH_RUNNING_LIST.'
145 * If <b>retry_if_no_servers</b>, then if all the possible servers seem
146 * down, mark them up and try again.
148 void
149 directory_get_from_dirserver(uint8_t purpose, const char *resource,
150 int retry_if_no_servers)
152 routerinfo_t *r = NULL;
153 trusted_dir_server_t *ds = NULL;
154 int fascistfirewall = get_options()->FascistFirewall;
155 int directconn = purpose == DIR_PURPOSE_FETCH_DIR ||
156 purpose == DIR_PURPOSE_FETCH_RUNNING_LIST;
157 int fetch_fresh_first = advertised_server_mode();
159 if (directconn) {
160 if (fetch_fresh_first) {
161 /* only ask authdirservers, and don't ask myself */
162 ds = router_pick_trusteddirserver(1, fascistfirewall,
163 retry_if_no_servers);
165 if (!ds) {
166 /* anybody with a non-zero dirport will do */
167 r = router_pick_directory_server(1, fascistfirewall,
168 purpose==DIR_PURPOSE_FETCH_RUNNING_LIST,
169 retry_if_no_servers);
170 if (!r) {
171 log_fn(LOG_INFO, "No router found for %s; falling back to dirserver list",
172 purpose == DIR_PURPOSE_FETCH_RUNNING_LIST
173 ? "status list" : "directory");
174 ds = router_pick_trusteddirserver(1, fascistfirewall,
175 retry_if_no_servers);
178 } else { // (purpose == DIR_PURPOSE_FETCH_RENDDESC)
179 /* only ask authdirservers, any of them will do */
180 /* Never use fascistfirewall; we're going via Tor. */
181 ds = router_pick_trusteddirserver(0, 0, retry_if_no_servers);
184 if (r)
185 directory_initiate_command_router(r, purpose, resource, NULL, 0);
186 else if (ds)
187 directory_initiate_command_trusted_dir(ds, purpose, resource, NULL, 0);
188 else {
189 log_fn(LOG_NOTICE,"No running dirservers known. Not trying. (purpose %d)",
190 purpose);
191 if (directconn) {
192 /* remember we tried them all and failed. */
193 directory_all_unreachable(time(NULL));
198 /** Launch a new connection to the directory server <b>router</b> to upload or
199 * download a service or rendezvous descriptor. <b>purpose</b> determines what
200 * kind of directory connection we're launching, and must be one of
201 * DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC}.
203 * When uploading, <b>payload</b> and <b>payload_len</b> determine the content
204 * of the HTTP post. Otherwise, <b>payload</b> should be NULL.
206 * When fetching a rendezvous descriptor, <b>resource</b> is the service ID we
207 * want to fetch.
209 static void
210 directory_initiate_command_router(routerinfo_t *router, uint8_t purpose,
211 const char *resource,
212 const char *payload, size_t payload_len)
214 directory_initiate_command(router->address, router->addr, router->dir_port,
215 router->platform, router->identity_digest,
216 purpose, resource, payload, payload_len);
219 /** As directory_initiate_command_router, but send the command to a trusted
220 * directory server <b>dirserv</b>. **/
221 static void
222 directory_initiate_command_trusted_dir(trusted_dir_server_t *dirserv,
223 uint8_t purpose, const char *resource,
224 const char *payload, size_t payload_len)
226 directory_initiate_command(dirserv->address, dirserv->addr,dirserv->dir_port,
227 NULL, dirserv->digest, purpose, resource, payload, payload_len);
230 /** Called when we are unable to complete our connection to a
231 * directory server: Mark the router as down and try again if possible.
233 void
234 connection_dir_connect_failed(connection_t *conn)
236 router_mark_as_down(conn->identity_digest); /* don't try him again */
237 if (conn->purpose == DIR_PURPOSE_FETCH_DIR ||
238 conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
239 log_fn(LOG_INFO, "Giving up on directory server at '%s'; retrying",
240 conn->address);
241 directory_get_from_dirserver(conn->purpose, NULL,
242 0 /* don't retry_if_no_servers */);
246 /** Helper for directory_initiate_command_(router|trusted_dir): send the
247 * command to a server whose address is <b>address</b>, whose IP is
248 * <b>addr</b>, whose directory port is <b>dir_port</b>, whose tor version is
249 * <b>platform</b>, and whose identity key digest is <b>digest</b>. The
250 * <b>platform</b> argument is optional; the others are required. */
251 static void
252 directory_initiate_command(const char *address, uint32_t addr,
253 uint16_t dir_port, const char *platform,
254 const char *digest, uint8_t purpose,
255 const char *resource,
256 const char *payload, size_t payload_len)
258 connection_t *conn;
260 tor_assert(address);
261 tor_assert(addr);
262 tor_assert(dir_port);
263 tor_assert(digest);
265 switch (purpose) {
266 case DIR_PURPOSE_FETCH_DIR:
267 log_fn(LOG_DEBUG,"initiating directory fetch");
268 break;
269 case DIR_PURPOSE_FETCH_RENDDESC:
270 log_fn(LOG_DEBUG,"initiating hidden-service descriptor fetch");
271 break;
272 case DIR_PURPOSE_UPLOAD_DIR:
273 log_fn(LOG_DEBUG,"initiating server descriptor upload");
274 break;
275 case DIR_PURPOSE_UPLOAD_RENDDESC:
276 log_fn(LOG_DEBUG,"initiating hidden-service descriptor upload");
277 break;
278 case DIR_PURPOSE_FETCH_RUNNING_LIST:
279 log_fn(LOG_DEBUG,"initiating running-routers fetch");
280 break;
281 default:
282 log_fn(LOG_ERR, "Unrecognized directory connection purpose.");
283 tor_assert(0);
286 conn = connection_new(CONN_TYPE_DIR);
288 /* set up conn so it's got all the data we need to remember */
289 conn->addr = addr;
290 conn->port = dir_port;
292 if (get_options()->HttpProxy) {
293 addr = get_options()->HttpProxyAddr;
294 dir_port = get_options()->HttpProxyPort;
297 conn->address = tor_strdup(address);
298 /* conn->nickname = tor_strdup(router->nickname); */
299 /* tor_assert(router->identity_pkey); */
300 /* conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey); */
301 /* crypto_pk_get_digest(conn->identity_pkey, conn->identity_digest); */
302 memcpy(conn->identity_digest, digest, DIGEST_LEN);
304 conn->purpose = purpose;
306 /* give it an initial state */
307 conn->state = DIR_CONN_STATE_CONNECTING;
309 if (purpose == DIR_PURPOSE_FETCH_DIR ||
310 purpose == DIR_PURPOSE_UPLOAD_DIR ||
311 purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
312 /* then we want to connect directly */
313 switch (connection_connect(conn, conn->address, addr, dir_port)) {
314 case -1:
315 connection_dir_connect_failed(conn);
316 connection_free(conn);
317 return;
318 case 1:
319 conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
320 /* fall through */
321 case 0:
322 /* queue the command on the outbuf */
323 directory_send_command(conn, platform, purpose, resource,
324 payload, payload_len);
325 connection_watch_events(conn, EV_READ | EV_WRITE);
326 /* writable indicates finish, readable indicates broken link,
327 error indicates broken link in windowsland. */
329 } else { /* we want to connect via tor */
330 /* make an AP connection
331 * populate it and add it at the right state
332 * socketpair and hook up both sides
334 conn->s = connection_ap_make_bridge(conn->address, conn->port);
335 if (conn->s < 0) {
336 log_fn(LOG_WARN,"Making AP bridge to dirserver failed.");
337 connection_mark_for_close(conn);
338 return;
341 conn->state = DIR_CONN_STATE_CLIENT_SENDING;
342 connection_add(conn);
343 /* queue the command on the outbuf */
344 directory_send_command(conn, platform, purpose, resource,
345 payload, payload_len);
346 connection_watch_events(conn, EV_READ | EV_WRITE);
350 /** Queue an appropriate HTTP command on conn-\>outbuf. The other args
351 * are as in directory_initiate_command.
353 static void
354 directory_send_command(connection_t *conn, const char *platform,
355 int purpose, const char *resource,
356 const char *payload, size_t payload_len) {
357 char tmp[8192];
358 char proxystring[128];
359 char hoststring[128];
360 char url[128];
361 int use_newer = 0;
362 const char *httpcommand = NULL;
364 tor_assert(conn);
365 tor_assert(conn->type == CONN_TYPE_DIR);
367 /* If we don't know the platform, assume it's up-to-date. */
368 use_newer = platform ? tor_version_as_new_as(platform, "0.0.9pre1"):1;
370 if (conn->port == 80) {
371 strlcpy(hoststring, conn->address, sizeof(hoststring));
372 } else {
373 tor_snprintf(hoststring, sizeof(hoststring),"%s:%d",conn->address, conn->port);
375 if (get_options()->HttpProxy) {
376 tor_snprintf(proxystring, sizeof(proxystring),"http://%s", hoststring);
377 } else {
378 proxystring[0] = 0;
381 switch (purpose) {
382 case DIR_PURPOSE_FETCH_DIR:
383 tor_assert(!resource);
384 tor_assert(!payload);
385 log_fn(LOG_DEBUG, "Asking for %scompressed directory from server running %s",
386 use_newer?"":"un", platform?platform:"<unknown version>");
387 httpcommand = "GET";
388 strlcpy(url, use_newer ? "/tor/dir.z" : "/", sizeof(url));
389 break;
390 case DIR_PURPOSE_FETCH_RUNNING_LIST:
391 tor_assert(!resource);
392 tor_assert(!payload);
393 httpcommand = "GET";
394 strlcpy(url, use_newer ? "/tor/running-routers" : "/running-routers", sizeof(url));
395 break;
396 case DIR_PURPOSE_UPLOAD_DIR:
397 tor_assert(!resource);
398 tor_assert(payload);
399 httpcommand = "POST";
400 strlcpy(url, use_newer ? "/tor/" : "/", sizeof(url));
401 break;
402 case DIR_PURPOSE_FETCH_RENDDESC:
403 tor_assert(resource);
404 tor_assert(!payload);
406 /* this must be true or we wouldn't be doing the lookup */
407 tor_assert(strlen(resource) <= REND_SERVICE_ID_LEN);
408 /* This breaks the function abstraction. */
409 strlcpy(conn->rend_query, resource, sizeof(conn->rend_query));
411 httpcommand = "GET";
412 tor_snprintf(url, sizeof(url), "%s/rendezvous/%s", use_newer ? "/tor" : "", resource);
414 break;
415 case DIR_PURPOSE_UPLOAD_RENDDESC:
416 tor_assert(!resource);
417 tor_assert(payload);
418 httpcommand = "POST";
419 tor_snprintf(url, sizeof(url), "%s/rendezvous/publish", use_newer ? "/tor" : "");
420 break;
423 tor_snprintf(tmp, sizeof(tmp), "%s %s%s HTTP/1.0\r\nContent-Length: %lu\r\nHost: %s\r\n\r\n",
424 httpcommand,
425 proxystring,
426 url,
427 payload ? (unsigned long)payload_len : 0,
428 hoststring);
429 connection_write_to_buf(tmp, strlen(tmp), conn);
431 if (payload) {
432 /* then send the payload afterwards too */
433 connection_write_to_buf(payload, payload_len, conn);
437 /** Parse an HTTP request string <b>headers</b> of the form
438 * "\%s [http[s]://]\%s HTTP/1..."
439 * If it's well-formed, strdup the second \%s into *<b>url</b>, and
440 * null-terminate it. If the url doesn't start with "/tor/", rewrite it
441 * so it does. Return 0.
442 * Otherwise, return -1.
444 static int
445 parse_http_url(char *headers, char **url)
447 char *s, *start, *tmp;
449 s = (char *)eat_whitespace_no_nl(headers);
450 if (!*s) return -1;
451 s = (char *)find_whitespace(s); /* get past GET/POST */
452 if (!*s) return -1;
453 s = (char *)eat_whitespace_no_nl(s);
454 if (!*s) return -1;
455 start = s; /* this is it, assuming it's valid */
456 s = (char *)find_whitespace(start);
457 if (!*s) return -1;
459 /* tolerate the http[s] proxy style of putting the hostname in the url */
460 if (s-start >= 4 && !strcmpstart(start,"http")) {
461 tmp = start + 4;
462 if (*tmp == 's')
463 tmp++;
464 if (s-tmp >= 3 && !strcmpstart(tmp,"://")) {
465 tmp = strchr(tmp+3, '/');
466 if (tmp && tmp < s) {
467 log_fn(LOG_DEBUG,"Skipping over 'http[s]://hostname' string");
468 start = tmp;
473 if (s-start < 5 || strcmpstart(start,"/tor/")) { /* need to rewrite it */
474 *url = tor_malloc(s - start + 5);
475 strlcpy(*url,"/tor", s-start+5);
476 strlcat((*url)+4, start, s-start+1);
477 } else {
478 *url = tor_strndup(start, s-start);
480 return 0;
483 /** Parse an HTTP response string <b>headers</b> of the form
484 * "HTTP/1.\%d \%d\%s\r\n...".
485 * If it's well-formed, assign *<b>code</b> and return 0.
486 * If <b>date</b> is provided, set *date to the Date header in the
487 * http headers, or 0 if no such header is found. If <b>compression</b>
488 * is provided, set *<b>compression</b> to the compression method given
489 * in the Content-Encoding header, or 0 if no such header is found, or -1
490 * if the value of the header is not recognized.
491 * Otherwise, return -1.
493 static int
494 parse_http_response(const char *headers, int *code, time_t *date,
495 int *compression)
497 int n1, n2;
498 char datestr[RFC1123_TIME_LEN+1];
499 smartlist_t *parsed_headers;
500 tor_assert(headers);
501 tor_assert(code);
503 while (TOR_ISSPACE(*headers)) headers++; /* tolerate leading whitespace */
505 if (sscanf(headers, "HTTP/1.%d %d", &n1, &n2) < 2 ||
506 (n1 != 0 && n1 != 1) ||
507 (n2 < 100 || n2 >= 600)) {
508 log_fn(LOG_WARN,"Failed to parse header '%s'",headers);
509 return -1;
511 *code = n2;
513 parsed_headers = smartlist_create();
514 smartlist_split_string(parsed_headers, headers, "\n",
515 SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
516 if (date) {
517 *date = 0;
518 SMARTLIST_FOREACH(parsed_headers, const char *, s,
519 if (!strcmpstart(s, "Date: ")) {
520 strlcpy(datestr, s+6, sizeof(datestr));
521 /* This will do nothing on failure, so we don't need to check
522 the result. We shouldn't warn, since there are many other valid
523 date formats besides the one we use. */
524 parse_rfc1123_time(datestr, date);
525 break;
528 if (compression) {
529 const char *enc = NULL;
530 SMARTLIST_FOREACH(parsed_headers, const char *, s,
531 if (!strcmpstart(s, "Content-Encoding: ")) {
532 enc = s+18; break;
534 if (!enc || !strcmp(enc, "identity")) {
535 *compression = 0;
536 } else if (!strcmp(enc, "deflate") || !strcmp(enc, "x-deflate")) {
537 *compression = ZLIB_METHOD;
538 } else if (!strcmp(enc, "gzip") || !strcmp(enc, "x-gzip")) {
539 *compression = GZIP_METHOD;
540 } else {
541 log_fn(LOG_INFO, "Unrecognized content encoding: '%s'", enc);
542 *compression = -1;
545 SMARTLIST_FOREACH(parsed_headers, char *, s, tor_free(s));
546 smartlist_free(parsed_headers);
548 return 0;
551 /** Return true iff <b>body</b> doesn't start with a plausible router or
552 * running-list or directory opening. This is a sign of possible compression.
554 static int
555 body_is_plausible(const char *body, size_t len, int purpose)
557 int i;
558 if (len == 0)
559 return 1; /* empty bodies don't need decompression */
560 if (len < 32)
561 return 0;
562 if (purpose != DIR_PURPOSE_FETCH_RENDDESC) {
563 if (!strcmpstart(body,"router") ||
564 !strcmpstart(body,"signed-directory") ||
565 !strcmpstart(body,"network-status") ||
566 !strcmpstart(body,"running-routers"))
567 return 1;
568 for (i=0;i<32;++i) {
569 if (!TOR_ISPRINT(body[i]) && !TOR_ISSPACE(body[i]))
570 return 0;
572 return 1;
573 } else {
574 return 1;
578 /** We are a client, and we've finished reading the server's
579 * response. Parse and it and act appropriately.
581 * Return -1 if an error has occurred, or 0 normally. The caller
582 * will take care of marking the connection for close.
584 static int
585 connection_dir_client_reached_eof(connection_t *conn)
587 char *body;
588 char *headers;
589 size_t body_len=0;
590 int status_code;
591 time_t now, date_header=0;
592 int delta;
593 int compression;
594 int plausible;
595 int skewed=0;
597 switch (fetch_from_buf_http(conn->inbuf,
598 &headers, MAX_HEADERS_SIZE,
599 &body, &body_len, MAX_DIR_SIZE)) {
600 case -1: /* overflow */
601 log_fn(LOG_WARN,"'fetch' response too large (server '%s'). Failing.", conn->address);
602 return -1;
603 case 0:
604 log_fn(LOG_INFO,"'fetch' response not all here, but we're at eof. Closing.");
605 return -1;
606 /* case 1, fall through */
609 if (parse_http_response(headers, &status_code, &date_header,
610 &compression) < 0) {
611 log_fn(LOG_WARN,"Unparseable headers (server '%s'). Closing.", conn->address);
612 tor_free(body); tor_free(headers);
613 return -1;
615 if (date_header > 0) {
616 now = time(NULL);
617 delta = now-date_header;
618 if (abs(delta)>ALLOW_DIRECTORY_TIME_SKEW) {
619 routerinfo_t *router = router_get_by_digest(conn->identity_digest);
620 log_fn((router && router->is_verified) ? LOG_WARN : LOG_INFO,
621 "Received directory with skewed time (server '%s'): we are %d minutes %s, or the directory is %d minutes %s.",
622 conn->address,
623 abs(delta)/60, delta>0 ? "ahead" : "behind",
624 abs(delta)/60, delta>0 ? "behind" : "ahead");
625 skewed = 1; /* don't check the recommended-versions line */
626 } else {
627 log_fn(LOG_INFO, "Time on received directory is within tolerance; we are %d seconds skewed. (That's okay.)", delta);
631 plausible = body_is_plausible(body, body_len, conn->purpose);
632 if (compression || !plausible) {
633 char *new_body = NULL;
634 size_t new_len = 0;
635 int guessed = detect_compression_method(body, body_len);
636 if (compression <= 0 || guessed != compression) {
637 /* Tell the user if we don't believe what we're told about compression.*/
638 const char *description1, *description2;
639 if (compression == ZLIB_METHOD)
640 description1 = "as deflated";
641 else if (compression == GZIP_METHOD)
642 description1 = "as gzipped";
643 else if (compression == 0)
644 description1 = "as uncompressed";
645 else
646 description1 = "with an unknown Content-Encoding";
647 if (guessed == ZLIB_METHOD)
648 description2 = "deflated";
649 else if (guessed == GZIP_METHOD)
650 description2 = "gzipped";
651 else if (!plausible)
652 description2 = "confusing binary junk";
653 else
654 description2 = "uncompressed";
656 log_fn(LOG_INFO, "HTTP body from server '%s' was labeled %s,"
657 "but it seems to be %s.%s",
658 conn->address, description1, description2,
659 (compression>0 && guessed>0)?" Trying both.":"");
661 /* Try declared compression first if we can. */
662 if (compression > 0)
663 tor_gzip_uncompress(&new_body, &new_len, body, body_len, compression);
664 /* Okay, if that didn't work, and we think that it was compressed
665 * differently, try that. */
666 if (!new_body && guessed > 0 && compression != guessed)
667 tor_gzip_uncompress(&new_body, &new_len, body, body_len, guessed);
668 /* If we're pretty sure that we have a compressed directory, and
669 * we didn't manage to uncompress it, then warn and bail. */
670 if (!plausible && !new_body) {
671 log_fn(LOG_WARN, "Unable to decompress HTTP body (server '%s').", conn->address);
672 tor_free(body); tor_free(headers);
673 return -1;
675 if (new_body) {
676 tor_free(body);
677 body = new_body;
678 body_len = new_len;
682 if (conn->purpose == DIR_PURPOSE_FETCH_DIR) {
683 /* fetch/process the directory to learn about new routers. */
684 log_fn(LOG_INFO,"Received directory (size %d) from server '%s'",
685 (int)body_len, conn->address);
686 if (status_code == 503 || body_len == 0) {
687 log_fn(LOG_INFO,"Empty directory. Ignoring.");
688 tor_free(body); tor_free(headers);
689 return 0;
691 if (status_code != 200) {
692 log_fn(LOG_WARN,"Received http status code %d from server '%s'. Failing.",
693 status_code, conn->address);
694 tor_free(body); tor_free(headers);
695 return -1;
697 if (router_load_routerlist_from_directory(body, NULL, !skewed, 0) < 0) {
698 log_fn(LOG_NOTICE,"I failed to parse the directory I fetched from %s:%d. Ignoring.", conn->address, conn->port);
699 } else {
700 log_fn(LOG_INFO,"updated routers.");
702 directory_has_arrived(time(NULL)); /* do things we've been waiting to do */
705 if (conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
706 running_routers_t *rrs;
707 routerlist_t *rl;
708 /* just update our list of running routers, if this list is new info */
709 log_fn(LOG_INFO,"Received running-routers list (size %d)", (int)body_len);
710 if (status_code != 200) {
711 log_fn(LOG_WARN,"Received http status code %d from server '%s'. Failing.",
712 status_code, conn->address);
713 tor_free(body); tor_free(headers);
714 return -1;
716 if (!(rrs = router_parse_runningrouters(body, 1))) {
717 log_fn(LOG_WARN, "Can't parse runningrouters list (server '%s')", conn->address);
718 tor_free(body); tor_free(headers);
719 return -1;
721 router_get_routerlist(&rl);
722 if (rl)
723 routerlist_update_from_runningrouters(rl,rrs);
724 running_routers_free(rrs);
727 if (conn->purpose == DIR_PURPOSE_UPLOAD_DIR) {
728 switch (status_code) {
729 case 200:
730 log_fn(LOG_INFO,"eof (status 200) after uploading server descriptor: finished.");
731 break;
732 case 400:
733 log_fn(LOG_WARN,"http status 400 (bad request) response from dirserver '%s'. Malformed server descriptor?", conn->address);
734 break;
735 case 403:
736 log_fn(LOG_WARN,"http status 403 (unapproved server) response from dirserver '%s'. 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.html#server.", conn->address);
737 break;
738 default:
739 log_fn(LOG_WARN,"http status %d response unrecognized (server '%s').", status_code, conn->address);
740 break;
744 if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC) {
745 log_fn(LOG_INFO,"Received rendezvous descriptor (size %d, status code %d)",
746 (int)body_len, status_code);
747 switch (status_code) {
748 case 200:
749 if (rend_cache_store(body, body_len) < 0) {
750 log_fn(LOG_WARN,"Failed to store rendezvous descriptor.");
751 /* alice's ap_stream will notice when connection_mark_for_close
752 * cleans it up */
753 } else {
754 /* success. notify pending connections about this. */
755 conn->purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
756 rend_client_desc_here(conn->rend_query);
758 break;
759 case 404:
760 /* not there. pending connections will be notified when
761 * connection_mark_for_close cleans it up. */
762 break;
763 case 400:
764 log_fn(LOG_WARN,"http status 400 (bad request). Dirserver didn't like our rendezvous query?");
765 break;
769 if (conn->purpose == DIR_PURPOSE_UPLOAD_RENDDESC) {
770 switch (status_code) {
771 case 200:
772 log_fn(LOG_INFO,"eof (status 200) after uploading rendezvous descriptor: finished.");
773 break;
774 case 400:
775 log_fn(LOG_WARN,"http status 400 (bad request) response from dirserver. Malformed rendezvous descriptor?");
776 break;
777 default:
778 log_fn(LOG_WARN,"http status %d response unrecognized.", status_code);
779 break;
782 tor_free(body); tor_free(headers);
783 return 0;
786 int connection_dir_reached_eof(connection_t *conn) {
787 int retval;
788 if (conn->state != DIR_CONN_STATE_CLIENT_READING) {
789 log_fn(LOG_INFO,"conn reached eof, not reading. Closing.");
790 connection_close_immediate(conn); /* it was an error; give up on flushing */
791 connection_mark_for_close(conn);
792 return -1;
795 retval = connection_dir_client_reached_eof(conn);
796 connection_mark_for_close(conn);
797 return retval;
800 /** Read handler for directory connections. (That's connections <em>to</em>
801 * directory servers and connections <em>at</em> directory servers.)
803 int connection_dir_process_inbuf(connection_t *conn) {
805 tor_assert(conn);
806 tor_assert(conn->type == CONN_TYPE_DIR);
808 /* Directory clients write, then read data until they receive EOF;
809 * directory servers read data until they get an HTTP command, then
810 * write their response (when it's finished flushing, they mark for
811 * close).
814 /* If we're on the dirserver side, look for a command. */
815 if (conn->state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
816 if (directory_handle_command(conn) < 0) {
817 connection_mark_for_close(conn);
818 return -1;
820 return 0;
823 /* XXX for READ states, might want to make sure inbuf isn't too big */
825 log_fn(LOG_DEBUG,"Got data, not eof. Leaving on inbuf.");
826 return 0;
829 /** Create an http response for the client <b>conn</b> out of
830 * <b>status</b> and <b>reason_phrase</b>. Write it to <b>conn</b>.
832 static void
833 write_http_status_line(connection_t *conn, int status,
834 const char *reason_phrase)
836 char buf[256];
837 if (tor_snprintf(buf, sizeof(buf), "HTTP/1.0 %d %s\r\n\r\n",
838 status, reason_phrase) < 0) {
839 log_fn(LOG_WARN,"Bug: status line too long.");
840 return;
842 connection_write_to_buf(buf, strlen(buf), conn);
845 /** Helper function: called when a dirserver gets a complete HTTP GET
846 * request. Look for a request for a directory or for a rendezvous
847 * service descriptor. On finding one, write a response into
848 * conn-\>outbuf. If the request is unrecognized, send a 400.
849 * Always return 0. */
850 static int
851 directory_handle_command_get(connection_t *conn, char *headers,
852 char *body, size_t body_len)
854 size_t dlen;
855 const char *cp;
856 char *url;
857 char tmp[8192];
858 char date[RFC1123_TIME_LEN+1];
860 log_fn(LOG_DEBUG,"Received GET command.");
862 conn->state = DIR_CONN_STATE_SERVER_WRITING;
864 if (parse_http_url(headers, &url) < 0) {
865 write_http_status_line(conn, 400, "Bad request");
866 return 0;
868 log_fn(LOG_INFO,"rewritten url as '%s'.", url);
870 if (!strcmp(url,"/tor/") || !strcmp(url,"/tor/dir.z")) { /* directory fetch */
871 int deflated = !strcmp(url,"/tor/dir.z");
872 dlen = dirserv_get_directory(&cp, deflated);
874 tor_free(url);
876 if (dlen == 0) {
877 log_fn(LOG_NOTICE,"Client asked for the mirrored directory, but we don't have a good one yet. Sending 503 Dir not available.");
878 write_http_status_line(conn, 503, "Directory unavailable");
879 /* try to get a new one now */
880 if (!connection_get_by_type_purpose(CONN_TYPE_DIR, DIR_PURPOSE_FETCH_DIR))
881 directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 1);
882 return 0;
885 log_fn(LOG_DEBUG,"Dumping %sdirectory to client.",
886 deflated?"deflated ":"");
887 format_rfc1123_time(date, time(NULL));
888 tor_snprintf(tmp, sizeof(tmp), "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\nContent-Type: text/plain\r\nContent-Encoding: %s\r\n\r\n",
889 date,
890 (int)dlen,
891 deflated?"deflate":"identity");
892 connection_write_to_buf(tmp, strlen(tmp), conn);
893 connection_write_to_buf(cp, dlen, conn);
894 return 0;
897 if (!strcmp(url,"/tor/running-routers") ||
898 !strcmp(url,"/tor/running-routers.z")) { /* running-routers fetch */
899 int deflated = !strcmp(url,"/tor/dir.z");
900 tor_free(url);
901 dlen = dirserv_get_runningrouters(&cp, deflated);
902 if (!dlen) { /* we failed to create/cache cp */
903 write_http_status_line(conn, 503, "Directory unavailable");
904 /* try to get a new one now */
905 if (!connection_get_by_type_purpose(CONN_TYPE_DIR,
906 DIR_PURPOSE_FETCH_RUNNING_LIST))
907 directory_get_from_dirserver(DIR_PURPOSE_FETCH_RUNNING_LIST, NULL, 1);
908 return 0;
911 format_rfc1123_time(date, time(NULL));
912 tor_snprintf(tmp, sizeof(tmp), "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\nContent-Type: text/plain\r\nContent-Encoding: %s\r\n\r\n",
913 date,
914 (int)dlen,
915 deflated?"deflate":"identity");
916 connection_write_to_buf(tmp, strlen(tmp), conn);
917 connection_write_to_buf(cp, strlen(cp), conn);
918 return 0;
921 if (!strcmpstart(url,"/tor/rendezvous/")) {
922 /* rendezvous descriptor fetch */
923 const char *descp;
924 size_t desc_len;
926 if (!authdir_mode(get_options())) {
927 /* We don't hand out rend descs. In fact, it could be a security
928 * risk, since rend_cache_lookup_desc() below would provide it
929 * if we're gone to the site recently, and 404 if we haven't.
931 * Reject. */
932 write_http_status_line(conn, 400, "Nonauthoritative directory does not not store rendezvous descriptors.");
933 tor_free(url);
934 return 0;
936 switch (rend_cache_lookup_desc(url+strlen("/tor/rendezvous/"), &descp, &desc_len)) {
937 case 1: /* valid */
938 format_rfc1123_time(date, time(NULL));
939 tor_snprintf(tmp, sizeof(tmp), "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\nContent-Type: application/octet-stream\r\n\r\n",
940 date,
941 (int)desc_len); /* can't include descp here, because it's got nuls */
942 connection_write_to_buf(tmp, strlen(tmp), conn);
943 connection_write_to_buf(descp, desc_len, conn);
944 break;
945 case 0: /* well-formed but not present */
946 write_http_status_line(conn, 404, "Not found");
947 break;
948 case -1: /* not well-formed */
949 write_http_status_line(conn, 400, "Bad request");
950 break;
952 tor_free(url);
953 return 0;
956 /* we didn't recognize the url */
957 write_http_status_line(conn, 404, "Not found");
958 tor_free(url);
959 return 0;
962 /** Helper function: called when a dirserver gets a complete HTTP POST
963 * request. Look for an uploaded server descriptor or rendezvous
964 * service descriptor. On finding one, process it and write a
965 * response into conn-\>outbuf. If the request is unrecognized, send a
966 * 400. Always return 0. */
967 static int
968 directory_handle_command_post(connection_t *conn, char *headers,
969 char *body, size_t body_len)
971 const char *cp;
972 char *url;
974 log_fn(LOG_DEBUG,"Received POST command.");
976 conn->state = DIR_CONN_STATE_SERVER_WRITING;
978 if (!authdir_mode(get_options())) {
979 /* we just provide cached directories; we don't want to
980 * receive anything. */
981 write_http_status_line(conn, 400, "Nonauthoritative directory does not not store server descriptors.");
982 return 0;
985 if (parse_http_url(headers, &url) < 0) {
986 write_http_status_line(conn, 400, "Bad request");
987 return 0;
989 log_fn(LOG_INFO,"rewritten url as '%s'.", url);
991 if (!strcmp(url,"/tor/")) { /* server descriptor post */
992 const char *msg;
993 cp = body;
994 switch (dirserv_add_descriptor(&cp, &msg)) {
995 case -2:
996 case -1:
997 /* malformed descriptor, or something wrong */
998 write_http_status_line(conn, 400, msg?msg:"Malformed or unacceptable server descriptor");
999 break;
1000 case 0:
1001 /* descriptor was well-formed but server has not been approved */
1002 write_http_status_line(conn, 200, msg?msg:"Unverified server descriptor accepted");
1003 break;
1004 case 1:
1005 dirserv_get_directory(&cp, 0); /* rebuild and write to disk */
1006 write_http_status_line(conn, 200, msg?msg:"Verified server descriptor accepted");
1007 break;
1009 tor_free(url);
1010 return 0;
1013 if (!strcmpstart(url,"/tor/rendezvous/publish")) {
1014 /* rendezvous descriptor post */
1015 if (rend_cache_store(body, body_len) < 0)
1016 write_http_status_line(conn, 400, "Invalid service descriptor rejected");
1017 else
1018 write_http_status_line(conn, 200, "Service descriptor stored");
1019 tor_free(url);
1020 return 0;
1023 /* we didn't recognize the url */
1024 write_http_status_line(conn, 404, "Not found");
1025 tor_free(url);
1026 return 0;
1029 /** Called when a dirserver receives data on a directory connection;
1030 * looks for an HTTP request. If the request is complete, remove it
1031 * from the inbuf, try to process it; otherwise, leave it on the
1032 * buffer. Return a 0 on success, or -1 on error.
1034 static int directory_handle_command(connection_t *conn) {
1035 char *headers=NULL, *body=NULL;
1036 size_t body_len=0;
1037 int r;
1039 tor_assert(conn);
1040 tor_assert(conn->type == CONN_TYPE_DIR);
1042 switch (fetch_from_buf_http(conn->inbuf,
1043 &headers, MAX_HEADERS_SIZE,
1044 &body, &body_len, MAX_BODY_SIZE)) {
1045 case -1: /* overflow */
1046 log_fn(LOG_WARN,"Invalid input. Closing.");
1047 return -1;
1048 case 0:
1049 log_fn(LOG_DEBUG,"command not all here yet.");
1050 return 0;
1051 /* case 1, fall through */
1054 log_fn(LOG_DEBUG,"headers '%s', body '%s'.", headers, body);
1056 if (!strncasecmp(headers,"GET",3))
1057 r = directory_handle_command_get(conn, headers, body, body_len);
1058 else if (!strncasecmp(headers,"POST",4))
1059 r = directory_handle_command_post(conn, headers, body, body_len);
1060 else {
1061 log_fn(LOG_WARN,"Got headers '%s' with unknown command. Closing.", headers);
1062 r = -1;
1065 tor_free(headers); tor_free(body);
1066 return r;
1069 /** Write handler for directory connections; called when all data has
1070 * been flushed. Close the connection or wait for a response as
1071 * appropriate.
1073 int connection_dir_finished_flushing(connection_t *conn) {
1075 tor_assert(conn);
1076 tor_assert(conn->type == CONN_TYPE_DIR);
1078 switch (conn->state) {
1079 case DIR_CONN_STATE_CLIENT_SENDING:
1080 log_fn(LOG_DEBUG,"client finished sending command.");
1081 conn->state = DIR_CONN_STATE_CLIENT_READING;
1082 connection_stop_writing(conn);
1083 return 0;
1084 case DIR_CONN_STATE_SERVER_WRITING:
1085 log_fn(LOG_INFO,"Finished writing server response. Closing.");
1086 connection_mark_for_close(conn);
1087 return 0;
1088 default:
1089 log_fn(LOG_WARN,"Bug: called in unexpected state %d.", conn->state);
1090 #ifdef TOR_FRAGILE
1091 tor_assert(0);
1092 #endif
1093 return -1;
1095 return 0;
1098 /** Connected handler for directory connections: begin sending data to the
1099 * server */
1100 int connection_dir_finished_connecting(connection_t *conn)
1102 tor_assert(conn);
1103 tor_assert(conn->type == CONN_TYPE_DIR);
1104 tor_assert(conn->state == DIR_CONN_STATE_CONNECTING);
1106 log_fn(LOG_INFO,"Dir connection to router %s:%u established.",
1107 conn->address,conn->port);
1109 conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
1110 return 0;