In my private little universe, terminals are still 80 columns. Impose a 160-characte...
[tor.git] / src / or / directory.c
blobb3f8bbe2e31d5cedd0fe202f44b9a8c74318c728
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 Code to send and fetch directories and router
12 * descriptors via HTTP. Directories use dirserv.c to generate the
13 * results; clients use routers.c to parse them.
14 **/
16 /* In-points to directory.c:
18 * - directory_post_to_dirservers(), called from
19 * router_upload_dir_desc_to_dirservers() in router.c
20 * upload_service_descriptor() in rendservice.c
21 * - directory_get_from_dirserver(), called from
22 * rend_client_refetch_renddesc() in rendclient.c
23 * run_scheduled_events() in main.c
24 * do_hup() in main.c
25 * - connection_dir_process_inbuf(), called from
26 * connection_process_inbuf() in connection.c
27 * - connection_dir_finished_flushing(), called from
28 * connection_finished_flushing() in connection.c
29 * - connection_dir_finished_connecting(), called from
30 * connection_finished_connecting() in connection.c
32 static void
33 directory_initiate_command_trusted_dir(trusted_dir_server_t *dirserv,
34 uint8_t purpose, int private_connection,
35 const char *resource,
36 const char *payload, size_t payload_len);
37 static void
38 directory_initiate_command(const char *address, uint32_t addr, uint16_t port,
39 const char *platform,
40 const char *digest, uint8_t purpose,
41 int private_connection, const char *resource,
42 const char *payload, size_t payload_len);
44 static void
45 directory_send_command(connection_t *conn, const char *platform,
46 int purpose, const char *resource,
47 const char *payload, size_t payload_len);
48 static int directory_handle_command(connection_t *conn);
49 static int body_is_plausible(const char *body, size_t body_len, int purpose);
50 static int purpose_is_private(uint8_t purpose);
51 static char *http_get_header(const char *headers, const char *which);
52 static char *http_get_origin(const char *headers, connection_t *conn);
53 static void connection_dir_download_networkstatus_failed(connection_t *conn);
54 static void connection_dir_download_routerdesc_failed(connection_t *conn);
55 static void dir_networkstatus_download_failed(smartlist_t *failed);
56 static void dir_routerdesc_download_failed(smartlist_t *failed);
58 /********* START VARIABLES **********/
60 static addr_policy_t *dir_policy = NULL;
62 #define ALLOW_DIRECTORY_TIME_SKEW 30*60 /* 30 minutes */
64 /********* END VARIABLES ************/
66 /** Parse get_options()->DirPolicy, and put the processed version in
67 * &dir_policy. Ignore port specifiers.
69 void
70 parse_dir_policy(void)
72 addr_policy_t *n;
73 if (dir_policy) {
74 addr_policy_free(dir_policy);
75 dir_policy = NULL;
77 config_parse_addr_policy(get_options()->DirPolicy, &dir_policy, -1);
78 /* ports aren't used. */
79 for (n=dir_policy; n; n = n->next) {
80 n->prt_min = 1;
81 n->prt_max = 65535;
85 /** Free storage used to hold parsed directory policy */
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
97 dir_policy_permits_address(uint32_t addr)
99 int a;
101 if (!dir_policy) /* 'no dir policy' means 'accept' */
102 return 1;
103 a = router_compare_addr_to_addr_policy(addr, 1, dir_policy);
104 if (a==ADDR_POLICY_REJECTED)
105 return 0;
106 else if (a==ADDR_POLICY_ACCEPTED)
107 return 1;
108 warn(LD_BUG, "Bug: got unexpected 'maybe' answer from dir policy");
109 return 0;
112 /** Return true iff the directory purpose 'purpose' must use an
113 * anonymous connection to a directory. */
114 static int
115 purpose_is_private(uint8_t purpose)
117 if (purpose == DIR_PURPOSE_FETCH_DIR ||
118 purpose == DIR_PURPOSE_UPLOAD_DIR ||
119 purpose == DIR_PURPOSE_FETCH_RUNNING_LIST ||
120 purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS ||
121 purpose == DIR_PURPOSE_FETCH_SERVERDESC)
122 return 0;
123 return 1;
126 /** Start a connection to every known directory server, using
127 * connection purpose 'purpose' and uploading the payload 'payload'
128 * (length 'payload_len'). The purpose should be one of
129 * 'DIR_PURPOSE_UPLOAD_DIR' or 'DIR_PURPOSE_UPLOAD_RENDDESC'.
131 void
132 directory_post_to_dirservers(uint8_t purpose, const char *payload,
133 size_t payload_len)
135 smartlist_t *dirservers;
136 int post_via_tor;
138 router_get_trusted_dir_servers(&dirservers);
139 tor_assert(dirservers);
140 /* This tries dirservers which we believe to be down, but ultimately, that's
141 * harmless, and we may as well err on the side of getting things uploaded.
143 SMARTLIST_FOREACH(dirservers, trusted_dir_server_t *, ds,
145 post_via_tor = purpose_is_private(purpose) ||
146 !fascist_firewall_allows_address(ds->addr,ds->dir_port);
147 directory_initiate_command_trusted_dir(ds, purpose, post_via_tor,
148 NULL, payload, payload_len);
152 /** Start a connection to a random running directory server, using
153 * connection purpose 'purpose' and requesting 'resource'.
154 * If <b>retry_if_no_servers</b>, then if all the possible servers seem
155 * down, mark them up and try again.
157 void
158 directory_get_from_dirserver(uint8_t purpose, const char *resource,
159 int retry_if_no_servers)
161 routerinfo_t *r = NULL;
162 trusted_dir_server_t *ds = NULL;
163 or_options_t *options = get_options();
164 int fetch_fresh_first = server_mode(options) && options->DirPort != 0;
165 int directconn = !purpose_is_private(purpose);
167 int need_v1_support = purpose == DIR_PURPOSE_FETCH_DIR ||
168 purpose == DIR_PURPOSE_FETCH_RUNNING_LIST;
169 int need_v2_support = purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS ||
170 purpose == DIR_PURPOSE_FETCH_SERVERDESC;
172 if (directconn) {
173 if (fetch_fresh_first && purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS &&
174 !strcmpstart(resource,"fp/") && strlen(resource) == HEX_DIGEST_LEN+3) {
175 /* Try to ask the actual dirserver its opinion. */
176 char digest[DIGEST_LEN];
177 base16_decode(digest, DIGEST_LEN, resource+3, HEX_DIGEST_LEN);
178 ds = router_get_trusteddirserver_by_digest(digest);
180 if (!ds && fetch_fresh_first) {
181 /* only ask authdirservers, and don't ask myself */
182 ds = router_pick_trusteddirserver(need_v1_support, 1, 1,
183 retry_if_no_servers);
185 if (!ds) {
186 /* anybody with a non-zero dirport will do */
187 r = router_pick_directory_server(1, 1, need_v2_support,
188 retry_if_no_servers);
189 if (!r) {
190 const char *which;
191 if (purpose == DIR_PURPOSE_FETCH_DIR)
192 which = "directory";
193 else if (purpose == DIR_PURPOSE_FETCH_RUNNING_LIST)
194 which = "status list";
195 else if (purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS)
196 which = "network status";
197 else // if (purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS)
198 which = "server descriptors";
199 info(LD_DIR,
200 "No router found for %s; falling back to dirserver list", which);
201 ds = router_pick_trusteddirserver(1, 1, 1,
202 retry_if_no_servers);
203 if (!ds)
204 directconn = 0; /* last resort: try routing it via Tor */
208 if (!directconn) {
209 /* Never use fascistfirewall; we're going via Tor. */
210 if (purpose == DIR_PURPOSE_FETCH_RENDDESC) {
211 /* only ask authdirservers, any of them will do */
212 ds = router_pick_trusteddirserver(0, 0, 0, retry_if_no_servers);
213 } else {
214 /* anybody with a non-zero dirport will do. Disregard firewalls. */
215 r = router_pick_directory_server(1, 0, need_v2_support,
216 retry_if_no_servers);
220 if (r)
221 directory_initiate_command_router(r, purpose, !directconn,
222 resource, NULL, 0);
223 else if (ds)
224 directory_initiate_command_trusted_dir(ds, purpose, !directconn,
225 resource, NULL, 0);
226 else {
227 notice(LD_DIR,
228 "No running dirservers known. Will try again later. (purpose %d)",
229 purpose);
230 if (!purpose_is_private(purpose)) {
231 /* remember we tried them all and failed. */
232 directory_all_unreachable(time(NULL));
237 /** Launch a new connection to the directory server <b>router</b> to upload or
238 * download a service or rendezvous descriptor. <b>purpose</b> determines what
239 * kind of directory connection we're launching, and must be one of
240 * DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC}.
242 * When uploading, <b>payload</b> and <b>payload_len</b> determine the content
243 * of the HTTP post. Otherwise, <b>payload</b> should be NULL.
245 * When fetching a rendezvous descriptor, <b>resource</b> is the service ID we
246 * want to fetch.
248 void
249 directory_initiate_command_router(routerinfo_t *router, uint8_t purpose,
250 int private_connection, const char *resource,
251 const char *payload, size_t payload_len)
253 directory_initiate_command(router->address, router->addr, router->dir_port,
254 router->platform, router->cache_info.identity_digest,
255 purpose, private_connection, resource,
256 payload, payload_len);
259 /** As directory_initiate_command_router, but send the command to a trusted
260 * directory server <b>dirserv</b>. **/
261 static void
262 directory_initiate_command_trusted_dir(trusted_dir_server_t *dirserv,
263 uint8_t purpose, int private_connection,
264 const char *resource,
265 const char *payload, size_t payload_len)
267 directory_initiate_command(dirserv->address, dirserv->addr,
268 dirserv->dir_port, NULL, dirserv->digest, purpose,
269 private_connection, resource,
270 payload, payload_len);
273 /** Called when we are unable to complete the client's request to a
274 * directory server: Mark the router as down and try again if possible.
276 void
277 connection_dir_request_failed(connection_t *conn)
279 if (router_digest_is_me(conn->identity_digest))
280 return; /* this was a test fetch. don't retry. */
281 router_mark_as_down(conn->identity_digest); /* don't try him again */
282 if (conn->purpose == DIR_PURPOSE_FETCH_DIR ||
283 conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
284 info(LD_DIR, "Giving up on directory server at '%s:%d'; retrying",
285 conn->address, conn->port);
286 directory_get_from_dirserver(conn->purpose, NULL,
287 0 /* don't retry_if_no_servers */);
288 } else if (conn->purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) {
289 info(LD_DIR, "Giving up on directory server at '%s'; retrying",
290 conn->address);
291 connection_dir_download_networkstatus_failed(conn);
292 } else if (conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC) {
293 info(LD_DIR, "Giving up on directory server at '%s'; retrying",
294 conn->address);
295 connection_dir_download_routerdesc_failed(conn);
299 /** Called when an attempt to download one or more network status
300 * documents on connection <b>conn</b> failed. Decide whether to
301 * retry the fetch now, later, or never.
303 static void
304 connection_dir_download_networkstatus_failed(connection_t *conn)
306 if (!conn->requested_resource) {
307 /* We never reached directory_send_command, which means that we never
308 * opened a network connection. Either we're out of sockets, or the
309 * network is down. Either way, retrying would be pointless. */
310 return;
312 if (!strcmpstart(conn->requested_resource, "all")) {
313 /* We're a non-authoritative directory cache; try again. */
314 directory_get_from_dirserver(conn->purpose, "all.z",
315 0 /* don't retry_if_no_servers */);
316 } else if (!strcmpstart(conn->requested_resource, "fp/")) {
317 /* We were trying to download by fingerprint; mark them all has having
318 * failed, and possibly retry them later.*/
319 smartlist_t *failed = smartlist_create();
320 dir_split_resource_into_fingerprints(conn->requested_resource+3,
321 failed, NULL, 0);
322 if (smartlist_len(failed)) {
323 dir_networkstatus_download_failed(failed);
324 SMARTLIST_FOREACH(failed, char *, cp, tor_free(cp));
326 smartlist_free(failed);
330 /** Called when an attempt to download one or more router descriptors
331 * on connection <b>conn</b> failed.
333 static void
334 connection_dir_download_routerdesc_failed(connection_t *conn)
336 /* Try again. No need to increment the failure count for routerdescs, since
337 * it's not their fault.*/
338 /* update_router_descriptor_downloads(time(NULL)); */
341 /** Helper for directory_initiate_command_(router|trusted_dir): send the
342 * command to a server whose address is <b>address</b>, whose IP is
343 * <b>addr</b>, whose directory port is <b>dir_port</b>, whose tor version is
344 * <b>platform</b>, and whose identity key digest is <b>digest</b>. The
345 * <b>platform</b> argument is optional; the others are required. */
346 static void
347 directory_initiate_command(const char *address, uint32_t addr,
348 uint16_t dir_port, const char *platform,
349 const char *digest, uint8_t purpose,
350 int private_connection, const char *resource,
351 const char *payload, size_t payload_len)
353 connection_t *conn;
355 tor_assert(address);
356 tor_assert(addr);
357 tor_assert(dir_port);
358 tor_assert(digest);
360 switch (purpose) {
361 case DIR_PURPOSE_FETCH_DIR:
362 debug(LD_DIR,"initiating directory fetch");
363 break;
364 case DIR_PURPOSE_FETCH_RENDDESC:
365 debug(LD_DIR,"initiating hidden-service descriptor fetch");
366 break;
367 case DIR_PURPOSE_UPLOAD_DIR:
368 debug(LD_OR,"initiating server descriptor upload");
369 break;
370 case DIR_PURPOSE_UPLOAD_RENDDESC:
371 debug(LD_REND,"initiating hidden-service descriptor upload");
372 break;
373 case DIR_PURPOSE_FETCH_RUNNING_LIST:
374 debug(LD_DIR,"initiating running-routers fetch");
375 break;
376 case DIR_PURPOSE_FETCH_NETWORKSTATUS:
377 debug(LD_DIR,"initiating network-status fetch");
378 break;
379 case DIR_PURPOSE_FETCH_SERVERDESC:
380 debug(LD_DIR,"initiating server descriptor fetch");
381 break;
382 default:
383 err(LD_BUG, "Unrecognized directory connection purpose.");
384 tor_assert(0);
387 conn = connection_new(CONN_TYPE_DIR);
389 /* set up conn so it's got all the data we need to remember */
390 conn->addr = addr;
391 conn->port = dir_port;
392 conn->address = tor_strdup(address);
393 memcpy(conn->identity_digest, digest, DIGEST_LEN);
395 conn->purpose = purpose;
397 /* give it an initial state */
398 conn->state = DIR_CONN_STATE_CONNECTING;
400 if (!private_connection) {
401 /* then we want to connect directly */
403 if (get_options()->HttpProxy) {
404 addr = get_options()->HttpProxyAddr;
405 dir_port = get_options()->HttpProxyPort;
408 switch (connection_connect(conn, conn->address, addr, dir_port)) {
409 case -1:
410 connection_dir_request_failed(conn); /* retry if we want */
411 connection_free(conn);
412 return;
413 case 1:
414 conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
415 /* fall through */
416 case 0:
417 /* queue the command on the outbuf */
418 directory_send_command(conn, platform, purpose, resource,
419 payload, payload_len);
420 connection_watch_events(conn, EV_READ | EV_WRITE);
421 /* writable indicates finish, readable indicates broken link,
422 error indicates broken link in windowsland. */
424 } else { /* we want to connect via tor */
425 /* make an AP connection
426 * populate it and add it at the right state
427 * socketpair and hook up both sides
429 conn->s = connection_ap_make_bridge(conn->address, conn->port);
430 if (conn->s < 0) {
431 warn(LD_NET,"Making AP bridge to dirserver failed.");
432 connection_mark_for_close(conn);
433 return;
436 conn->state = DIR_CONN_STATE_CLIENT_SENDING;
437 connection_add(conn);
438 /* queue the command on the outbuf */
439 directory_send_command(conn, platform, purpose, resource,
440 payload, payload_len);
441 connection_watch_events(conn, EV_READ | EV_WRITE);
445 /** Queue an appropriate HTTP command on conn-\>outbuf. The other args
446 * are as in directory_initiate_command.
448 static void
449 directory_send_command(connection_t *conn, const char *platform,
450 int purpose, const char *resource,
451 const char *payload, size_t payload_len)
453 char proxystring[256];
454 char proxyauthstring[256];
455 char hoststring[128];
456 char *url;
457 char request[8192];
458 const char *httpcommand = NULL;
459 size_t len;
461 tor_assert(conn);
462 tor_assert(conn->type == CONN_TYPE_DIR);
464 tor_free(conn->requested_resource);
465 if (resource)
466 conn->requested_resource = tor_strdup(resource);
468 /* come up with a string for which Host: we want */
469 if (conn->port == 80) {
470 strlcpy(hoststring, conn->address, sizeof(hoststring));
471 } else {
472 tor_snprintf(hoststring, sizeof(hoststring),"%s:%d",conn->address, conn->port);
475 /* come up with some proxy lines, if we're using one. */
476 if (get_options()->HttpProxy) {
477 char *base64_authenticator=NULL;
478 const char *authenticator = get_options()->HttpProxyAuthenticator;
480 tor_snprintf(proxystring, sizeof(proxystring),"http://%s", hoststring);
481 if (authenticator) {
482 base64_authenticator = alloc_http_authenticator(authenticator);
483 if (!base64_authenticator)
484 warn(LD_BUG, "Encoding http authenticator failed");
486 if (base64_authenticator) {
487 tor_snprintf(proxyauthstring, sizeof(proxyauthstring),
488 "\r\nProxy-Authorization: Basic %s",
489 base64_authenticator);
490 tor_free(base64_authenticator);
491 } else {
492 proxyauthstring[0] = 0;
494 } else {
495 proxystring[0] = 0;
496 proxyauthstring[0] = 0;
499 switch (purpose) {
500 case DIR_PURPOSE_FETCH_DIR:
501 tor_assert(!resource);
502 tor_assert(!payload);
503 debug(LD_DIR, "Asking for compressed directory from server running %s",
504 platform?platform:"<unknown version>");
505 httpcommand = "GET";
506 url = tor_strdup("/tor/dir.z");
507 break;
508 case DIR_PURPOSE_FETCH_RUNNING_LIST:
509 tor_assert(!resource);
510 tor_assert(!payload);
511 httpcommand = "GET";
512 url = tor_strdup("/tor/running-routers");
513 break;
514 case DIR_PURPOSE_FETCH_NETWORKSTATUS:
515 httpcommand = "GET";
516 len = strlen(resource)+32;
517 url = tor_malloc(len);
518 tor_snprintf(url, len, "/tor/status/%s", resource);
519 break;
520 case DIR_PURPOSE_FETCH_SERVERDESC:
521 httpcommand = "GET";
522 len = strlen(resource)+32;
523 url = tor_malloc(len);
524 tor_snprintf(url, len, "/tor/server/%s", resource);
525 break;
526 case DIR_PURPOSE_UPLOAD_DIR:
527 tor_assert(!resource);
528 tor_assert(payload);
529 httpcommand = "POST";
530 url = tor_strdup("/tor/");
531 break;
532 case DIR_PURPOSE_FETCH_RENDDESC:
533 tor_assert(resource);
534 tor_assert(!payload);
536 /* this must be true or we wouldn't be doing the lookup */
537 tor_assert(strlen(resource) <= REND_SERVICE_ID_LEN);
538 /* This breaks the function abstraction. */
539 strlcpy(conn->rend_query, resource, sizeof(conn->rend_query));
541 httpcommand = "GET";
542 /* Request the most recent versioned descriptor. */
543 // XXXX011
544 //tor_snprintf(url, sizeof(url), "/tor/rendezvous1/%s", resource);
545 len = strlen(resource)+32;
546 url = tor_malloc(len);
547 tor_snprintf(url, len, "/tor/rendezvous/%s", resource);
548 break;
549 case DIR_PURPOSE_UPLOAD_RENDDESC:
550 tor_assert(!resource);
551 tor_assert(payload);
552 httpcommand = "POST";
553 url = tor_strdup("/tor/rendezvous/publish");
554 break;
555 default:
556 tor_assert(0);
557 return;
559 tor_snprintf(request, sizeof(request), "%s %s", httpcommand, proxystring);
560 connection_write_to_buf(request, strlen(request), conn);
561 connection_write_to_buf(url, strlen(url), conn);
562 tor_free(url);
564 tor_snprintf(request, sizeof(request), " HTTP/1.0\r\nContent-Length: %lu\r\nHost: %s%s\r\n\r\n",
565 payload ? (unsigned long)payload_len : 0,
566 hoststring,
567 proxyauthstring);
568 connection_write_to_buf(request, strlen(request), conn);
570 if (payload) {
571 /* then send the payload afterwards too */
572 connection_write_to_buf(payload, payload_len, conn);
576 /** Parse an HTTP request string <b>headers</b> of the form
577 * \verbatim
578 * "\%s [http[s]://]\%s HTTP/1..."
579 * \endverbatim
580 * If it's well-formed, strdup the second \%s into *<b>url</b>, and
581 * null-terminate it. If the url doesn't start with "/tor/", rewrite it
582 * so it does. Return 0.
583 * Otherwise, return -1.
585 static int
586 parse_http_url(char *headers, char **url)
588 char *s, *start, *tmp;
590 s = (char *)eat_whitespace_no_nl(headers);
591 if (!*s) return -1;
592 s = (char *)find_whitespace(s); /* get past GET/POST */
593 if (!*s) return -1;
594 s = (char *)eat_whitespace_no_nl(s);
595 if (!*s) return -1;
596 start = s; /* this is it, assuming it's valid */
597 s = (char *)find_whitespace(start);
598 if (!*s) return -1;
600 /* tolerate the http[s] proxy style of putting the hostname in the url */
601 if (s-start >= 4 && !strcmpstart(start,"http")) {
602 tmp = start + 4;
603 if (*tmp == 's')
604 tmp++;
605 if (s-tmp >= 3 && !strcmpstart(tmp,"://")) {
606 tmp = strchr(tmp+3, '/');
607 if (tmp && tmp < s) {
608 debug(LD_DIR,"Skipping over 'http[s]://hostname' string");
609 start = tmp;
614 if (s-start < 5 || strcmpstart(start,"/tor/")) { /* need to rewrite it */
615 *url = tor_malloc(s - start + 5);
616 strlcpy(*url,"/tor", s-start+5);
617 strlcat((*url)+4, start, s-start+1);
618 } else {
619 *url = tor_strndup(start, s-start);
621 return 0;
624 /** Return a copy of the first HTTP header in <b>headers</b> whose key is
625 * <b>which</b>. The key should be given with a terminating colon and space;
626 * this function copies everything after, up to but not including the
627 * following \\r\\n. */
628 static char *
629 http_get_header(const char *headers, const char *which)
631 const char *cp = headers;
632 while (cp) {
633 if (!strcmpstart(cp, which)) {
634 char *eos;
635 cp += strlen(which);
636 if ((eos = strchr(cp,'\r')))
637 return tor_strndup(cp, eos-cp);
638 else
639 return tor_strdup(cp);
641 cp = strchr(cp, '\n');
642 if (cp)
643 ++cp;
645 return NULL;
648 /** Allocate and return a string describing the source of an HTTP request with
649 * headers <b>headers</b> received on <b>conn</b>. The format is either
650 * "'1.2.3.4'", or "'1.2.3.4' (forwarded for '5.6.7.8')".
652 static char *
653 http_get_origin(const char *headers, connection_t *conn)
655 char *fwd;
657 fwd = http_get_header(headers, "Forwarded-For: ");
658 if (!fwd)
659 fwd = http_get_header(headers, "X-Forwarded-For: ");
660 if (fwd) {
661 size_t len = strlen(fwd)+strlen(conn->address)+32;
662 char *result = tor_malloc(len);
663 tor_snprintf(result, len, "'%s' (forwarded for '%s')", conn->address, fwd);
664 tor_free(fwd);
665 return result;
666 } else {
667 size_t len = strlen(conn->address)+3;
668 char *result = tor_malloc(len);
669 tor_snprintf(result, len, "'%s'", conn->address);
670 return result;
674 /** Parse an HTTP response string <b>headers</b> of the form
675 * \verbatim
676 * "HTTP/1.\%d \%d\%s\r\n...".
677 * \endverbatim
679 * If it's well-formed, assign the status code to *<b>code</b> and
680 * return 0. Otherwise, return -1.
682 * On success: If <b>date</b> is provided, set *date to the Date
683 * header in the http headers, or 0 if no such header is found. If
684 * <b>compression</b> is provided, set *<b>compression</b> to the
685 * compression method given in the Content-Encoding header, or 0 if no
686 * such header is found, or -1 if the value of the header is not
687 * recognized. If <b>reason</b> is provided, strdup the reason string
688 * into it.
691 parse_http_response(const char *headers, int *code, time_t *date,
692 int *compression, char **reason)
694 int n1, n2;
695 char datestr[RFC1123_TIME_LEN+1];
696 smartlist_t *parsed_headers;
697 tor_assert(headers);
698 tor_assert(code);
700 while (TOR_ISSPACE(*headers)) headers++; /* tolerate leading whitespace */
702 if (sscanf(headers, "HTTP/1.%d %d", &n1, &n2) < 2 ||
703 (n1 != 0 && n1 != 1) ||
704 (n2 < 100 || n2 >= 600)) {
705 warn(LD_HTTP,"Failed to parse header '%s'",headers);
706 return -1;
708 *code = n2;
710 parsed_headers = smartlist_create();
711 smartlist_split_string(parsed_headers, headers, "\n",
712 SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
713 if (reason) {
714 smartlist_t *status_line_elements = smartlist_create();
715 tor_assert(smartlist_len(parsed_headers));
716 smartlist_split_string(status_line_elements,
717 smartlist_get(parsed_headers, 0),
718 " ", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 3);
719 tor_assert(smartlist_len(status_line_elements) <= 3);
720 if (smartlist_len(status_line_elements) == 3) {
721 *reason = smartlist_get(status_line_elements, 2);
722 smartlist_set(status_line_elements, 2, NULL); /* Prevent free */
724 SMARTLIST_FOREACH(status_line_elements, char *, cp, tor_free(cp));
725 smartlist_free(status_line_elements);
727 if (date) {
728 *date = 0;
729 SMARTLIST_FOREACH(parsed_headers, const char *, s,
730 if (!strcmpstart(s, "Date: ")) {
731 strlcpy(datestr, s+6, sizeof(datestr));
732 /* This will do nothing on failure, so we don't need to check
733 the result. We shouldn't warn, since there are many other valid
734 date formats besides the one we use. */
735 parse_rfc1123_time(datestr, date);
736 break;
739 if (compression) {
740 const char *enc = NULL;
741 SMARTLIST_FOREACH(parsed_headers, const char *, s,
742 if (!strcmpstart(s, "Content-Encoding: ")) {
743 enc = s+18; break;
745 if (!enc || !strcmp(enc, "identity")) {
746 *compression = 0;
747 } else if (!strcmp(enc, "deflate") || !strcmp(enc, "x-deflate")) {
748 *compression = ZLIB_METHOD;
749 } else if (!strcmp(enc, "gzip") || !strcmp(enc, "x-gzip")) {
750 *compression = GZIP_METHOD;
751 } else {
752 info(LD_HTTP, "Unrecognized content encoding: '%s'. Trying to deal.", enc);
753 *compression = -1;
756 SMARTLIST_FOREACH(parsed_headers, char *, s, tor_free(s));
757 smartlist_free(parsed_headers);
759 return 0;
762 /** Return true iff <b>body</b> doesn't start with a plausible router or
763 * running-list or directory opening. This is a sign of possible compression.
765 static int
766 body_is_plausible(const char *body, size_t len, int purpose)
768 int i;
769 if (len == 0)
770 return 1; /* empty bodies don't need decompression */
771 if (len < 32)
772 return 0;
773 if (purpose != DIR_PURPOSE_FETCH_RENDDESC) {
774 if (!strcmpstart(body,"router") ||
775 !strcmpstart(body,"signed-directory") ||
776 !strcmpstart(body,"network-status") ||
777 !strcmpstart(body,"running-routers"))
778 return 1;
779 for (i=0;i<32;++i) {
780 if (!TOR_ISPRINT(body[i]) && !TOR_ISSPACE(body[i]))
781 return 0;
783 return 1;
784 } else {
785 return 1;
789 /** We are a client, and we've finished reading the server's
790 * response. Parse and it and act appropriately.
792 * If we're happy with the result (we get it and it's useful),
793 * return 0. Otherwise return -1, and the caller should consider
794 * trying the request again.
796 * The caller will take care of marking the connection for close.
798 static int
799 connection_dir_client_reached_eof(connection_t *conn)
801 char *body;
802 char *headers;
803 char *reason = NULL;
804 size_t body_len=0;
805 int status_code;
806 time_t now, date_header=0;
807 int delta;
808 int compression;
809 int plausible;
810 int skewed=0;
811 int allow_partial = conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC;
813 switch (fetch_from_buf_http(conn->inbuf,
814 &headers, MAX_HEADERS_SIZE,
815 &body, &body_len, MAX_DIR_SIZE,
816 allow_partial)) {
817 case -1: /* overflow */
818 warn(LD_PROTOCOL,"'fetch' response too large (server '%s:%d'). Closing.", conn->address, conn->port);
819 return -1;
820 case 0:
821 info(LD_HTTP,"'fetch' response not all here, but we're at eof. Closing.");
822 return -1;
823 /* case 1, fall through */
826 if (parse_http_response(headers, &status_code, &date_header,
827 &compression, &reason) < 0) {
828 warn(LD_HTTP,"Unparseable headers (server '%s:%d'). Closing.", conn->address, conn->port);
829 tor_free(body); tor_free(headers);
830 return -1;
832 if (!reason) reason = tor_strdup("[no reason given]");
834 debug(LD_DIR,
835 "Received response from directory server '%s:%d': %d \"%s\"",
836 conn->address, conn->port, status_code, reason);
838 if (date_header > 0) {
839 now = time(NULL);
840 delta = now-date_header;
841 if (abs(delta)>ALLOW_DIRECTORY_TIME_SKEW) {
842 log_fn(router_digest_is_trusted_dir(conn->identity_digest) ? LOG_WARN : LOG_INFO,
843 LD_HTTP,
844 "Received directory with skewed time (server '%s:%d'): we are %d minutes %s, or the directory is %d minutes %s.",
845 conn->address, conn->port,
846 abs(delta)/60, delta>0 ? "ahead" : "behind",
847 abs(delta)/60, delta>0 ? "behind" : "ahead");
848 skewed = 1; /* don't check the recommended-versions line */
849 } else {
850 debug(LD_HTTP, "Time on received directory is within tolerance; we are %d seconds skewed. (That's okay.)", delta);
854 plausible = body_is_plausible(body, body_len, conn->purpose);
855 if (compression || !plausible) {
856 char *new_body = NULL;
857 size_t new_len = 0;
858 int guessed = detect_compression_method(body, body_len);
859 if (compression <= 0 || guessed != compression) {
860 /* Tell the user if we don't believe what we're told about compression.*/
861 const char *description1, *description2;
862 if (compression == ZLIB_METHOD)
863 description1 = "as deflated";
864 else if (compression == GZIP_METHOD)
865 description1 = "as gzipped";
866 else if (compression == 0)
867 description1 = "as uncompressed";
868 else
869 description1 = "with an unknown Content-Encoding";
870 if (guessed == ZLIB_METHOD)
871 description2 = "deflated";
872 else if (guessed == GZIP_METHOD)
873 description2 = "gzipped";
874 else if (!plausible)
875 description2 = "confusing binary junk";
876 else
877 description2 = "uncompressed";
879 info(LD_HTTP, "HTTP body from server '%s:%d' was labeled %s, "
880 "but it seems to be %s.%s",
881 conn->address, conn->port, description1, description2,
882 (compression>0 && guessed>0)?" Trying both.":"");
884 /* Try declared compression first if we can. */
885 if (compression > 0)
886 tor_gzip_uncompress(&new_body, &new_len, body, body_len, compression,
887 allow_partial);
888 /* Okay, if that didn't work, and we think that it was compressed
889 * differently, try that. */
890 if (!new_body && guessed > 0 && compression != guessed)
891 tor_gzip_uncompress(&new_body, &new_len, body, body_len, guessed,
892 allow_partial);
893 /* If we're pretty sure that we have a compressed directory, and
894 * we didn't manage to uncompress it, then warn and bail. */
895 if (!plausible && !new_body) {
896 warn(LD_HTTP, "Unable to decompress HTTP body (server '%s:%d').",
897 conn->address, conn->port);
898 tor_free(body); tor_free(headers); tor_free(reason);
899 return -1;
901 if (new_body) {
902 tor_free(body);
903 body = new_body;
904 body_len = new_len;
908 if (conn->purpose == DIR_PURPOSE_FETCH_DIR) {
909 /* fetch/process the directory to learn about new routers. */
910 info(LD_DIR,"Received directory (size %d) from server '%s:%d'",
911 (int)body_len, conn->address, conn->port);
912 if (status_code == 503 || body_len == 0) {
913 info(LD_DIR,"Empty directory; status %d (\"%s\") Ignoring.",
914 status_code, reason);
915 tor_free(body); tor_free(headers); tor_free(reason);
916 return -1;
918 if (status_code != 200) {
919 warn(LD_DIR,"Received http status code %d (\"%s\") from server '%s:%d'. I'll try again soon.",
920 status_code, reason, conn->address, conn->port);
921 tor_free(body); tor_free(headers); tor_free(reason);
922 return -1;
924 if (router_parse_directory(body) < 0) {
925 notice(LD_DIR,"I failed to parse the directory I fetched from '%s:%d'. Ignoring.", conn->address, conn->port);
929 if (conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
930 /* just update our list of running routers, if this list is new info */
931 info(LD_DIR,"Received running-routers list (size %d)", (int)body_len);
932 if (status_code != 200) {
933 warn(LD_DIR,"Received http status code %d (\"%s\") from server '%s:%d'. I'll try again soon.",
934 status_code, reason, conn->address, conn->port);
935 tor_free(body); tor_free(headers); tor_free(reason);
936 return -1;
938 if (router_parse_runningrouters(body)<0) {
939 warn(LD_DIR,"Bad running-routers from server '%s:%d'. I'll try again soon.",
940 conn->address, conn->port);
941 tor_free(body); tor_free(headers); tor_free(reason);
942 return -1;
946 if (conn->purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) {
947 smartlist_t *which = NULL;
948 char *cp;
949 info(LD_DIR,"Received networkstatus objects (size %d) from server '%s:%d'",(int) body_len, conn->address, conn->port);
950 if (status_code != 200) {
951 warn(LD_DIR,"Received http status code %d (\"%s\") from server '%s:%d' while fetching \"/tor/status/%s\". I'll try again soon.",
952 status_code, reason, conn->address, conn->port,
953 conn->requested_resource);
954 tor_free(body); tor_free(headers); tor_free(reason);
955 connection_dir_download_networkstatus_failed(conn);
956 return -1;
958 if (conn->requested_resource &&
959 !strcmpstart(conn->requested_resource,"fp/")) {
960 which = smartlist_create();
961 dir_split_resource_into_fingerprints(conn->requested_resource+3,
962 which, NULL, 0);
964 cp = body;
965 while (*cp) {
966 char *next = strstr(cp, "\nnetwork-status-version");
967 if (next)
968 next[1] = '\0';
969 /* learn from it, and then remove it from 'which' */
970 if (router_set_networkstatus(cp, time(NULL), NS_FROM_DIR, which)<0)
971 break;
972 if (next) {
973 next[1] = 'n';
974 cp = next+1;
976 else
977 break;
979 routers_update_all_from_networkstatus(); /*launches router downloads*/
980 directory_info_has_arrived(time(NULL), 0);
981 if (which) {
982 if (smartlist_len(which)) {
983 dir_networkstatus_download_failed(which);
985 SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
986 smartlist_free(which);
990 if (conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC) {
991 smartlist_t *which = NULL;
992 int n_asked_for = 0;
993 info(LD_DIR,"Received server info (size %d) from server '%s:%d'",
994 (int)body_len, conn->address, conn->port);
995 if (conn->requested_resource &&
996 !strcmpstart(conn->requested_resource,"fp/")) {
997 which = smartlist_create();
998 dir_split_resource_into_fingerprints(conn->requested_resource+3,
999 which, NULL, 0);
1000 n_asked_for = smartlist_len(which);
1002 if (status_code != 200) {
1003 int no_warn = status_code == 404 ||
1004 (status_code == 400 && !strcmp(reason, "Servers unavailable."));
1005 /* 404 means that it didn't have them; no big deal.
1006 * Older (pre-0.1.1.8) servers said 400 Servers unavailable instead. */
1007 log_fn(no_warn ? LOG_INFO : LOG_WARN, LD_DIR,
1008 "Received http status code %d (\"%s\") from server '%s:%d' while fetching \"/tor/server/%s\". I'll try again soon.",
1009 status_code, reason, conn->address, conn->port,
1010 conn->requested_resource);
1011 if (!which) {
1012 connection_dir_download_routerdesc_failed(conn);
1013 } else {
1014 dir_routerdesc_download_failed(which);
1015 SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
1016 smartlist_free(which);
1018 tor_free(body); tor_free(headers); tor_free(reason);
1019 return -1;
1021 /* Learn the routers, assuming we requested by fingerprint or "all".
1022 * Right now, we only use "authority" to fetch ourself, so we don't want
1023 * to risk replacing ourself with a router running at the addr:port we
1024 * think we have.
1026 if (which || (conn->requested_resource &&
1027 !strcmpstart(conn->requested_resource, "all"))) {
1028 /* as we learn from them, we remove them from 'which' */
1029 router_load_routers_from_string(body, 0, which);
1030 directory_info_has_arrived(time(NULL), 0);
1032 if (which) { /* mark remaining ones as failed */
1033 info(LD_DIR, "Received %d/%d routers requested from %s:%d",
1034 n_asked_for-smartlist_len(which), n_asked_for,
1035 conn->address, (int)conn->port);
1036 if (smartlist_len(which)) {
1037 dir_routerdesc_download_failed(which);
1039 SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
1040 smartlist_free(which);
1042 if (conn->requested_resource &&
1043 !strcmpstart(conn->requested_resource,"authority")) {
1044 /* this might have been a dirport reachability test. see if it is. */
1045 routerinfo_t *me = router_get_my_routerinfo();
1046 if (me &&
1047 router_digest_is_me(conn->identity_digest) &&
1048 me->addr == conn->addr &&
1049 me->dir_port == conn->port)
1050 router_dirport_found_reachable();
1054 if (conn->purpose == DIR_PURPOSE_UPLOAD_DIR) {
1055 switch (status_code) {
1056 case 200:
1057 info(LD_GENERAL,"eof (status 200) after uploading server descriptor: finished.");
1058 break;
1059 case 400:
1060 warn(LD_GENERAL,"http status 400 (\"%s\") response from dirserver '%s:%d'. Please correct.", reason, conn->address, conn->port);
1061 break;
1062 case 403:
1063 warn(LD_GENERAL,"http status 403 (\"%s\") response from dirserver "
1064 "'%s:%d'. Is your clock skewed? Have you mailed us your key "
1065 "fingerprint? Are you using the right key? Are you using a "
1066 "private IP address? See http://tor.eff.org/doc/"
1067 "tor-doc-server.html", reason, conn->address, conn->port);
1068 break;
1069 default:
1070 warn(LD_GENERAL,"http status %d (\"%s\") reason unexpected (server '%s:%d').", status_code, reason, conn->address, conn->port);
1071 break;
1073 /* return 0 in all cases, since we don't want to mark any
1074 * dirservers down just because they don't like us. */
1077 if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC) {
1078 info(LD_REND,"Received rendezvous descriptor (size %d, status %d (\"%s\"))",
1079 (int)body_len, status_code, reason);
1080 switch (status_code) {
1081 case 200:
1082 if (rend_cache_store(body, body_len) < 0) {
1083 warn(LD_REND,"Failed to store rendezvous descriptor.");
1084 /* alice's ap_stream will notice when connection_mark_for_close
1085 * cleans it up */
1086 } else {
1087 /* success. notify pending connections about this. */
1088 conn->purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
1089 rend_client_desc_here(conn->rend_query);
1091 break;
1092 case 404:
1093 /* not there. pending connections will be notified when
1094 * connection_mark_for_close cleans it up. */
1095 break;
1096 case 400:
1097 warn(LD_REND,"http status 400 (\"%s\"). Dirserver didn't like our rendezvous query?", reason);
1098 break;
1099 default:
1100 warn(LD_REND,"http status %d (\"%s\") response unexpected (server '%s:%d').", status_code, reason, conn->address, conn->port);
1101 break;
1105 if (conn->purpose == DIR_PURPOSE_UPLOAD_RENDDESC) {
1106 switch (status_code) {
1107 case 200:
1108 info(LD_REND,"Uploading rendezvous descriptor: finished with status 200 (\"%s\")", reason);
1109 break;
1110 case 400:
1111 warn(LD_REND,"http status 400 (\"%s\") response from dirserver '%s:%d'. Malformed rendezvous descriptor?", reason, conn->address, conn->port);
1112 break;
1113 default:
1114 warn(LD_REND,"http status %d (\"%s\") response unexpected (server '%s:%d').", status_code, reason, conn->address, conn->port);
1115 break;
1118 tor_free(body); tor_free(headers); tor_free(reason);
1119 return 0;
1122 /** Called when a directory connection reaches EOF */
1124 connection_dir_reached_eof(connection_t *conn)
1126 int retval;
1127 if (conn->state != DIR_CONN_STATE_CLIENT_READING) {
1128 info(LD_HTTP,"conn reached eof, not reading. Closing.");
1129 /* This check is temporary; it's to let us know whether we should consider
1130 * parsing partial serverdesc responses. */
1131 if (conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC &&
1132 buf_datalen(conn->inbuf)>=(24*1024)) {
1133 notice(LD_DIR, "Directory connection closed early after downloading %d bytes of descriptors. If this happens often, please file a bug report.",
1134 (int)buf_datalen(conn->inbuf));
1136 connection_close_immediate(conn); /* it was an error; give up on flushing */
1137 connection_mark_for_close(conn);
1138 return -1;
1141 retval = connection_dir_client_reached_eof(conn);
1142 if (retval == 0) /* success */
1143 conn->state = DIR_CONN_STATE_CLIENT_FINISHED;
1144 connection_mark_for_close(conn);
1145 return retval;
1148 /** Read handler for directory connections. (That's connections <em>to</em>
1149 * directory servers and connections <em>at</em> directory servers.)
1152 connection_dir_process_inbuf(connection_t *conn)
1154 tor_assert(conn);
1155 tor_assert(conn->type == CONN_TYPE_DIR);
1157 /* Directory clients write, then read data until they receive EOF;
1158 * directory servers read data until they get an HTTP command, then
1159 * write their response (when it's finished flushing, they mark for
1160 * close).
1163 /* If we're on the dirserver side, look for a command. */
1164 if (conn->state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
1165 if (directory_handle_command(conn) < 0) {
1166 connection_mark_for_close(conn);
1167 return -1;
1169 return 0;
1172 /* XXX for READ states, might want to make sure inbuf isn't too big */
1174 debug(LD_HTTP,"Got data, not eof. Leaving on inbuf.");
1175 return 0;
1178 /** Create an http response for the client <b>conn</b> out of
1179 * <b>status</b> and <b>reason_phrase</b>. Write it to <b>conn</b>.
1181 static void
1182 write_http_status_line(connection_t *conn, int status,
1183 const char *reason_phrase)
1185 char buf[256];
1186 if (tor_snprintf(buf, sizeof(buf), "HTTP/1.0 %d %s\r\n\r\n",
1187 status, reason_phrase) < 0) {
1188 warn(LD_BUG,"Bug: status line too long.");
1189 return;
1191 connection_write_to_buf(buf, strlen(buf), conn);
1194 /** Helper function: return 1 if there are any dir conns of purpose
1195 * <b>purpose</b> that are going elsewhere than our own ORPort/Dirport.
1196 * Else return 0.
1198 static int
1199 already_fetching_directory(int purpose)
1201 int i, n;
1202 connection_t *conn;
1203 connection_t **carray;
1205 get_connection_array(&carray,&n);
1206 for (i=0;i<n;i++) {
1207 conn = carray[i];
1208 if (conn->type == CONN_TYPE_DIR &&
1209 conn->purpose == purpose &&
1210 !conn->marked_for_close &&
1211 !router_digest_is_me(conn->identity_digest))
1212 return 1;
1214 return 0;
1217 /** Helper function: called when a dirserver gets a complete HTTP GET
1218 * request. Look for a request for a directory or for a rendezvous
1219 * service descriptor. On finding one, write a response into
1220 * conn-\>outbuf. If the request is unrecognized, send a 400.
1221 * Always return 0. */
1222 static int
1223 directory_handle_command_get(connection_t *conn, char *headers,
1224 char *body, size_t body_len)
1226 size_t dlen;
1227 const char *cp;
1228 char *url = NULL;
1229 char tmp[8192];
1230 char date[RFC1123_TIME_LEN+1];
1232 debug(LD_DIRSERV,"Received GET command.");
1234 conn->state = DIR_CONN_STATE_SERVER_WRITING;
1236 if (parse_http_url(headers, &url) < 0) {
1237 write_http_status_line(conn, 400, "Bad request");
1238 return 0;
1240 debug(LD_DIRSERV,"rewritten url as '%s'.", url);
1242 if (!strcmp(url,"/tor/") || !strcmp(url,"/tor/dir.z")) { /* directory fetch */
1243 int deflated = !strcmp(url,"/tor/dir.z");
1244 dlen = dirserv_get_directory(&cp, deflated);
1246 tor_free(url);
1248 if (dlen == 0) {
1249 notice(LD_DIRSERV,"Client asked for the mirrored directory, but we don't have a good one yet. Sending 503 Dir not available.");
1250 write_http_status_line(conn, 503, "Directory unavailable");
1251 /* try to get a new one now */
1252 if (!already_fetching_directory(DIR_PURPOSE_FETCH_DIR))
1253 directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 1);
1254 return 0;
1257 debug(LD_DIRSERV,"Dumping %sdirectory to client.",
1258 deflated?"deflated ":"");
1259 format_rfc1123_time(date, time(NULL));
1260 tor_snprintf(tmp, sizeof(tmp), "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\nContent-Type: %s\r\nContent-Encoding: %s\r\n\r\n",
1261 date,
1262 (int)dlen,
1263 deflated?"application/octet-stream":"text/plain",
1264 deflated?"deflate":"identity");
1265 connection_write_to_buf(tmp, strlen(tmp), conn);
1266 connection_write_to_buf(cp, dlen, conn);
1267 return 0;
1270 if (!strcmp(url,"/tor/running-routers") ||
1271 !strcmp(url,"/tor/running-routers.z")) { /* running-routers fetch */
1272 int deflated = !strcmp(url,"/tor/running-routers.z");
1273 tor_free(url);
1274 dlen = dirserv_get_runningrouters(&cp, deflated);
1275 if (!dlen) { /* we failed to create/cache cp */
1276 write_http_status_line(conn, 503, "Directory unavailable");
1277 /* try to get a new one now */
1278 if (!already_fetching_directory(DIR_PURPOSE_FETCH_RUNNING_LIST))
1279 directory_get_from_dirserver(DIR_PURPOSE_FETCH_RUNNING_LIST, NULL, 1);
1280 return 0;
1283 format_rfc1123_time(date, time(NULL));
1284 tor_snprintf(tmp, sizeof(tmp), "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\nContent-Type: %s\r\nContent-Encoding: %s\r\n\r\n",
1285 date,
1286 (int)dlen,
1287 deflated?"application/octet-stream":"text/plain",
1288 deflated?"deflate":"identity");
1289 connection_write_to_buf(tmp, strlen(tmp), conn);
1290 connection_write_to_buf(cp, strlen(cp), conn);
1291 return 0;
1294 if (!strcmpstart(url,"/tor/status/")) {
1295 /* v2 network status fetch. */
1296 size_t url_len = strlen(url);
1297 int deflated = !strcmp(url+url_len-2, ".z");
1298 smartlist_t *dir_objs = smartlist_create();
1299 const char *key = url + strlen("/tor/status/");
1300 if (deflated)
1301 url[url_len-2] = '\0';
1302 if (dirserv_get_networkstatus_v2(dir_objs, key)) {
1303 smartlist_free(dir_objs);
1304 return 0;
1306 tor_free(url);
1307 if (!smartlist_len(dir_objs)) { /* we failed to create/cache cp */
1308 write_http_status_line(conn, 503, "Network status object unavailable");
1309 smartlist_free(dir_objs);
1310 return 0;
1312 dlen = 0;
1313 SMARTLIST_FOREACH(dir_objs, cached_dir_t *, d,
1314 dlen += deflated?d->dir_z_len:d->dir_len);
1315 format_rfc1123_time(date, time(NULL));
1316 tor_snprintf(tmp, sizeof(tmp), "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\nContent-Type: %s\r\nContent-Encoding: %s\r\n\r\n",
1317 date,
1318 (int)dlen,
1319 deflated?"application/octet-stream":"text/plain",
1320 deflated?"deflate":"identity");
1321 connection_write_to_buf(tmp, strlen(tmp), conn);
1322 SMARTLIST_FOREACH(dir_objs, cached_dir_t *, d,
1324 if (deflated)
1325 connection_write_to_buf(d->dir_z, d->dir_z_len, conn);
1326 else
1327 connection_write_to_buf(d->dir, d->dir_len, conn);
1329 smartlist_free(dir_objs);
1330 return 0;
1333 if (!strcmpstart(url,"/tor/server/")) {
1334 size_t url_len = strlen(url);
1335 int deflated = !strcmp(url+url_len-2, ".z");
1336 int res;
1337 const char *msg;
1338 smartlist_t *descs = smartlist_create();
1339 if (deflated)
1340 url[url_len-2] = '\0';
1341 res = dirserv_get_routerdescs(descs, url, &msg);
1342 tor_free(url);
1343 if (res < 0)
1344 write_http_status_line(conn, 404, msg);
1345 else {
1346 size_t len = 0;
1347 format_rfc1123_time(date, time(NULL));
1348 SMARTLIST_FOREACH(descs, signed_descriptor_t *, ri,
1349 len += ri->signed_descriptor_len);
1350 if (deflated) {
1351 size_t compressed_len;
1352 char *compressed;
1353 char *inp = tor_malloc(len+smartlist_len(descs)+1);
1354 char *cp = inp;
1355 SMARTLIST_FOREACH(descs, signed_descriptor_t *, ri,
1357 memcpy(cp, ri->signed_descriptor,
1358 ri->signed_descriptor_len);
1359 cp += ri->signed_descriptor_len;
1360 *cp++ = '\n';
1362 *cp = '\0';
1363 /* XXXX This could be way more efficiently handled; let's see if it
1364 * shows up under oprofile. */
1365 if (tor_gzip_compress(&compressed, &compressed_len,
1366 inp, cp-inp, ZLIB_METHOD)<0) {
1367 tor_free(inp);
1368 smartlist_free(descs);
1369 return -1;
1371 tor_free(inp);
1372 tor_snprintf(tmp, sizeof(tmp),
1373 "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n"
1374 "Content-Type: application/octet-stream\r\n"
1375 "Content-Encoding: deflate\r\n\r\n",
1376 date,
1377 (int)compressed_len);
1378 connection_write_to_buf(tmp, strlen(tmp), conn);
1379 connection_write_to_buf(compressed, compressed_len, conn);
1380 tor_free(compressed);
1381 } else {
1382 tor_snprintf(tmp, sizeof(tmp),
1383 "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n"
1384 "Content-Type: text/plain\r\n\r\n",
1385 date,
1386 (int)len);
1387 connection_write_to_buf(tmp, strlen(tmp), conn);
1388 SMARTLIST_FOREACH(descs, signed_descriptor_t *, ri,
1389 connection_write_to_buf(ri->signed_descriptor,
1390 ri->signed_descriptor_len,
1391 conn));
1394 smartlist_free(descs);
1395 return 0;
1398 if (!strcmpstart(url,"/tor/rendezvous/") ||
1399 !strcmpstart(url,"/tor/rendezvous1/")) {
1400 /* rendezvous descriptor fetch */
1401 const char *descp;
1402 size_t desc_len;
1403 int versioned = !strcmpstart(url,"/tor/rendezvous1/");
1404 const char *query = url+strlen("/tor/rendezvous/")+(versioned?1:0);
1406 if (!authdir_mode(get_options())) {
1407 /* We don't hand out rend descs. In fact, it could be a security
1408 * risk, since rend_cache_lookup_desc() below would provide it
1409 * if we're gone to the site recently, and 404 if we haven't.
1411 * Reject. */
1412 write_http_status_line(conn, 400, "Nonauthoritative directory does not not store rendezvous descriptors");
1413 tor_free(url);
1414 return 0;
1416 switch (rend_cache_lookup_desc(query, versioned?-1:0, &descp, &desc_len)) {
1417 case 1: /* valid */
1418 format_rfc1123_time(date, time(NULL));
1419 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",
1420 date,
1421 (int)desc_len); /* can't include descp here, because it's got nuls */
1422 connection_write_to_buf(tmp, strlen(tmp), conn);
1423 connection_write_to_buf(descp, desc_len, conn);
1424 break;
1425 case 0: /* well-formed but not present */
1426 write_http_status_line(conn, 404, "Not found");
1427 break;
1428 case -1: /* not well-formed */
1429 write_http_status_line(conn, 400, "Bad request");
1430 break;
1432 tor_free(url);
1433 return 0;
1436 /* we didn't recognize the url */
1437 write_http_status_line(conn, 404, "Not found");
1438 tor_free(url);
1439 return 0;
1442 /** Helper function: called when a dirserver gets a complete HTTP POST
1443 * request. Look for an uploaded server descriptor or rendezvous
1444 * service descriptor. On finding one, process it and write a
1445 * response into conn-\>outbuf. If the request is unrecognized, send a
1446 * 400. Always return 0. */
1447 static int
1448 directory_handle_command_post(connection_t *conn, char *headers,
1449 char *body, size_t body_len)
1451 const char *cp;
1452 char *origin = NULL;
1453 char *url = NULL;
1455 debug(LD_DIRSERV,"Received POST command.");
1457 conn->state = DIR_CONN_STATE_SERVER_WRITING;
1459 if (!authdir_mode(get_options())) {
1460 /* we just provide cached directories; we don't want to
1461 * receive anything. */
1462 write_http_status_line(conn, 400, "Nonauthoritative directory does not accept posted server descriptors");
1463 return 0;
1466 if (parse_http_url(headers, &url) < 0) {
1467 write_http_status_line(conn, 400, "Bad request");
1468 return 0;
1470 debug(LD_DIRSERV,"rewritten url as '%s'.", url);
1471 origin = http_get_origin(headers, conn);
1473 if (!strcmp(url,"/tor/")) { /* server descriptor post */
1474 const char *msg;
1475 int r = dirserv_add_descriptor(body, &msg);
1476 tor_assert(msg);
1477 if (r > 0)
1478 dirserv_get_directory(&cp, 0); /* rebuild and write to disk */
1479 switch (r) {
1480 case -2:
1481 case -1:
1482 case 1:
1483 notice(LD_DIRSERV,"Rejected descriptor from %s.", origin);
1484 /* malformed descriptor, or something wrong */
1485 write_http_status_line(conn, 400, msg);
1486 break;
1487 case 0: /* accepted but discarded */
1488 case 2: /* accepted */
1489 write_http_status_line(conn, 200, msg);
1490 break;
1492 goto done;
1495 if (!strcmpstart(url,"/tor/rendezvous/publish")) {
1496 /* rendezvous descriptor post */
1497 if (rend_cache_store(body, body_len) < 0)
1498 write_http_status_line(conn, 400, "Invalid service descriptor rejected");
1499 else
1500 write_http_status_line(conn, 200, "Service descriptor stored");
1501 goto done;
1504 /* we didn't recognize the url */
1505 write_http_status_line(conn, 404, "Not found");
1507 done:
1508 tor_free(url);
1509 tor_free(origin);
1510 return 0;
1514 /** Called when a dirserver receives data on a directory connection;
1515 * looks for an HTTP request. If the request is complete, remove it
1516 * from the inbuf, try to process it; otherwise, leave it on the
1517 * buffer. Return a 0 on success, or -1 on error.
1519 static int
1520 directory_handle_command(connection_t *conn)
1522 char *headers=NULL, *body=NULL;
1523 size_t body_len=0;
1524 int r;
1526 tor_assert(conn);
1527 tor_assert(conn->type == CONN_TYPE_DIR);
1529 switch (fetch_from_buf_http(conn->inbuf,
1530 &headers, MAX_HEADERS_SIZE,
1531 &body, &body_len, MAX_BODY_SIZE, 0)) {
1532 case -1: /* overflow */
1533 warn(LD_DIRSERV,
1534 "Invalid input from address '%s'. Closing.", conn->address);
1535 return -1;
1536 case 0:
1537 debug(LD_DIRSERV,"command not all here yet.");
1538 return 0;
1539 /* case 1, fall through */
1542 debug(LD_DIRSERV,"headers '%s', body '%s'.", headers, body);
1544 if (!strncasecmp(headers,"GET",3))
1545 r = directory_handle_command_get(conn, headers, body, body_len);
1546 else if (!strncasecmp(headers,"POST",4))
1547 r = directory_handle_command_post(conn, headers, body, body_len);
1548 else {
1549 warn(LD_PROTOCOL,"Got headers '%s' with unknown command. Closing.", headers);
1550 r = -1;
1553 tor_free(headers); tor_free(body);
1554 return r;
1557 /** Write handler for directory connections; called when all data has
1558 * been flushed. Close the connection or wait for a response as
1559 * appropriate.
1562 connection_dir_finished_flushing(connection_t *conn)
1564 tor_assert(conn);
1565 tor_assert(conn->type == CONN_TYPE_DIR);
1567 switch (conn->state) {
1568 case DIR_CONN_STATE_CLIENT_SENDING:
1569 debug(LD_DIR,"client finished sending command.");
1570 conn->state = DIR_CONN_STATE_CLIENT_READING;
1571 connection_stop_writing(conn);
1572 return 0;
1573 case DIR_CONN_STATE_SERVER_WRITING:
1574 debug(LD_DIRSERV,"Finished writing server response. Closing.");
1575 connection_mark_for_close(conn);
1576 return 0;
1577 default:
1578 warn(LD_BUG,"Bug: called in unexpected state %d.", conn->state);
1579 tor_fragile_assert();
1580 return -1;
1582 return 0;
1585 /** Connected handler for directory connections: begin sending data to the
1586 * server */
1588 connection_dir_finished_connecting(connection_t *conn)
1590 tor_assert(conn);
1591 tor_assert(conn->type == CONN_TYPE_DIR);
1592 tor_assert(conn->state == DIR_CONN_STATE_CONNECTING);
1594 debug(LD_HTTP,"Dir connection to router %s:%u established.",
1595 conn->address,conn->port);
1597 conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
1598 return 0;
1601 /** Called when one or more networkstatus fetches have failed (with uppercase
1602 * fingerprints listed in <b>failed</>). Mark those fingerprints has having
1603 * failed once. */
1604 static void
1605 dir_networkstatus_download_failed(smartlist_t *failed)
1607 SMARTLIST_FOREACH(failed, const char *, fp,
1609 char digest[DIGEST_LEN];
1610 trusted_dir_server_t *dir;
1611 base16_decode(digest, DIGEST_LEN, fp, strlen(fp));
1612 dir = router_get_trusteddirserver_by_digest(digest);
1614 if (dir)
1615 ++dir->n_networkstatus_failures;
1619 /** Called when one or more networkstatus fetches have failed (with uppercase
1620 * fingerprints listed in <b>failed</>). */
1621 static void
1622 dir_routerdesc_download_failed(smartlist_t *failed)
1624 char digest[DIGEST_LEN];
1625 local_routerstatus_t *rs;
1626 time_t now = time(NULL);
1627 int server = server_mode(get_options()) && get_options()->DirPort;
1628 SMARTLIST_FOREACH(failed, const char *, cp,
1630 base16_decode(digest, DIGEST_LEN, cp, strlen(cp));
1631 rs = router_get_combined_status_by_digest(digest);
1632 if (!rs || rs->n_download_failures >= MAX_ROUTERDESC_DOWNLOAD_FAILURES)
1633 continue;
1634 ++rs->n_download_failures;
1635 if (server) {
1636 switch (rs->n_download_failures) {
1637 case 1: rs->next_attempt_at = 0; break;
1638 case 2: rs->next_attempt_at = 0; break;
1639 case 3: rs->next_attempt_at = now+60; break;
1640 case 4: rs->next_attempt_at = now+60; break;
1641 case 5: rs->next_attempt_at = now+60*2; break;
1642 case 6: rs->next_attempt_at = now+60*5; break;
1643 case 7: rs->next_attempt_at = now+60*15; break;
1644 default: rs->next_attempt_at = TIME_MAX; break;
1646 } else {
1647 switch (rs->n_download_failures) {
1648 case 1: rs->next_attempt_at = 0; break;
1649 case 2: rs->next_attempt_at = now+60; break;
1650 case 3: rs->next_attempt_at = now+60*5; break;
1651 case 4: rs->next_attempt_at = now+60*10; break;
1652 default: rs->next_attempt_at = TIME_MAX; break;
1655 if (rs->next_attempt_at == 0)
1656 debug(LD_DIR, "%s failed %d time(s); I'll try again immediately.",
1657 cp, (int)rs->n_download_failures);
1658 else if (rs->next_attempt_at < TIME_MAX)
1659 debug(LD_DIR, "%s failed %d time(s); I'll try again in %d seconds.",
1660 cp, (int)rs->n_download_failures, (int)(rs->next_attempt_at-now));
1661 else
1662 debug(LD_DIR, "%s failed %d time(s); Giving up for a while.",
1663 cp, (int)rs->n_download_failures);
1666 /* update_router_descriptor_downloads(time(NULL)); */
1669 /* Given a directory <b>resource</b> request generated by us, containing zero
1670 * or more strings separated by plus signs, followed optionally by ".z", store
1671 * the strings, in order, into <b>fp_out</b>. If <b>compressed_out</b> is
1672 * non-NULL, set it to 1 if the resource ends in ".z", else set it to 0. If
1673 * decode_hex is true, then delete all elements that aren't hex digests, and
1674 * decode the rest.
1677 dir_split_resource_into_fingerprints(const char *resource,
1678 smartlist_t *fp_out, int *compressed_out,
1679 int decode_hex)
1681 int old_len;
1682 tor_assert(fp_out);
1683 old_len = smartlist_len(fp_out);
1684 smartlist_split_string(fp_out, resource, "+", 0, 0);
1685 if (compressed_out)
1686 *compressed_out = 0;
1687 if (smartlist_len(fp_out) > old_len) {
1688 char *last = smartlist_get(fp_out,smartlist_len(fp_out)-1);
1689 size_t last_len = strlen(last);
1690 if (last_len > 2 && !strcmp(last+last_len-2, ".z")) {
1691 last[last_len-2] = '\0';
1692 if (compressed_out)
1693 *compressed_out = 1;
1696 if (decode_hex) {
1697 int i;
1698 char *cp, *d = NULL;
1699 for (i = old_len; i < smartlist_len(fp_out); ++i) {
1700 cp = smartlist_get(fp_out, i);
1701 if (strlen(cp) != HEX_DIGEST_LEN) {
1702 info(LD_DIR, "Skipping digest \"%s\" with non-standard length.", cp);
1703 smartlist_del(fp_out, i--);
1704 goto again;
1706 d = tor_malloc_zero(DIGEST_LEN);
1707 if (base16_decode(d, DIGEST_LEN, cp, HEX_DIGEST_LEN)<0) {
1708 info(LD_DIR, "Skipping non-decodable digest \"%s\"", cp);
1709 smartlist_del(fp_out, i--);
1710 goto again;
1712 smartlist_set(fp_out, i, d);
1713 d = NULL;
1714 again:
1715 tor_free(cp);
1716 tor_free(d);
1719 return 0;