1 /* Copyright 2001-2004 Roger Dingledine.
2 * Copyright 2004-2005 Roger Dingledine, Nick Mathewson. */
3 /* See LICENSE for licensing information */
5 const char directory_c_id
[] = "$Id$";
11 * \brief Implement directory HTTP protocol.
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
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
32 directory_initiate_command_trusted_dir(trusted_dir_server_t
*dirserv
,
33 uint8_t purpose
, int private_connection
,
35 const char *payload
, size_t payload_len
);
37 directory_initiate_command(const char *address
, uint32_t addr
, uint16_t port
,
39 const char *digest
, uint8_t purpose
,
40 int private_connection
, const char *resource
,
41 const char *payload
, size_t payload_len
);
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/";
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.
71 parse_dir_policy(void)
75 addr_policy_free(dir_policy
);
78 config_parse_addr_policy(get_options()->DirPolicy
, &dir_policy
);
79 /* ports aren't used. */
80 for (n
=dir_policy
; n
; n
= n
->next
) {
89 addr_policy_free(dir_policy
);
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
)
100 if (!dir_policy
) /* 'no dir policy' means 'accept' */
102 a
= router_compare_addr_to_addr_policy(addr
, 1, dir_policy
);
103 if (a
==ADDR_POLICY_REJECTED
)
105 else if (a
==ADDR_POLICY_ACCEPTED
)
107 log_fn(LOG_WARN
, "Bug: got unexpected 'maybe' answer from dir policy");
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
)
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'.
126 directory_post_to_dirservers(uint8_t purpose
, const char *payload
,
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
))
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.
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
);
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
);
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
);
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
);
196 directory_initiate_command_router(r
, purpose
, priv
, resource
, NULL
, 0);
198 directory_initiate_command_trusted_dir(ds
, purpose
, priv
, resource
, NULL
, 0);
200 log_fn(LOG_NOTICE
,"No running dirservers known. Not trying. (purpose %d)",
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
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>. **/
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.
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",
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. */
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
)
276 tor_assert(dir_port
);
280 case DIR_PURPOSE_FETCH_DIR
:
281 log_fn(LOG_DEBUG
,"initiating directory fetch");
283 case DIR_PURPOSE_FETCH_RENDDESC
:
284 log_fn(LOG_DEBUG
,"initiating hidden-service descriptor fetch");
286 case DIR_PURPOSE_UPLOAD_DIR
:
287 log_fn(LOG_DEBUG
,"initiating server descriptor upload");
289 case DIR_PURPOSE_UPLOAD_RENDDESC
:
290 log_fn(LOG_DEBUG
,"initiating hidden-service descriptor upload");
292 case DIR_PURPOSE_FETCH_RUNNING_LIST
:
293 log_fn(LOG_DEBUG
,"initiating running-routers fetch");
296 log_fn(LOG_ERR
, "Unrecognized directory connection purpose.");
300 conn
= connection_new(CONN_TYPE_DIR
);
302 /* set up conn so it's got all the data we need to remember */
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
)) {
323 connection_dir_connect_failed(conn
);
324 connection_free(conn
);
327 conn
->state
= DIR_CONN_STATE_CLIENT_SENDING
; /* start flushing conn */
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
);
344 log_fn(LOG_WARN
,"Making AP bridge to dirserver failed.");
345 connection_mark_for_close(conn
);
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.
362 directory_send_command(connection_t
*conn
, const char *platform
,
363 int purpose
, const char *resource
,
364 const char *payload
, size_t payload_len
) {
366 char proxystring
[256];
367 char proxyauthstring
[256];
368 char hoststring
[128];
370 const char *httpcommand
= NULL
;
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
));
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
);
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
);
399 proxyauthstring
[0] = 0;
403 proxyauthstring
[0] = 0;
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>");
413 strlcpy(url
, "/tor/dir.z", sizeof(url
));
415 case DIR_PURPOSE_FETCH_RUNNING_LIST
:
416 tor_assert(!resource
);
417 tor_assert(!payload
);
419 strlcpy(url
, "/tor/running-routers", sizeof(url
));
421 case DIR_PURPOSE_UPLOAD_DIR
:
422 tor_assert(!resource
);
424 httpcommand
= "POST";
425 strlcpy(url
, "/tor/", sizeof(url
));
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
));
437 tor_snprintf(url
, sizeof(url
), "/tor/rendezvous/%s", resource
);
440 case DIR_PURPOSE_UPLOAD_RENDDESC
:
441 tor_assert(!resource
);
443 httpcommand
= "POST";
444 tor_snprintf(url
, sizeof(url
), "/tor/rendezvous/publish");
448 tor_snprintf(tmp
, sizeof(tmp
), "%s %s%s HTTP/1.0\r\nContent-Length: %lu\r\nHost: %s%s\r\n\r\n",
452 payload
? (unsigned long)payload_len
: 0,
455 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
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
465 * "\%s [http[s]://]\%s HTTP/1..."
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.
473 parse_http_url(char *headers
, char **url
)
475 char *s
, *start
, *tmp
;
477 s
= (char *)eat_whitespace_no_nl(headers
);
479 s
= (char *)find_whitespace(s
); /* get past GET/POST */
481 s
= (char *)eat_whitespace_no_nl(s
);
483 start
= s
; /* this is it, assuming it's valid */
484 s
= (char *)find_whitespace(start
);
487 /* tolerate the http[s] proxy style of putting the hostname in the url */
488 if (s
-start
>= 4 && !strcmpstart(start
,"http")) {
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");
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);
506 *url
= tor_strndup(start
, s
-start
);
511 /** Parse an HTTP response string <b>headers</b> of the form
513 * "HTTP/1.\%d \%d\%s\r\n...".
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
528 parse_http_response(const char *headers
, int *code
, time_t *date
,
529 int *compression
, char **reason
)
532 char datestr
[RFC1123_TIME_LEN
+1];
533 smartlist_t
*parsed_headers
;
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
);
547 parsed_headers
= smartlist_create();
548 smartlist_split_string(parsed_headers
, headers
, "\n",
549 SPLIT_SKIP_SPACE
|SPLIT_IGNORE_BLANK
, -1);
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
);
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
);
577 const char *enc
= NULL
;
578 SMARTLIST_FOREACH(parsed_headers
, const char *, s
,
579 if (!strcmpstart(s
, "Content-Encoding: ")) {
582 if (!enc
|| !strcmp(enc
, "identity")) {
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
;
589 log_fn(LOG_INFO
, "Unrecognized content encoding: '%s'. Trying to deal.", enc
);
593 SMARTLIST_FOREACH(parsed_headers
, char *, s
, tor_free(s
));
594 smartlist_free(parsed_headers
);
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.
603 body_is_plausible(const char *body
, size_t len
, int purpose
)
607 return 1; /* empty bodies don't need decompression */
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"))
617 if (!TOR_ISPRINT(body
[i
]) && !TOR_ISSPACE(body
[i
]))
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.
633 connection_dir_client_reached_eof(connection_t
*conn
)
640 time_t now
, date_header
=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
);
653 log_fn(LOG_INFO
,"'fetch' response not all here, but we're at eof. Closing.");
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
);
664 if (!reason
) reason
= tor_strdup("[no reason given]");
667 "Received response from directory server '%s': %d \"%s\"",
668 conn
->address
, status_code
, reason
);
670 if (date_header
> 0) {
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.",
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 */
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
;
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";
700 description1
= "with an unknown Content-Encoding";
701 if (guessed
== ZLIB_METHOD
)
702 description2
= "deflated";
703 else if (guessed
== GZIP_METHOD
)
704 description2
= "gzipped";
706 description2
= "confusing binary junk";
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. */
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
);
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
);
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
);
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
);
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
;
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
);
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
);
777 router_get_routerlist(&rl
);
779 routerlist_set_runningrouters(rl
,rrs
);
781 running_routers_free(rrs
);
785 if (conn
->purpose
== DIR_PURPOSE_UPLOAD_DIR
) {
786 switch (status_code
) {
788 log_fn(LOG_INFO
,"eof (status 200) after uploading server descriptor: finished.");
791 log_fn(LOG_WARN
,"http status 400 (\"%s\") response from dirserver '%s'. Malformed server descriptor?", reason
, conn
->address
);
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
);
797 log_fn(LOG_WARN
,"http status %d (\"%s\") reason unexpected (server '%s').", status_code
, reason
, conn
->address
);
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
) {
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
812 /* success. notify pending connections about this. */
813 conn
->purpose
= DIR_PURPOSE_HAS_FETCHED_RENDDESC
;
814 rend_client_desc_here(conn
->rend_query
);
818 /* not there. pending connections will be notified when
819 * connection_mark_for_close cleans it up. */
822 log_fn(LOG_WARN
,"http status 400 (\"%s\"). Dirserver didn't like our rendezvous query?", reason
);
825 log_fn(LOG_WARN
,"http status %d (\"%s\") response unexpected (server '%s').", status_code
, reason
, conn
->address
);
830 if (conn
->purpose
== DIR_PURPOSE_UPLOAD_RENDDESC
) {
831 switch (status_code
) {
833 log_fn(LOG_INFO
,"Uploading rendezvous descriptor: finished with status 200 (\"%s\")", reason
);
836 log_fn(LOG_WARN
,"http status 400 (\"%s\") response from dirserver. Malformed rendezvous descriptor?", reason
);
839 log_fn(LOG_WARN
,"http status %d (\"%s\") response unexpected (server '%s').", status_code
, reason
, conn
->address
);
843 tor_free(body
); tor_free(headers
); tor_free(reason
);
847 int connection_dir_reached_eof(connection_t
*conn
) {
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
);
856 retval
= connection_dir_client_reached_eof(conn
);
857 connection_mark_for_close(conn
);
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
) {
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
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
);
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.");
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>.
894 write_http_status_line(connection_t
*conn
, int status
,
895 const char *reason_phrase
)
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.");
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.
911 already_fetching_directory(int purpose
) {
914 connection_t
**carray
;
916 get_connection_array(&carray
,&n
);
919 if (conn
->type
== CONN_TYPE_DIR
&&
920 conn
->purpose
== purpose
&&
921 !conn
->marked_for_close
&&
922 !router_digest_is_me(conn
->identity_digest
))
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. */
934 directory_handle_command_get(connection_t
*conn
, char *headers
,
935 char *body
, size_t body_len
)
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");
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
);
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);
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",
974 deflated
?"deflate":"identity");
975 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
976 connection_write_to_buf(cp
, dlen
, conn
);
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");
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);
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",
997 deflated
?"deflate":"identity");
998 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
999 connection_write_to_buf(cp
, strlen(cp
), conn
);
1003 if (!strcmpstart(url
,"/tor/rendezvous/")) {
1004 /* rendezvous descriptor fetch */
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.
1014 write_http_status_line(conn
, 400, "Nonauthoritative directory does not not store rendezvous descriptors.");
1018 switch (rend_cache_lookup_desc(url
+strlen("/tor/rendezvous/"), &descp
, &desc_len
)) {
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",
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
);
1027 case 0: /* well-formed but not present */
1028 write_http_status_line(conn
, 404, "Not found");
1030 case -1: /* not well-formed */
1031 write_http_status_line(conn
, 400, "Bad request");
1038 /* we didn't recognize the url */
1039 write_http_status_line(conn
, 404, "Not found");
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. */
1050 directory_handle_command_post(connection_t
*conn
, char *headers
,
1051 char *body
, size_t body_len
)
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.");
1067 if (parse_http_url(headers
, &url
) < 0) {
1068 write_http_status_line(conn
, 400, "Bad request");
1071 log_fn(LOG_INFO
,"rewritten url as '%s'.", url
);
1073 if (!strcmp(url
,"/tor/")) { /* server descriptor post */
1076 switch (dirserv_add_descriptor(&cp
, &msg
)) {
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
);
1084 /* descriptor was well-formed but server has not been approved */
1085 write_http_status_line(conn
, 200, msg
?msg
:"Unverified server descriptor accepted");
1088 dirserv_get_directory(&cp
, 0); /* rebuild and write to disk */
1089 write_http_status_line(conn
, 200, msg
?msg
:"Verified server descriptor accepted");
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");
1101 write_http_status_line(conn
, 200, "Service descriptor stored");
1106 /* we didn't recognize the url */
1107 write_http_status_line(conn
, 404, "Not found");
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
;
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
);
1132 log_fn(LOG_DEBUG
,"command not all here yet.");
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
);
1144 log_fn(LOG_WARN
,"Got headers '%s' with unknown command. Closing.", headers
);
1148 tor_free(headers
); tor_free(body
);
1152 /** Write handler for directory connections; called when all data has
1153 * been flushed. Close the connection or wait for a response as
1156 int connection_dir_finished_flushing(connection_t
*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
);
1167 case DIR_CONN_STATE_SERVER_WRITING
:
1168 log_fn(LOG_INFO
,"Finished writing server response. Closing.");
1169 connection_mark_for_close(conn
);
1172 log_fn(LOG_WARN
,"Bug: called in unexpected state %d.", conn
->state
);
1173 tor_fragile_assert();
1179 /** Connected handler for directory connections: begin sending data to the
1181 int connection_dir_finished_connecting(connection_t
*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 */