clean up a few more log entries
[tor.git] / src / or / directory.c
blob32ed70ab0d88b009682528648881b4b11556351f
1 /* Copyright 2001-2004 Roger Dingledine.
2 * Copyright 2004-2005 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_trusted_dir(trusted_dir_server_t *dirserv,
33 uint8_t purpose, int private_connection,
34 const char *resource,
35 const char *payload, size_t payload_len);
36 static void
37 directory_initiate_command(const char *address, uint32_t addr, uint16_t port,
38 const char *platform,
39 const char *digest, uint8_t purpose,
40 int private_connection, const char *resource,
41 const char *payload, size_t payload_len);
43 static void
44 directory_send_command(connection_t *conn, const char *platform,
45 int purpose, const char *resource,
46 const char *payload, size_t payload_len);
47 static int directory_handle_command(connection_t *conn);
48 static int body_is_plausible(const char *body, size_t body_len, int purpose);
49 static int purpose_is_private(uint8_t purpose);
51 /********* START VARIABLES **********/
53 static addr_policy_t *dir_policy = NULL;
55 #if 0 /* commented out for now, since for now what clients send is
56 different from what servers want to receive */
57 /** URL for publishing rendezvous descriptors. */
58 char rend_publish_string[] = "/tor/rendezvous/publish";
59 /** Prefix for downloading rendezvous descriptors. */
60 char rend_fetch_url[] = "/tor/rendezvous/";
61 #endif
63 #define ALLOW_DIRECTORY_TIME_SKEW 30*60 /* 30 minutes */
65 /********* END VARIABLES ************/
67 /** Parse get_options()->DirPolicy, and put the processed version in
68 * &dir_policy. Ignore port specifiers.
70 void
71 parse_dir_policy(void)
73 addr_policy_t *n;
74 if (dir_policy) {
75 addr_policy_free(dir_policy);
76 dir_policy = NULL;
78 config_parse_addr_policy(get_options()->DirPolicy, &dir_policy);
79 /* ports aren't used. */
80 for (n=dir_policy; n; n = n->next) {
81 n->prt_min = 1;
82 n->prt_max = 65535;
86 void
87 free_dir_policy(void)
89 addr_policy_free(dir_policy);
90 dir_policy = NULL;
93 /** Return 1 if <b>addr</b> is permitted to connect to our dir port,
94 * based on <b>dir_policy</b>. Else return 0.
96 int dir_policy_permits_address(uint32_t addr)
98 int a;
100 if (!dir_policy) /* 'no dir policy' means 'accept' */
101 return 1;
102 a = router_compare_addr_to_addr_policy(addr, 1, dir_policy);
103 if (a==ADDR_POLICY_REJECTED)
104 return 0;
105 else if (a==ADDR_POLICY_ACCEPTED)
106 return 1;
107 log_fn(LOG_WARN, "Bug: got unexpected 'maybe' answer from dir policy");
108 return 0;
111 static int
112 purpose_is_private(uint8_t purpose) {
113 if (purpose == DIR_PURPOSE_FETCH_DIR ||
114 purpose == DIR_PURPOSE_UPLOAD_DIR ||
115 purpose == DIR_PURPOSE_FETCH_RUNNING_LIST)
116 return 0;
117 return 1;
120 /** Start a connection to every known directory server, using
121 * connection purpose 'purpose' and uploading the payload 'payload'
122 * (length 'payload_len'). The purpose should be one of
123 * 'DIR_PURPOSE_UPLOAD_DIR' or 'DIR_PURPOSE_UPLOAD_RENDDESC'.
125 void
126 directory_post_to_dirservers(uint8_t purpose, const char *payload,
127 size_t payload_len)
129 smartlist_t *dirservers;
131 router_get_trusted_dir_servers(&dirservers);
132 tor_assert(dirservers);
133 /* This tries dirservers which we believe to be down, but ultimately, that's
134 * harmless, and we may as well err on the side of getting things uploaded.
136 SMARTLIST_FOREACH(dirservers, trusted_dir_server_t *, ds,
138 /* Pay attention to fascistfirewall when we're uploading a
139 * router descriptor, but not when uploading a service
140 * descriptor -- those use Tor. */
141 if (get_options()->FascistFirewall && purpose == DIR_PURPOSE_UPLOAD_DIR &&
142 !get_options()->HttpProxy) {
143 if (!smartlist_string_num_isin(get_options()->FirewallPorts, ds->dir_port))
144 continue;
146 directory_initiate_command_trusted_dir(ds, purpose, purpose_is_private(purpose),
147 NULL, payload, payload_len);
151 /** Start a connection to a random running directory server, using
152 * connection purpose 'purpose' requesting 'resource'. The purpose
153 * should be one of 'DIR_PURPOSE_FETCH_DIR',
154 * 'DIR_PURPOSE_FETCH_RENDDESC', 'DIR_PURPOSE_FETCH_RUNNING_LIST.'
155 * If <b>retry_if_no_servers</b>, then if all the possible servers seem
156 * down, mark them up and try again.
158 void
159 directory_get_from_dirserver(uint8_t purpose, const char *resource,
160 int retry_if_no_servers)
162 routerinfo_t *r = NULL;
163 trusted_dir_server_t *ds = NULL;
164 int fascistfirewall = get_options()->FascistFirewall;
165 int directconn = purpose == DIR_PURPOSE_FETCH_DIR ||
166 purpose == DIR_PURPOSE_FETCH_RUNNING_LIST;
167 int fetch_fresh_first = advertised_server_mode();
168 int priv = purpose_is_private(purpose);
170 if (directconn) {
171 if (fetch_fresh_first) {
172 /* only ask authdirservers, and don't ask myself */
173 ds = router_pick_trusteddirserver(1, fascistfirewall,
174 retry_if_no_servers);
176 if (!ds) {
177 /* anybody with a non-zero dirport will do */
178 r = router_pick_directory_server(1, fascistfirewall,
179 purpose==DIR_PURPOSE_FETCH_RUNNING_LIST,
180 retry_if_no_servers);
181 if (!r) {
182 log_fn(LOG_INFO, "No router found for %s; falling back to dirserver list",
183 purpose == DIR_PURPOSE_FETCH_RUNNING_LIST
184 ? "status list" : "directory");
185 ds = router_pick_trusteddirserver(1, fascistfirewall,
186 retry_if_no_servers);
189 } else { // (purpose == DIR_PURPOSE_FETCH_RENDDESC)
190 /* only ask authdirservers, any of them will do */
191 /* Never use fascistfirewall; we're going via Tor. */
192 ds = router_pick_trusteddirserver(0, 0, retry_if_no_servers);
195 if (r)
196 directory_initiate_command_router(r, purpose, priv, resource, NULL, 0);
197 else if (ds)
198 directory_initiate_command_trusted_dir(ds, purpose, priv, resource, NULL, 0);
199 else {
200 log_fn(LOG_NOTICE,"No running dirservers known. Not trying. (purpose %d)",
201 purpose);
202 if (directconn) {
203 /* remember we tried them all and failed. */
204 directory_all_unreachable(time(NULL));
209 /** Launch a new connection to the directory server <b>router</b> to upload or
210 * download a service or rendezvous descriptor. <b>purpose</b> determines what
211 * kind of directory connection we're launching, and must be one of
212 * DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC}.
214 * When uploading, <b>payload</b> and <b>payload_len</b> determine the content
215 * of the HTTP post. Otherwise, <b>payload</b> should be NULL.
217 * When fetching a rendezvous descriptor, <b>resource</b> is the service ID we
218 * want to fetch.
220 void
221 directory_initiate_command_router(routerinfo_t *router, uint8_t purpose,
222 int private_connection, const char *resource,
223 const char *payload, size_t payload_len)
225 directory_initiate_command(router->address, router->addr, router->dir_port,
226 router->platform, router->identity_digest,
227 purpose, private_connection, resource,
228 payload, payload_len);
231 /** As directory_initiate_command_router, but send the command to a trusted
232 * directory server <b>dirserv</b>. **/
233 static void
234 directory_initiate_command_trusted_dir(trusted_dir_server_t *dirserv,
235 uint8_t purpose, int private_connection,
236 const char *resource,
237 const char *payload, size_t payload_len)
239 directory_initiate_command(dirserv->address, dirserv->addr,dirserv->dir_port,
240 NULL, dirserv->digest, purpose, private_connection, resource,
241 payload, payload_len);
244 /** Called when we are unable to complete our connection to a
245 * directory server: Mark the router as down and try again if possible.
247 void
248 connection_dir_connect_failed(connection_t *conn)
250 router_mark_as_down(conn->identity_digest); /* don't try him again */
251 if (conn->purpose == DIR_PURPOSE_FETCH_DIR ||
252 conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
253 log_fn(LOG_INFO, "Giving up on directory server at '%s'; retrying",
254 conn->address);
255 directory_get_from_dirserver(conn->purpose, NULL,
256 0 /* don't retry_if_no_servers */);
260 /** Helper for directory_initiate_command_(router|trusted_dir): send the
261 * command to a server whose address is <b>address</b>, whose IP is
262 * <b>addr</b>, whose directory port is <b>dir_port</b>, whose tor version is
263 * <b>platform</b>, and whose identity key digest is <b>digest</b>. The
264 * <b>platform</b> argument is optional; the others are required. */
265 static void
266 directory_initiate_command(const char *address, uint32_t addr,
267 uint16_t dir_port, const char *platform,
268 const char *digest, uint8_t purpose,
269 int private_connection, const char *resource,
270 const char *payload, size_t payload_len)
272 connection_t *conn;
274 tor_assert(address);
275 tor_assert(addr);
276 tor_assert(dir_port);
277 tor_assert(digest);
279 switch (purpose) {
280 case DIR_PURPOSE_FETCH_DIR:
281 log_fn(LOG_DEBUG,"initiating directory fetch");
282 break;
283 case DIR_PURPOSE_FETCH_RENDDESC:
284 log_fn(LOG_DEBUG,"initiating hidden-service descriptor fetch");
285 break;
286 case DIR_PURPOSE_UPLOAD_DIR:
287 log_fn(LOG_DEBUG,"initiating server descriptor upload");
288 break;
289 case DIR_PURPOSE_UPLOAD_RENDDESC:
290 log_fn(LOG_DEBUG,"initiating hidden-service descriptor upload");
291 break;
292 case DIR_PURPOSE_FETCH_RUNNING_LIST:
293 log_fn(LOG_DEBUG,"initiating running-routers fetch");
294 break;
295 default:
296 log_fn(LOG_ERR, "Unrecognized directory connection purpose.");
297 tor_assert(0);
300 conn = connection_new(CONN_TYPE_DIR);
302 /* set up conn so it's got all the data we need to remember */
303 conn->addr = addr;
304 conn->port = dir_port;
305 conn->address = tor_strdup(address);
306 memcpy(conn->identity_digest, digest, DIGEST_LEN);
308 conn->purpose = purpose;
310 /* give it an initial state */
311 conn->state = DIR_CONN_STATE_CONNECTING;
313 if (!private_connection) {
314 /* then we want to connect directly */
316 if (get_options()->HttpProxy) {
317 addr = get_options()->HttpProxyAddr;
318 dir_port = get_options()->HttpProxyPort;
321 switch (connection_connect(conn, conn->address, addr, dir_port)) {
322 case -1:
323 connection_dir_connect_failed(conn);
324 connection_free(conn);
325 return;
326 case 1:
327 conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
328 /* fall through */
329 case 0:
330 /* queue the command on the outbuf */
331 directory_send_command(conn, platform, purpose, resource,
332 payload, payload_len);
333 connection_watch_events(conn, EV_READ | EV_WRITE);
334 /* writable indicates finish, readable indicates broken link,
335 error indicates broken link in windowsland. */
337 } else { /* we want to connect via tor */
338 /* make an AP connection
339 * populate it and add it at the right state
340 * socketpair and hook up both sides
342 conn->s = connection_ap_make_bridge(conn->address, conn->port);
343 if (conn->s < 0) {
344 log_fn(LOG_WARN,"Making AP bridge to dirserver failed.");
345 connection_mark_for_close(conn);
346 return;
349 conn->state = DIR_CONN_STATE_CLIENT_SENDING;
350 connection_add(conn);
351 /* queue the command on the outbuf */
352 directory_send_command(conn, platform, purpose, resource,
353 payload, payload_len);
354 connection_watch_events(conn, EV_READ | EV_WRITE);
358 /** Queue an appropriate HTTP command on conn-\>outbuf. The other args
359 * are as in directory_initiate_command.
361 static void
362 directory_send_command(connection_t *conn, const char *platform,
363 int purpose, const char *resource,
364 const char *payload, size_t payload_len) {
365 char tmp[8192];
366 char proxystring[256];
367 char proxyauthstring[256];
368 char hoststring[128];
369 char url[128];
370 const char *httpcommand = NULL;
372 tor_assert(conn);
373 tor_assert(conn->type == CONN_TYPE_DIR);
375 /* come up with a string for which Host: we want */
376 if (conn->port == 80) {
377 strlcpy(hoststring, conn->address, sizeof(hoststring));
378 } else {
379 tor_snprintf(hoststring, sizeof(hoststring),"%s:%d",conn->address, conn->port);
382 /* come up with some proxy lines, if we're using one. */
383 if (get_options()->HttpProxy) {
384 char *base64_authenticator=NULL;
385 const char *authenticator = get_options()->HttpProxyAuthenticator;
387 tor_snprintf(proxystring, sizeof(proxystring),"http://%s", hoststring);
388 if (authenticator) {
389 base64_authenticator = alloc_http_authenticator(authenticator);
390 if (!base64_authenticator)
391 log_fn(LOG_WARN, "Encoding http authenticator failed");
393 if (base64_authenticator) {
394 tor_snprintf(proxyauthstring, sizeof(proxyauthstring),
395 "\r\nProxy-Authorization: Basic %s",
396 base64_authenticator);
397 tor_free(base64_authenticator);
398 } else {
399 proxyauthstring[0] = 0;
401 } else {
402 proxystring[0] = 0;
403 proxyauthstring[0] = 0;
406 switch (purpose) {
407 case DIR_PURPOSE_FETCH_DIR:
408 tor_assert(!resource);
409 tor_assert(!payload);
410 log_fn(LOG_DEBUG, "Asking for compressed directory from server running %s",
411 platform?platform:"<unknown version>");
412 httpcommand = "GET";
413 strlcpy(url, "/tor/dir.z", sizeof(url));
414 break;
415 case DIR_PURPOSE_FETCH_RUNNING_LIST:
416 tor_assert(!resource);
417 tor_assert(!payload);
418 httpcommand = "GET";
419 strlcpy(url, "/tor/running-routers", sizeof(url));
420 break;
421 case DIR_PURPOSE_UPLOAD_DIR:
422 tor_assert(!resource);
423 tor_assert(payload);
424 httpcommand = "POST";
425 strlcpy(url, "/tor/", sizeof(url));
426 break;
427 case DIR_PURPOSE_FETCH_RENDDESC:
428 tor_assert(resource);
429 tor_assert(!payload);
431 /* this must be true or we wouldn't be doing the lookup */
432 tor_assert(strlen(resource) <= REND_SERVICE_ID_LEN);
433 /* This breaks the function abstraction. */
434 strlcpy(conn->rend_query, resource, sizeof(conn->rend_query));
436 httpcommand = "GET";
437 tor_snprintf(url, sizeof(url), "/tor/rendezvous/%s", resource);
439 break;
440 case DIR_PURPOSE_UPLOAD_RENDDESC:
441 tor_assert(!resource);
442 tor_assert(payload);
443 httpcommand = "POST";
444 tor_snprintf(url, sizeof(url), "/tor/rendezvous/publish");
445 break;
448 tor_snprintf(tmp, sizeof(tmp), "%s %s%s HTTP/1.0\r\nContent-Length: %lu\r\nHost: %s%s\r\n\r\n",
449 httpcommand,
450 proxystring,
451 url,
452 payload ? (unsigned long)payload_len : 0,
453 hoststring,
454 proxyauthstring);
455 connection_write_to_buf(tmp, strlen(tmp), conn);
457 if (payload) {
458 /* then send the payload afterwards too */
459 connection_write_to_buf(payload, payload_len, conn);
463 /** Parse an HTTP request string <b>headers</b> of the form
464 * \verbatim
465 * "\%s [http[s]://]\%s HTTP/1..."
466 * \endverbatim
467 * If it's well-formed, strdup the second \%s into *<b>url</b>, and
468 * null-terminate it. If the url doesn't start with "/tor/", rewrite it
469 * so it does. Return 0.
470 * Otherwise, return -1.
472 static int
473 parse_http_url(char *headers, char **url)
475 char *s, *start, *tmp;
477 s = (char *)eat_whitespace_no_nl(headers);
478 if (!*s) return -1;
479 s = (char *)find_whitespace(s); /* get past GET/POST */
480 if (!*s) return -1;
481 s = (char *)eat_whitespace_no_nl(s);
482 if (!*s) return -1;
483 start = s; /* this is it, assuming it's valid */
484 s = (char *)find_whitespace(start);
485 if (!*s) return -1;
487 /* tolerate the http[s] proxy style of putting the hostname in the url */
488 if (s-start >= 4 && !strcmpstart(start,"http")) {
489 tmp = start + 4;
490 if (*tmp == 's')
491 tmp++;
492 if (s-tmp >= 3 && !strcmpstart(tmp,"://")) {
493 tmp = strchr(tmp+3, '/');
494 if (tmp && tmp < s) {
495 log_fn(LOG_DEBUG,"Skipping over 'http[s]://hostname' string");
496 start = tmp;
501 if (s-start < 5 || strcmpstart(start,"/tor/")) { /* need to rewrite it */
502 *url = tor_malloc(s - start + 5);
503 strlcpy(*url,"/tor", s-start+5);
504 strlcat((*url)+4, start, s-start+1);
505 } else {
506 *url = tor_strndup(start, s-start);
508 return 0;
511 /** Parse an HTTP response string <b>headers</b> of the form
512 * \verbatim
513 * "HTTP/1.\%d \%d\%s\r\n...".
514 * \endverbatim
516 * If it's well-formed, assign the status code to *<b>code</b> and
517 * return 0. Otherwise, return -1.
519 * On success: If <b>date</b> is provided, set *date to the Date
520 * header in the http headers, or 0 if no such header is found. If
521 * <b>compression</b> is provided, set *<b>compression</b> to the
522 * compression method given in the Content-Encoding header, or 0 if no
523 * such header is found, or -1 if the value of the header is not
524 * recognized. If <b>reason</b> is provided, strdup the reason string
525 * into it.
528 parse_http_response(const char *headers, int *code, time_t *date,
529 int *compression, char **reason)
531 int n1, n2;
532 char datestr[RFC1123_TIME_LEN+1];
533 smartlist_t *parsed_headers;
534 tor_assert(headers);
535 tor_assert(code);
537 while (TOR_ISSPACE(*headers)) headers++; /* tolerate leading whitespace */
539 if (sscanf(headers, "HTTP/1.%d %d", &n1, &n2) < 2 ||
540 (n1 != 0 && n1 != 1) ||
541 (n2 < 100 || n2 >= 600)) {
542 log_fn(LOG_WARN,"Failed to parse header '%s'",headers);
543 return -1;
545 *code = n2;
547 parsed_headers = smartlist_create();
548 smartlist_split_string(parsed_headers, headers, "\n",
549 SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
550 if (reason) {
551 smartlist_t *status_line_elements = smartlist_create();
552 tor_assert(smartlist_len(parsed_headers));
553 smartlist_split_string(status_line_elements,
554 smartlist_get(parsed_headers, 0),
555 " ", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 3);
556 tor_assert(smartlist_len(status_line_elements) <= 3);
557 if (smartlist_len(status_line_elements) == 3) {
558 *reason = smartlist_get(status_line_elements, 2);
559 smartlist_set(status_line_elements, 2, NULL); /* Prevent free */
561 SMARTLIST_FOREACH(status_line_elements, char *, cp, tor_free(cp));
562 smartlist_free(status_line_elements);
564 if (date) {
565 *date = 0;
566 SMARTLIST_FOREACH(parsed_headers, const char *, s,
567 if (!strcmpstart(s, "Date: ")) {
568 strlcpy(datestr, s+6, sizeof(datestr));
569 /* This will do nothing on failure, so we don't need to check
570 the result. We shouldn't warn, since there are many other valid
571 date formats besides the one we use. */
572 parse_rfc1123_time(datestr, date);
573 break;
576 if (compression) {
577 const char *enc = NULL;
578 SMARTLIST_FOREACH(parsed_headers, const char *, s,
579 if (!strcmpstart(s, "Content-Encoding: ")) {
580 enc = s+18; break;
582 if (!enc || !strcmp(enc, "identity")) {
583 *compression = 0;
584 } else if (!strcmp(enc, "deflate") || !strcmp(enc, "x-deflate")) {
585 *compression = ZLIB_METHOD;
586 } else if (!strcmp(enc, "gzip") || !strcmp(enc, "x-gzip")) {
587 *compression = GZIP_METHOD;
588 } else {
589 log_fn(LOG_INFO, "Unrecognized content encoding: '%s'. Trying to deal.", enc);
590 *compression = -1;
593 SMARTLIST_FOREACH(parsed_headers, char *, s, tor_free(s));
594 smartlist_free(parsed_headers);
596 return 0;
599 /** Return true iff <b>body</b> doesn't start with a plausible router or
600 * running-list or directory opening. This is a sign of possible compression.
602 static int
603 body_is_plausible(const char *body, size_t len, int purpose)
605 int i;
606 if (len == 0)
607 return 1; /* empty bodies don't need decompression */
608 if (len < 32)
609 return 0;
610 if (purpose != DIR_PURPOSE_FETCH_RENDDESC) {
611 if (!strcmpstart(body,"router") ||
612 !strcmpstart(body,"signed-directory") ||
613 !strcmpstart(body,"network-status") ||
614 !strcmpstart(body,"running-routers"))
615 return 1;
616 for (i=0;i<32;++i) {
617 if (!TOR_ISPRINT(body[i]) && !TOR_ISSPACE(body[i]))
618 return 0;
620 return 1;
621 } else {
622 return 1;
626 /** We are a client, and we've finished reading the server's
627 * response. Parse and it and act appropriately.
629 * Return -1 if an error has occurred, or 0 normally. The caller
630 * will take care of marking the connection for close.
632 static int
633 connection_dir_client_reached_eof(connection_t *conn)
635 char *body;
636 char *headers;
637 char *reason = NULL;
638 size_t body_len=0;
639 int status_code;
640 time_t now, date_header=0;
641 int delta;
642 int compression;
643 int plausible;
644 int skewed=0;
646 switch (fetch_from_buf_http(conn->inbuf,
647 &headers, MAX_HEADERS_SIZE,
648 &body, &body_len, MAX_DIR_SIZE)) {
649 case -1: /* overflow */
650 log_fn(LOG_WARN,"'fetch' response too large (server '%s'). Failing.", conn->address);
651 return -1;
652 case 0:
653 log_fn(LOG_INFO,"'fetch' response not all here, but we're at eof. Closing.");
654 return -1;
655 /* case 1, fall through */
658 if (parse_http_response(headers, &status_code, &date_header,
659 &compression, &reason) < 0) {
660 log_fn(LOG_WARN,"Unparseable headers (server '%s'). Closing.", conn->address);
661 tor_free(body); tor_free(headers);
662 return -1;
664 if (!reason) reason = tor_strdup("[no reason given]");
666 log_fn(LOG_DEBUG,
667 "Received response from directory server '%s': %d \"%s\"",
668 conn->address, status_code, reason);
670 if (date_header > 0) {
671 now = time(NULL);
672 delta = now-date_header;
673 if (abs(delta)>ALLOW_DIRECTORY_TIME_SKEW) {
674 log_fn(router_digest_is_trusted_dir(conn->identity_digest) ? LOG_WARN : LOG_INFO,
675 "Received directory with skewed time (server '%s'): we are %d minutes %s, or the directory is %d minutes %s.",
676 conn->address,
677 abs(delta)/60, delta>0 ? "ahead" : "behind",
678 abs(delta)/60, delta>0 ? "behind" : "ahead");
679 skewed = 1; /* don't check the recommended-versions line */
680 } else {
681 log_fn(LOG_INFO, "Time on received directory is within tolerance; we are %d seconds skewed. (That's okay.)", delta);
685 plausible = body_is_plausible(body, body_len, conn->purpose);
686 if (compression || !plausible) {
687 char *new_body = NULL;
688 size_t new_len = 0;
689 int guessed = detect_compression_method(body, body_len);
690 if (compression <= 0 || guessed != compression) {
691 /* Tell the user if we don't believe what we're told about compression.*/
692 const char *description1, *description2;
693 if (compression == ZLIB_METHOD)
694 description1 = "as deflated";
695 else if (compression == GZIP_METHOD)
696 description1 = "as gzipped";
697 else if (compression == 0)
698 description1 = "as uncompressed";
699 else
700 description1 = "with an unknown Content-Encoding";
701 if (guessed == ZLIB_METHOD)
702 description2 = "deflated";
703 else if (guessed == GZIP_METHOD)
704 description2 = "gzipped";
705 else if (!plausible)
706 description2 = "confusing binary junk";
707 else
708 description2 = "uncompressed";
710 log_fn(LOG_INFO, "HTTP body from server '%s' was labeled %s, "
711 "but it seems to be %s.%s",
712 conn->address, description1, description2,
713 (compression>0 && guessed>0)?" Trying both.":"");
715 /* Try declared compression first if we can. */
716 if (compression > 0)
717 tor_gzip_uncompress(&new_body, &new_len, body, body_len, compression);
718 /* Okay, if that didn't work, and we think that it was compressed
719 * differently, try that. */
720 if (!new_body && guessed > 0 && compression != guessed)
721 tor_gzip_uncompress(&new_body, &new_len, body, body_len, guessed);
722 /* If we're pretty sure that we have a compressed directory, and
723 * we didn't manage to uncompress it, then warn and bail. */
724 if (!plausible && !new_body) {
725 log_fn(LOG_WARN, "Unable to decompress HTTP body (server '%s').", conn->address);
726 tor_free(body); tor_free(headers); tor_free(reason);
727 return -1;
729 if (new_body) {
730 tor_free(body);
731 body = new_body;
732 body_len = new_len;
736 if (conn->purpose == DIR_PURPOSE_FETCH_DIR) {
737 /* fetch/process the directory to learn about new routers. */
738 log_fn(LOG_INFO,"Received directory (size %d) from server '%s'",
739 (int)body_len, conn->address);
740 if (status_code == 503 || body_len == 0) {
741 log_fn(LOG_INFO,"Empty directory; status %d (\"%s\") Ignoring.",
742 status_code, reason);
743 tor_free(body); tor_free(headers); tor_free(reason);
744 return 0;
746 if (status_code != 200) {
747 log_fn(LOG_WARN,"Received http status code %d (\"%s\") from server '%s'. Failing.",
748 status_code, reason, conn->address);
749 tor_free(body); tor_free(headers); tor_free(reason);
750 return -1;
752 if (router_load_routerlist_from_directory(body, NULL, !skewed, 0) < 0) {
753 log_fn(LOG_NOTICE,"I failed to parse the directory I fetched from %s:%d. Ignoring.", conn->address, conn->port);
754 } else {
755 log_fn(LOG_INFO,"updated routers.");
757 /* do things we've been waiting to do */
758 directory_has_arrived(time(NULL), conn->identity_digest);
761 if (conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
762 running_routers_t *rrs;
763 routerlist_t *rl;
764 /* just update our list of running routers, if this list is new info */
765 log_fn(LOG_INFO,"Received running-routers list (size %d)", (int)body_len);
766 if (status_code != 200) {
767 log_fn(LOG_WARN,"Received http status code %d (\"%s\") from server '%s'. Failing.",
768 status_code, reason, conn->address);
769 tor_free(body); tor_free(headers); tor_free(reason);
770 return -1;
772 if (!(rrs = router_parse_runningrouters(body, 1))) {
773 log_fn(LOG_WARN, "Can't parse runningrouters list (server '%s')", conn->address);
774 tor_free(body); tor_free(headers); tor_free(reason);
775 return -1;
777 router_get_routerlist(&rl);
778 if (rl) {
779 routerlist_set_runningrouters(rl,rrs);
780 } else {
781 running_routers_free(rrs);
785 if (conn->purpose == DIR_PURPOSE_UPLOAD_DIR) {
786 switch (status_code) {
787 case 200:
788 log_fn(LOG_INFO,"eof (status 200) after uploading server descriptor: finished.");
789 break;
790 case 400:
791 log_fn(LOG_WARN,"http status 400 (\"%s\") response from dirserver '%s'. Malformed server descriptor?", reason, conn->address);
792 break;
793 case 403:
794 log_fn(LOG_WARN,"http status 403 (\"%s\") 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.", reason, conn->address);
795 break;
796 default:
797 log_fn(LOG_WARN,"http status %d (\"%s\") reason unexpected (server '%s').", status_code, reason, conn->address);
798 break;
802 if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC) {
803 log_fn(LOG_INFO,"Received rendezvous descriptor (size %d, status %d (\"%s\"))",
804 (int)body_len, status_code, reason);
805 switch (status_code) {
806 case 200:
807 if (rend_cache_store(body, body_len) < 0) {
808 log_fn(LOG_WARN,"Failed to store rendezvous descriptor.");
809 /* alice's ap_stream will notice when connection_mark_for_close
810 * cleans it up */
811 } else {
812 /* success. notify pending connections about this. */
813 conn->purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
814 rend_client_desc_here(conn->rend_query);
816 break;
817 case 404:
818 /* not there. pending connections will be notified when
819 * connection_mark_for_close cleans it up. */
820 break;
821 case 400:
822 log_fn(LOG_WARN,"http status 400 (\"%s\"). Dirserver didn't like our rendezvous query?", reason);
823 break;
824 default:
825 log_fn(LOG_WARN,"http status %d (\"%s\") response unexpected (server '%s').", status_code, reason, conn->address);
826 break;
830 if (conn->purpose == DIR_PURPOSE_UPLOAD_RENDDESC) {
831 switch (status_code) {
832 case 200:
833 log_fn(LOG_INFO,"Uploading rendezvous descriptor: finished with status 200 (\"%s\")", reason);
834 break;
835 case 400:
836 log_fn(LOG_WARN,"http status 400 (\"%s\") response from dirserver. Malformed rendezvous descriptor?", reason);
837 break;
838 default:
839 log_fn(LOG_WARN,"http status %d (\"%s\") response unexpected (server '%s').", status_code, reason, conn->address);
840 break;
843 tor_free(body); tor_free(headers); tor_free(reason);
844 return 0;
847 int connection_dir_reached_eof(connection_t *conn) {
848 int retval;
849 if (conn->state != DIR_CONN_STATE_CLIENT_READING) {
850 log_fn(LOG_INFO,"conn reached eof, not reading. Closing.");
851 connection_close_immediate(conn); /* it was an error; give up on flushing */
852 connection_mark_for_close(conn);
853 return -1;
856 retval = connection_dir_client_reached_eof(conn);
857 connection_mark_for_close(conn);
858 return retval;
861 /** Read handler for directory connections. (That's connections <em>to</em>
862 * directory servers and connections <em>at</em> directory servers.)
864 int connection_dir_process_inbuf(connection_t *conn) {
866 tor_assert(conn);
867 tor_assert(conn->type == CONN_TYPE_DIR);
869 /* Directory clients write, then read data until they receive EOF;
870 * directory servers read data until they get an HTTP command, then
871 * write their response (when it's finished flushing, they mark for
872 * close).
875 /* If we're on the dirserver side, look for a command. */
876 if (conn->state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
877 if (directory_handle_command(conn) < 0) {
878 connection_mark_for_close(conn);
879 return -1;
881 return 0;
884 /* XXX for READ states, might want to make sure inbuf isn't too big */
886 log_fn(LOG_DEBUG,"Got data, not eof. Leaving on inbuf.");
887 return 0;
890 /** Create an http response for the client <b>conn</b> out of
891 * <b>status</b> and <b>reason_phrase</b>. Write it to <b>conn</b>.
893 static void
894 write_http_status_line(connection_t *conn, int status,
895 const char *reason_phrase)
897 char buf[256];
898 if (tor_snprintf(buf, sizeof(buf), "HTTP/1.0 %d %s\r\n\r\n",
899 status, reason_phrase) < 0) {
900 log_fn(LOG_WARN,"Bug: status line too long.");
901 return;
903 connection_write_to_buf(buf, strlen(buf), conn);
906 /** Helper function: return 1 if there are any dir conns of purpose
907 * <b>purpose</b> that are going elsewhere than our own ORPort/Dirport.
908 * Else return 0.
910 static int
911 already_fetching_directory(int purpose) {
912 int i, n;
913 connection_t *conn;
914 connection_t **carray;
916 get_connection_array(&carray,&n);
917 for (i=0;i<n;i++) {
918 conn = carray[i];
919 if (conn->type == CONN_TYPE_DIR &&
920 conn->purpose == purpose &&
921 !conn->marked_for_close &&
922 !router_digest_is_me(conn->identity_digest))
923 return 1;
925 return 0;
928 /** Helper function: called when a dirserver gets a complete HTTP GET
929 * request. Look for a request for a directory or for a rendezvous
930 * service descriptor. On finding one, write a response into
931 * conn-\>outbuf. If the request is unrecognized, send a 400.
932 * Always return 0. */
933 static int
934 directory_handle_command_get(connection_t *conn, char *headers,
935 char *body, size_t body_len)
937 size_t dlen;
938 const char *cp;
939 char *url;
940 char tmp[8192];
941 char date[RFC1123_TIME_LEN+1];
943 log_fn(LOG_DEBUG,"Received GET command.");
945 conn->state = DIR_CONN_STATE_SERVER_WRITING;
947 if (parse_http_url(headers, &url) < 0) {
948 write_http_status_line(conn, 400, "Bad request");
949 return 0;
951 log_fn(LOG_INFO,"rewritten url as '%s'.", url);
953 if (!strcmp(url,"/tor/") || !strcmp(url,"/tor/dir.z")) { /* directory fetch */
954 int deflated = !strcmp(url,"/tor/dir.z");
955 dlen = dirserv_get_directory(&cp, deflated);
957 tor_free(url);
959 if (dlen == 0) {
960 log_fn(LOG_NOTICE,"Client asked for the mirrored directory, but we don't have a good one yet. Sending 503 Dir not available.");
961 write_http_status_line(conn, 503, "Directory unavailable");
962 /* try to get a new one now */
963 if (!already_fetching_directory(DIR_PURPOSE_FETCH_DIR))
964 directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 1);
965 return 0;
968 log_fn(LOG_DEBUG,"Dumping %sdirectory to client.",
969 deflated?"deflated ":"");
970 format_rfc1123_time(date, time(NULL));
971 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",
972 date,
973 (int)dlen,
974 deflated?"deflate":"identity");
975 connection_write_to_buf(tmp, strlen(tmp), conn);
976 connection_write_to_buf(cp, dlen, conn);
977 return 0;
980 if (!strcmp(url,"/tor/running-routers") ||
981 !strcmp(url,"/tor/running-routers.z")) { /* running-routers fetch */
982 int deflated = !strcmp(url,"/tor/dir.z");
983 tor_free(url);
984 dlen = dirserv_get_runningrouters(&cp, deflated);
985 if (!dlen) { /* we failed to create/cache cp */
986 write_http_status_line(conn, 503, "Directory unavailable");
987 /* try to get a new one now */
988 if (!already_fetching_directory(DIR_PURPOSE_FETCH_RUNNING_LIST))
989 directory_get_from_dirserver(DIR_PURPOSE_FETCH_RUNNING_LIST, NULL, 1);
990 return 0;
993 format_rfc1123_time(date, time(NULL));
994 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",
995 date,
996 (int)dlen,
997 deflated?"deflate":"identity");
998 connection_write_to_buf(tmp, strlen(tmp), conn);
999 connection_write_to_buf(cp, strlen(cp), conn);
1000 return 0;
1003 if (!strcmpstart(url,"/tor/rendezvous/")) {
1004 /* rendezvous descriptor fetch */
1005 const char *descp;
1006 size_t desc_len;
1008 if (!authdir_mode(get_options())) {
1009 /* We don't hand out rend descs. In fact, it could be a security
1010 * risk, since rend_cache_lookup_desc() below would provide it
1011 * if we're gone to the site recently, and 404 if we haven't.
1013 * Reject. */
1014 write_http_status_line(conn, 400, "Nonauthoritative directory does not not store rendezvous descriptors.");
1015 tor_free(url);
1016 return 0;
1018 switch (rend_cache_lookup_desc(url+strlen("/tor/rendezvous/"), &descp, &desc_len)) {
1019 case 1: /* valid */
1020 format_rfc1123_time(date, time(NULL));
1021 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",
1022 date,
1023 (int)desc_len); /* can't include descp here, because it's got nuls */
1024 connection_write_to_buf(tmp, strlen(tmp), conn);
1025 connection_write_to_buf(descp, desc_len, conn);
1026 break;
1027 case 0: /* well-formed but not present */
1028 write_http_status_line(conn, 404, "Not found");
1029 break;
1030 case -1: /* not well-formed */
1031 write_http_status_line(conn, 400, "Bad request");
1032 break;
1034 tor_free(url);
1035 return 0;
1038 /* we didn't recognize the url */
1039 write_http_status_line(conn, 404, "Not found");
1040 tor_free(url);
1041 return 0;
1044 /** Helper function: called when a dirserver gets a complete HTTP POST
1045 * request. Look for an uploaded server descriptor or rendezvous
1046 * service descriptor. On finding one, process it and write a
1047 * response into conn-\>outbuf. If the request is unrecognized, send a
1048 * 400. Always return 0. */
1049 static int
1050 directory_handle_command_post(connection_t *conn, char *headers,
1051 char *body, size_t body_len)
1053 const char *cp;
1054 char *url;
1056 log_fn(LOG_DEBUG,"Received POST command.");
1058 conn->state = DIR_CONN_STATE_SERVER_WRITING;
1060 if (!authdir_mode(get_options())) {
1061 /* we just provide cached directories; we don't want to
1062 * receive anything. */
1063 write_http_status_line(conn, 400, "Nonauthoritative directory does not not store server descriptors.");
1064 return 0;
1067 if (parse_http_url(headers, &url) < 0) {
1068 write_http_status_line(conn, 400, "Bad request");
1069 return 0;
1071 log_fn(LOG_INFO,"rewritten url as '%s'.", url);
1073 if (!strcmp(url,"/tor/")) { /* server descriptor post */
1074 const char *msg;
1075 cp = body;
1076 switch (dirserv_add_descriptor(&cp, &msg)) {
1077 case -2:
1078 case -1:
1079 /* malformed descriptor, or something wrong */
1080 write_http_status_line(conn, 400, msg?msg:"Malformed or unacceptable server descriptor");
1081 log_fn(LOG_NOTICE,"Rejected descriptor published by '%s'.", conn->address);
1082 break;
1083 case 0:
1084 /* descriptor was well-formed but server has not been approved */
1085 write_http_status_line(conn, 200, msg?msg:"Unverified server descriptor accepted");
1086 break;
1087 case 1:
1088 dirserv_get_directory(&cp, 0); /* rebuild and write to disk */
1089 write_http_status_line(conn, 200, msg?msg:"Verified server descriptor accepted");
1090 break;
1092 tor_free(url);
1093 return 0;
1096 if (!strcmpstart(url,"/tor/rendezvous/publish")) {
1097 /* rendezvous descriptor post */
1098 if (rend_cache_store(body, body_len) < 0)
1099 write_http_status_line(conn, 400, "Invalid service descriptor rejected");
1100 else
1101 write_http_status_line(conn, 200, "Service descriptor stored");
1102 tor_free(url);
1103 return 0;
1106 /* we didn't recognize the url */
1107 write_http_status_line(conn, 404, "Not found");
1108 tor_free(url);
1109 return 0;
1112 /** Called when a dirserver receives data on a directory connection;
1113 * looks for an HTTP request. If the request is complete, remove it
1114 * from the inbuf, try to process it; otherwise, leave it on the
1115 * buffer. Return a 0 on success, or -1 on error.
1117 static int directory_handle_command(connection_t *conn) {
1118 char *headers=NULL, *body=NULL;
1119 size_t body_len=0;
1120 int r;
1122 tor_assert(conn);
1123 tor_assert(conn->type == CONN_TYPE_DIR);
1125 switch (fetch_from_buf_http(conn->inbuf,
1126 &headers, MAX_HEADERS_SIZE,
1127 &body, &body_len, MAX_BODY_SIZE)) {
1128 case -1: /* overflow */
1129 log_fn(LOG_WARN,"Invalid input from address '%s'. Closing.", conn->address);
1130 return -1;
1131 case 0:
1132 log_fn(LOG_DEBUG,"command not all here yet.");
1133 return 0;
1134 /* case 1, fall through */
1137 log_fn(LOG_DEBUG,"headers '%s', body '%s'.", headers, body);
1139 if (!strncasecmp(headers,"GET",3))
1140 r = directory_handle_command_get(conn, headers, body, body_len);
1141 else if (!strncasecmp(headers,"POST",4))
1142 r = directory_handle_command_post(conn, headers, body, body_len);
1143 else {
1144 log_fn(LOG_WARN,"Got headers '%s' with unknown command. Closing.", headers);
1145 r = -1;
1148 tor_free(headers); tor_free(body);
1149 return r;
1152 /** Write handler for directory connections; called when all data has
1153 * been flushed. Close the connection or wait for a response as
1154 * appropriate.
1156 int connection_dir_finished_flushing(connection_t *conn) {
1158 tor_assert(conn);
1159 tor_assert(conn->type == CONN_TYPE_DIR);
1161 switch (conn->state) {
1162 case DIR_CONN_STATE_CLIENT_SENDING:
1163 log_fn(LOG_DEBUG,"client finished sending command.");
1164 conn->state = DIR_CONN_STATE_CLIENT_READING;
1165 connection_stop_writing(conn);
1166 return 0;
1167 case DIR_CONN_STATE_SERVER_WRITING:
1168 log_fn(LOG_INFO,"Finished writing server response. Closing.");
1169 connection_mark_for_close(conn);
1170 return 0;
1171 default:
1172 log_fn(LOG_WARN,"Bug: called in unexpected state %d.", conn->state);
1173 tor_fragile_assert();
1174 return -1;
1176 return 0;
1179 /** Connected handler for directory connections: begin sending data to the
1180 * server */
1181 int connection_dir_finished_connecting(connection_t *conn)
1183 tor_assert(conn);
1184 tor_assert(conn->type == CONN_TYPE_DIR);
1185 tor_assert(conn->state == DIR_CONN_STATE_CONNECTING);
1187 log_fn(LOG_INFO,"Dir connection to router %s:%u established.",
1188 conn->address,conn->port);
1190 conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
1191 return 0;