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 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.
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
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
33 directory_initiate_command_trusted_dir(trusted_dir_server_t
*dirserv
,
34 uint8_t purpose
, int private_connection
,
36 const char *payload
, size_t payload_len
);
38 directory_initiate_command(const char *address
, uint32_t addr
, uint16_t port
,
40 const char *digest
, uint8_t purpose
,
41 int private_connection
, const char *resource
,
42 const char *payload
, size_t payload_len
);
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.
70 parse_dir_policy(void)
74 addr_policy_free(dir_policy
);
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
) {
85 /** Free storage used to hold parsed directory policy */
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.
97 dir_policy_permits_address(uint32_t addr
)
101 if (!dir_policy
) /* 'no dir policy' means 'accept' */
103 a
= router_compare_addr_to_addr_policy(addr
, 1, dir_policy
);
104 if (a
==ADDR_POLICY_REJECTED
)
106 else if (a
==ADDR_POLICY_ACCEPTED
)
108 log_fn(LOG_WARN
, "Bug: got unexpected 'maybe' answer from dir policy");
112 /** Return true iff the directory purpose 'purpose' must use an
113 * anonymous connection to a directory. */
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
)
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'.
132 directory_post_to_dirservers(uint8_t purpose
, const char *payload
,
135 smartlist_t
*dirservers
;
137 router_get_trusted_dir_servers(&dirservers
);
138 tor_assert(dirservers
);
139 /* This tries dirservers which we believe to be down, but ultimately, that's
140 * harmless, and we may as well err on the side of getting things uploaded.
142 SMARTLIST_FOREACH(dirservers
, trusted_dir_server_t
*, ds
,
144 /* Pay attention to fascistfirewall when we're uploading a
145 * router descriptor, but not when uploading a service
146 * descriptor -- those use Tor. */
147 if (purpose
== DIR_PURPOSE_UPLOAD_DIR
&& !get_options()->HttpProxy
) {
148 if (!fascist_firewall_allows_address(ds
->addr
,ds
->dir_port
))
151 directory_initiate_command_trusted_dir(ds
, purpose
,
152 purpose_is_private(purpose
),
153 NULL
, payload
, payload_len
);
157 /** Start a connection to a random running directory server, using
158 * connection purpose 'purpose' requesting 'resource'. The purpose
159 * should be one of 'DIR_PURPOSE_FETCH_DIR',
160 * 'DIR_PURPOSE_FETCH_RENDDESC', 'DIR_PURPOSE_FETCH_RUNNING_LIST.'
161 * If <b>retry_if_no_servers</b>, then if all the possible servers seem
162 * down, mark them up and try again.
165 directory_get_from_dirserver(uint8_t purpose
, const char *resource
,
166 int retry_if_no_servers
)
168 routerinfo_t
*r
= NULL
;
169 trusted_dir_server_t
*ds
= NULL
;
170 int fascistfirewall
= firewall_is_fascist();
171 or_options_t
*options
= get_options();
172 int fetch_fresh_first
= server_mode(options
) && options
->DirPort
!= 0;
173 int directconn
= !purpose_is_private(purpose
);
175 int need_v1_support
= purpose
== DIR_PURPOSE_FETCH_DIR
||
176 purpose
== DIR_PURPOSE_FETCH_RUNNING_LIST
;
177 int need_v2_support
= purpose
== DIR_PURPOSE_FETCH_NETWORKSTATUS
||
178 purpose
== DIR_PURPOSE_FETCH_SERVERDESC
;
181 if (fetch_fresh_first
&& purpose
== DIR_PURPOSE_FETCH_NETWORKSTATUS
&&
182 !strcmpstart(resource
,"fp/") && strlen(resource
) == HEX_DIGEST_LEN
+3) {
183 /* Try to ask the actual dirserver its opinion. */
184 char digest
[DIGEST_LEN
];
185 base16_decode(digest
, DIGEST_LEN
, resource
+3, HEX_DIGEST_LEN
);
186 ds
= router_get_trusteddirserver_by_digest(digest
);
188 if (!ds
&& fetch_fresh_first
) {
189 /* only ask authdirservers, and don't ask myself */
190 ds
= router_pick_trusteddirserver(need_v1_support
, 1, fascistfirewall
,
191 retry_if_no_servers
);
194 /* anybody with a non-zero dirport will do */
195 r
= router_pick_directory_server(1, fascistfirewall
, need_v2_support
,
196 retry_if_no_servers
);
199 if (purpose
== DIR_PURPOSE_FETCH_DIR
)
201 else if (purpose
== DIR_PURPOSE_FETCH_RUNNING_LIST
)
202 which
= "status list";
203 else if (purpose
== DIR_PURPOSE_FETCH_NETWORKSTATUS
)
204 which
= "network status";
205 else // if (purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS)
206 which
= "server descriptors";
208 "No router found for %s; falling back to dirserver list",which
);
209 ds
= router_pick_trusteddirserver(1, 1, fascistfirewall
,
210 retry_if_no_servers
);
213 } else { // (purpose == DIR_PURPOSE_FETCH_RENDDESC)
214 /* only ask authdirservers, any of them will do */
215 /* Never use fascistfirewall; we're going via Tor. */
216 ds
= router_pick_trusteddirserver(0, 0, 0, retry_if_no_servers
);
220 directory_initiate_command_router(r
, purpose
, !directconn
,
223 directory_initiate_command_trusted_dir(ds
, purpose
, !directconn
,
226 log_fn(LOG_NOTICE
,"No running dirservers known. Will try again later. (purpose %d)",
229 /* remember we tried them all and failed. */
230 directory_all_unreachable(time(NULL
));
235 /** Launch a new connection to the directory server <b>router</b> to upload or
236 * download a service or rendezvous descriptor. <b>purpose</b> determines what
237 * kind of directory connection we're launching, and must be one of
238 * DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC}.
240 * When uploading, <b>payload</b> and <b>payload_len</b> determine the content
241 * of the HTTP post. Otherwise, <b>payload</b> should be NULL.
243 * When fetching a rendezvous descriptor, <b>resource</b> is the service ID we
247 directory_initiate_command_router(routerinfo_t
*router
, uint8_t purpose
,
248 int private_connection
, const char *resource
,
249 const char *payload
, size_t payload_len
)
251 directory_initiate_command(router
->address
, router
->addr
, router
->dir_port
,
252 router
->platform
, router
->identity_digest
,
253 purpose
, private_connection
, resource
,
254 payload
, payload_len
);
257 /** As directory_initiate_command_router, but send the command to a trusted
258 * directory server <b>dirserv</b>. **/
260 directory_initiate_command_trusted_dir(trusted_dir_server_t
*dirserv
,
261 uint8_t purpose
, int private_connection
,
262 const char *resource
,
263 const char *payload
, size_t payload_len
)
265 directory_initiate_command(dirserv
->address
, dirserv
->addr
,
266 dirserv
->dir_port
, NULL
, dirserv
->digest
, purpose
,
267 private_connection
, resource
,
268 payload
, payload_len
);
271 /** Called when we are unable to complete the client's request to a
272 * directory server: Mark the router as down and try again if possible.
275 connection_dir_request_failed(connection_t
*conn
)
277 if (router_digest_is_me(conn
->identity_digest
))
278 return; /* this was a test fetch. don't retry. */
279 router_mark_as_down(conn
->identity_digest
); /* don't try him again */
280 if (conn
->purpose
== DIR_PURPOSE_FETCH_DIR
||
281 conn
->purpose
== DIR_PURPOSE_FETCH_RUNNING_LIST
) {
282 log_fn(LOG_INFO
, "Giving up on directory server at '%s:%d'; retrying",
283 conn
->address
, conn
->port
);
284 directory_get_from_dirserver(conn
->purpose
, NULL
,
285 0 /* don't retry_if_no_servers */);
286 } else if (conn
->purpose
== DIR_PURPOSE_FETCH_NETWORKSTATUS
) {
287 log_fn(LOG_INFO
, "Giving up on directory server at '%s'; retrying",
289 connection_dir_download_networkstatus_failed(conn
);
290 } else if (conn
->purpose
== DIR_PURPOSE_FETCH_SERVERDESC
) {
291 log_fn(LOG_INFO
, "Giving up on directory server at '%s'; retrying",
293 connection_dir_download_routerdesc_failed(conn
);
297 /** Called when an attempt to download one or more network status
298 * documents on connection <b>conn</b> failed. Decide whether to
299 * retry the fetch now, later, or never.
302 connection_dir_download_networkstatus_failed(connection_t
*conn
)
304 if (!conn
->requested_resource
) {
305 /* We never reached directory_send_command, which means that we never
306 * opened a network connection. Either we're out of sockets, or the
307 * network is down. Either way, retrying would be pointless. */
310 if (!strcmpstart(conn
->requested_resource
, "all")) {
311 /* We're a non-authoritative directory cache; try again. */
312 directory_get_from_dirserver(conn
->purpose
, "all.z",
313 0 /* don't retry_if_no_servers */);
314 } else if (!strcmpstart(conn
->requested_resource
, "fp/")) {
315 /* We were trying to download by fingerprint; mark them all has having
316 * failed, and possibly retry them later.*/
317 smartlist_t
*failed
= smartlist_create();
318 dir_split_resource_into_fingerprints(conn
->requested_resource
+3,
320 if (smartlist_len(failed
)) {
321 dir_networkstatus_download_failed(failed
);
322 SMARTLIST_FOREACH(failed
, char *, cp
, tor_free(cp
));
324 smartlist_free(failed
);
328 /** Called when an attempt to download one or more router descriptors
329 * on connection <b>conn</b> failed.
332 connection_dir_download_routerdesc_failed(connection_t
*conn
)
334 /* Try again. No need to increment the failure count for routerdescs, since
335 * it's not their fault.*/
336 /* update_router_descriptor_downloads(time(NULL)); */
339 /** Helper for directory_initiate_command_(router|trusted_dir): send the
340 * command to a server whose address is <b>address</b>, whose IP is
341 * <b>addr</b>, whose directory port is <b>dir_port</b>, whose tor version is
342 * <b>platform</b>, and whose identity key digest is <b>digest</b>. The
343 * <b>platform</b> argument is optional; the others are required. */
345 directory_initiate_command(const char *address
, uint32_t addr
,
346 uint16_t dir_port
, const char *platform
,
347 const char *digest
, uint8_t purpose
,
348 int private_connection
, const char *resource
,
349 const char *payload
, size_t payload_len
)
355 tor_assert(dir_port
);
359 case DIR_PURPOSE_FETCH_DIR
:
360 log_fn(LOG_DEBUG
,"initiating directory fetch");
362 case DIR_PURPOSE_FETCH_RENDDESC
:
363 log_fn(LOG_DEBUG
,"initiating hidden-service descriptor fetch");
365 case DIR_PURPOSE_UPLOAD_DIR
:
366 log_fn(LOG_DEBUG
,"initiating server descriptor upload");
368 case DIR_PURPOSE_UPLOAD_RENDDESC
:
369 log_fn(LOG_DEBUG
,"initiating hidden-service descriptor upload");
371 case DIR_PURPOSE_FETCH_RUNNING_LIST
:
372 log_fn(LOG_DEBUG
,"initiating running-routers fetch");
374 case DIR_PURPOSE_FETCH_NETWORKSTATUS
:
375 log_fn(LOG_DEBUG
,"initiating network-status fetch");
377 case DIR_PURPOSE_FETCH_SERVERDESC
:
378 log_fn(LOG_DEBUG
,"initiating server descriptor fetch");
381 log_fn(LOG_ERR
, "Unrecognized directory connection purpose.");
385 conn
= connection_new(CONN_TYPE_DIR
);
387 /* set up conn so it's got all the data we need to remember */
389 conn
->port
= dir_port
;
390 conn
->address
= tor_strdup(address
);
391 memcpy(conn
->identity_digest
, digest
, DIGEST_LEN
);
393 conn
->purpose
= purpose
;
395 /* give it an initial state */
396 conn
->state
= DIR_CONN_STATE_CONNECTING
;
398 if (!private_connection
) {
399 /* then we want to connect directly */
401 if (get_options()->HttpProxy
) {
402 addr
= get_options()->HttpProxyAddr
;
403 dir_port
= get_options()->HttpProxyPort
;
406 switch (connection_connect(conn
, conn
->address
, addr
, dir_port
)) {
408 connection_dir_request_failed(conn
); /* retry if we want */
409 connection_free(conn
);
412 conn
->state
= DIR_CONN_STATE_CLIENT_SENDING
; /* start flushing conn */
415 /* queue the command on the outbuf */
416 directory_send_command(conn
, platform
, purpose
, resource
,
417 payload
, payload_len
);
418 connection_watch_events(conn
, EV_READ
| EV_WRITE
);
419 /* writable indicates finish, readable indicates broken link,
420 error indicates broken link in windowsland. */
422 } else { /* we want to connect via tor */
423 /* make an AP connection
424 * populate it and add it at the right state
425 * socketpair and hook up both sides
427 conn
->s
= connection_ap_make_bridge(conn
->address
, conn
->port
);
429 log_fn(LOG_WARN
,"Making AP bridge to dirserver failed.");
430 connection_mark_for_close(conn
);
434 conn
->state
= DIR_CONN_STATE_CLIENT_SENDING
;
435 connection_add(conn
);
436 /* queue the command on the outbuf */
437 directory_send_command(conn
, platform
, purpose
, resource
,
438 payload
, payload_len
);
439 connection_watch_events(conn
, EV_READ
| EV_WRITE
);
443 /** Queue an appropriate HTTP command on conn-\>outbuf. The other args
444 * are as in directory_initiate_command.
447 directory_send_command(connection_t
*conn
, const char *platform
,
448 int purpose
, const char *resource
,
449 const char *payload
, size_t payload_len
)
451 char proxystring
[256];
452 char proxyauthstring
[256];
453 char hoststring
[128];
456 const char *httpcommand
= NULL
;
460 tor_assert(conn
->type
== CONN_TYPE_DIR
);
462 tor_free(conn
->requested_resource
);
464 conn
->requested_resource
= tor_strdup(resource
);
466 /* come up with a string for which Host: we want */
467 if (conn
->port
== 80) {
468 strlcpy(hoststring
, conn
->address
, sizeof(hoststring
));
470 tor_snprintf(hoststring
, sizeof(hoststring
),"%s:%d",conn
->address
, conn
->port
);
473 /* come up with some proxy lines, if we're using one. */
474 if (get_options()->HttpProxy
) {
475 char *base64_authenticator
=NULL
;
476 const char *authenticator
= get_options()->HttpProxyAuthenticator
;
478 tor_snprintf(proxystring
, sizeof(proxystring
),"http://%s", hoststring
);
480 base64_authenticator
= alloc_http_authenticator(authenticator
);
481 if (!base64_authenticator
)
482 log_fn(LOG_WARN
, "Encoding http authenticator failed");
484 if (base64_authenticator
) {
485 tor_snprintf(proxyauthstring
, sizeof(proxyauthstring
),
486 "\r\nProxy-Authorization: Basic %s",
487 base64_authenticator
);
488 tor_free(base64_authenticator
);
490 proxyauthstring
[0] = 0;
494 proxyauthstring
[0] = 0;
498 case DIR_PURPOSE_FETCH_DIR
:
499 tor_assert(!resource
);
500 tor_assert(!payload
);
501 log_fn(LOG_DEBUG
, "Asking for compressed directory from server running %s",
502 platform
?platform
:"<unknown version>");
504 url
= tor_strdup("/tor/dir.z");
506 case DIR_PURPOSE_FETCH_RUNNING_LIST
:
507 tor_assert(!resource
);
508 tor_assert(!payload
);
510 url
= tor_strdup("/tor/running-routers");
512 case DIR_PURPOSE_FETCH_NETWORKSTATUS
:
514 len
= strlen(resource
)+32;
515 url
= tor_malloc(len
);
516 tor_snprintf(url
, len
, "/tor/status/%s", resource
);
518 case DIR_PURPOSE_FETCH_SERVERDESC
:
520 len
= strlen(resource
)+32;
521 url
= tor_malloc(len
);
522 tor_snprintf(url
, len
, "/tor/server/%s", resource
);
524 case DIR_PURPOSE_UPLOAD_DIR
:
525 tor_assert(!resource
);
527 httpcommand
= "POST";
528 url
= tor_strdup("/tor/");
530 case DIR_PURPOSE_FETCH_RENDDESC
:
531 tor_assert(resource
);
532 tor_assert(!payload
);
534 /* this must be true or we wouldn't be doing the lookup */
535 tor_assert(strlen(resource
) <= REND_SERVICE_ID_LEN
);
536 /* This breaks the function abstraction. */
537 strlcpy(conn
->rend_query
, resource
, sizeof(conn
->rend_query
));
540 /* Request the most recent versioned descriptor. */
542 //tor_snprintf(url, sizeof(url), "/tor/rendezvous1/%s", resource);
543 len
= strlen(resource
)+32;
544 url
= tor_malloc(len
);
545 tor_snprintf(url
, len
, "/tor/rendezvous/%s", resource
);
547 case DIR_PURPOSE_UPLOAD_RENDDESC
:
548 tor_assert(!resource
);
550 httpcommand
= "POST";
551 url
= tor_strdup("/tor/rendezvous/publish");
557 tor_snprintf(request
, sizeof(request
), "%s %s", httpcommand
, proxystring
);
558 connection_write_to_buf(request
, strlen(request
), conn
);
559 connection_write_to_buf(url
, strlen(url
), conn
);
562 tor_snprintf(request
, sizeof(request
), " HTTP/1.0\r\nContent-Length: %lu\r\nHost: %s%s\r\n\r\n",
563 payload
? (unsigned long)payload_len
: 0,
566 connection_write_to_buf(request
, strlen(request
), conn
);
569 /* then send the payload afterwards too */
570 connection_write_to_buf(payload
, payload_len
, conn
);
574 /** Parse an HTTP request string <b>headers</b> of the form
576 * "\%s [http[s]://]\%s HTTP/1..."
578 * If it's well-formed, strdup the second \%s into *<b>url</b>, and
579 * null-terminate it. If the url doesn't start with "/tor/", rewrite it
580 * so it does. Return 0.
581 * Otherwise, return -1.
584 parse_http_url(char *headers
, char **url
)
586 char *s
, *start
, *tmp
;
588 s
= (char *)eat_whitespace_no_nl(headers
);
590 s
= (char *)find_whitespace(s
); /* get past GET/POST */
592 s
= (char *)eat_whitespace_no_nl(s
);
594 start
= s
; /* this is it, assuming it's valid */
595 s
= (char *)find_whitespace(start
);
598 /* tolerate the http[s] proxy style of putting the hostname in the url */
599 if (s
-start
>= 4 && !strcmpstart(start
,"http")) {
603 if (s
-tmp
>= 3 && !strcmpstart(tmp
,"://")) {
604 tmp
= strchr(tmp
+3, '/');
605 if (tmp
&& tmp
< s
) {
606 log_fn(LOG_DEBUG
,"Skipping over 'http[s]://hostname' string");
612 if (s
-start
< 5 || strcmpstart(start
,"/tor/")) { /* need to rewrite it */
613 *url
= tor_malloc(s
- start
+ 5);
614 strlcpy(*url
,"/tor", s
-start
+5);
615 strlcat((*url
)+4, start
, s
-start
+1);
617 *url
= tor_strndup(start
, s
-start
);
622 /** Return a copy of the first HTTP header in <b>headers</b> whose key is
623 * <b>which</b>. The key should be given with a terminating colon and space;
624 * this function copies everything after, up to but not including the
625 * following \\r\\n. */
627 http_get_header(const char *headers
, const char *which
)
629 const char *cp
= headers
;
631 if (!strcmpstart(cp
, which
)) {
634 if ((eos
= strchr(cp
,'\r')))
635 return tor_strndup(cp
, eos
-cp
);
637 return tor_strdup(cp
);
639 cp
= strchr(cp
, '\n');
646 /** Allocate and return a string describing the source of an HTTP request with
647 * headers <b>headers</b> received on <b>conn</b>. The format is either
648 * "'1.2.3.4'", or "'1.2.3.4' (forwarded for '5.6.7.8')".
651 http_get_origin(const char *headers
, connection_t
*conn
)
655 fwd
= http_get_header(headers
, "Forwarded-For: ");
657 fwd
= http_get_header(headers
, "X-Forwarded-For: ");
659 size_t len
= strlen(fwd
)+strlen(conn
->address
)+32;
660 char *result
= tor_malloc(len
);
661 tor_snprintf(result
, len
, "'%s' (forwarded for '%s')", conn
->address
, fwd
);
665 size_t len
= strlen(conn
->address
)+3;
666 char *result
= tor_malloc(len
);
667 tor_snprintf(result
, len
, "'%s'", conn
->address
);
672 /** Parse an HTTP response string <b>headers</b> of the form
674 * "HTTP/1.\%d \%d\%s\r\n...".
677 * If it's well-formed, assign the status code to *<b>code</b> and
678 * return 0. Otherwise, return -1.
680 * On success: If <b>date</b> is provided, set *date to the Date
681 * header in the http headers, or 0 if no such header is found. If
682 * <b>compression</b> is provided, set *<b>compression</b> to the
683 * compression method given in the Content-Encoding header, or 0 if no
684 * such header is found, or -1 if the value of the header is not
685 * recognized. If <b>reason</b> is provided, strdup the reason string
689 parse_http_response(const char *headers
, int *code
, time_t *date
,
690 int *compression
, char **reason
)
693 char datestr
[RFC1123_TIME_LEN
+1];
694 smartlist_t
*parsed_headers
;
698 while (TOR_ISSPACE(*headers
)) headers
++; /* tolerate leading whitespace */
700 if (sscanf(headers
, "HTTP/1.%d %d", &n1
, &n2
) < 2 ||
701 (n1
!= 0 && n1
!= 1) ||
702 (n2
< 100 || n2
>= 600)) {
703 log_fn(LOG_WARN
,"Failed to parse header '%s'",headers
);
708 parsed_headers
= smartlist_create();
709 smartlist_split_string(parsed_headers
, headers
, "\n",
710 SPLIT_SKIP_SPACE
|SPLIT_IGNORE_BLANK
, -1);
712 smartlist_t
*status_line_elements
= smartlist_create();
713 tor_assert(smartlist_len(parsed_headers
));
714 smartlist_split_string(status_line_elements
,
715 smartlist_get(parsed_headers
, 0),
716 " ", SPLIT_SKIP_SPACE
|SPLIT_IGNORE_BLANK
, 3);
717 tor_assert(smartlist_len(status_line_elements
) <= 3);
718 if (smartlist_len(status_line_elements
) == 3) {
719 *reason
= smartlist_get(status_line_elements
, 2);
720 smartlist_set(status_line_elements
, 2, NULL
); /* Prevent free */
722 SMARTLIST_FOREACH(status_line_elements
, char *, cp
, tor_free(cp
));
723 smartlist_free(status_line_elements
);
727 SMARTLIST_FOREACH(parsed_headers
, const char *, s
,
728 if (!strcmpstart(s
, "Date: ")) {
729 strlcpy(datestr
, s
+6, sizeof(datestr
));
730 /* This will do nothing on failure, so we don't need to check
731 the result. We shouldn't warn, since there are many other valid
732 date formats besides the one we use. */
733 parse_rfc1123_time(datestr
, date
);
738 const char *enc
= NULL
;
739 SMARTLIST_FOREACH(parsed_headers
, const char *, s
,
740 if (!strcmpstart(s
, "Content-Encoding: ")) {
743 if (!enc
|| !strcmp(enc
, "identity")) {
745 } else if (!strcmp(enc
, "deflate") || !strcmp(enc
, "x-deflate")) {
746 *compression
= ZLIB_METHOD
;
747 } else if (!strcmp(enc
, "gzip") || !strcmp(enc
, "x-gzip")) {
748 *compression
= GZIP_METHOD
;
750 log_fn(LOG_INFO
, "Unrecognized content encoding: '%s'. Trying to deal.", enc
);
754 SMARTLIST_FOREACH(parsed_headers
, char *, s
, tor_free(s
));
755 smartlist_free(parsed_headers
);
760 /** Return true iff <b>body</b> doesn't start with a plausible router or
761 * running-list or directory opening. This is a sign of possible compression.
764 body_is_plausible(const char *body
, size_t len
, int purpose
)
768 return 1; /* empty bodies don't need decompression */
771 if (purpose
!= DIR_PURPOSE_FETCH_RENDDESC
) {
772 if (!strcmpstart(body
,"router") ||
773 !strcmpstart(body
,"signed-directory") ||
774 !strcmpstart(body
,"network-status") ||
775 !strcmpstart(body
,"running-routers"))
778 if (!TOR_ISPRINT(body
[i
]) && !TOR_ISSPACE(body
[i
]))
787 /** We are a client, and we've finished reading the server's
788 * response. Parse and it and act appropriately.
790 * If we're happy with the result (we get it and it's useful),
791 * return 0. Otherwise return -1, and the caller should consider
792 * trying the request again.
794 * The caller will take care of marking the connection for close.
797 connection_dir_client_reached_eof(connection_t
*conn
)
804 time_t now
, date_header
=0;
809 int allow_partial
= conn
->purpose
== DIR_PURPOSE_FETCH_SERVERDESC
;
811 switch (fetch_from_buf_http(conn
->inbuf
,
812 &headers
, MAX_HEADERS_SIZE
,
813 &body
, &body_len
, MAX_DIR_SIZE
,
815 case -1: /* overflow */
816 log_fn(LOG_WARN
,"'fetch' response too large (server '%s:%d'). Closing.", conn
->address
, conn
->port
);
819 log_fn(LOG_INFO
,"'fetch' response not all here, but we're at eof. Closing.");
821 /* case 1, fall through */
824 if (parse_http_response(headers
, &status_code
, &date_header
,
825 &compression
, &reason
) < 0) {
826 log_fn(LOG_WARN
,"Unparseable headers (server '%s:%d'). Closing.", conn
->address
, conn
->port
);
827 tor_free(body
); tor_free(headers
);
830 if (!reason
) reason
= tor_strdup("[no reason given]");
833 "Received response from directory server '%s:%d': %d \"%s\"",
834 conn
->address
, conn
->port
, status_code
, reason
);
836 if (date_header
> 0) {
838 delta
= now
-date_header
;
839 if (abs(delta
)>ALLOW_DIRECTORY_TIME_SKEW
) {
840 log_fn(router_digest_is_trusted_dir(conn
->identity_digest
) ? LOG_WARN
: LOG_INFO
,
841 "Received directory with skewed time (server '%s:%d'): we are %d minutes %s, or the directory is %d minutes %s.",
842 conn
->address
, conn
->port
,
843 abs(delta
)/60, delta
>0 ? "ahead" : "behind",
844 abs(delta
)/60, delta
>0 ? "behind" : "ahead");
845 skewed
= 1; /* don't check the recommended-versions line */
847 log_fn(LOG_DEBUG
, "Time on received directory is within tolerance; we are %d seconds skewed. (That's okay.)", delta
);
851 plausible
= body_is_plausible(body
, body_len
, conn
->purpose
);
852 if (compression
|| !plausible
) {
853 char *new_body
= NULL
;
855 int guessed
= detect_compression_method(body
, body_len
);
856 if (compression
<= 0 || guessed
!= compression
) {
857 /* Tell the user if we don't believe what we're told about compression.*/
858 const char *description1
, *description2
;
859 if (compression
== ZLIB_METHOD
)
860 description1
= "as deflated";
861 else if (compression
== GZIP_METHOD
)
862 description1
= "as gzipped";
863 else if (compression
== 0)
864 description1
= "as uncompressed";
866 description1
= "with an unknown Content-Encoding";
867 if (guessed
== ZLIB_METHOD
)
868 description2
= "deflated";
869 else if (guessed
== GZIP_METHOD
)
870 description2
= "gzipped";
872 description2
= "confusing binary junk";
874 description2
= "uncompressed";
876 log_fn(LOG_INFO
, "HTTP body from server '%s:%d' was labeled %s, "
877 "but it seems to be %s.%s",
878 conn
->address
, conn
->port
, description1
, description2
,
879 (compression
>0 && guessed
>0)?" Trying both.":"");
881 /* Try declared compression first if we can. */
883 tor_gzip_uncompress(&new_body
, &new_len
, body
, body_len
, compression
,
885 /* Okay, if that didn't work, and we think that it was compressed
886 * differently, try that. */
887 if (!new_body
&& guessed
> 0 && compression
!= guessed
)
888 tor_gzip_uncompress(&new_body
, &new_len
, body
, body_len
, guessed
,
890 /* If we're pretty sure that we have a compressed directory, and
891 * we didn't manage to uncompress it, then warn and bail. */
892 if (!plausible
&& !new_body
) {
893 log_fn(LOG_WARN
, "Unable to decompress HTTP body (server '%s:%d').",
894 conn
->address
, conn
->port
);
895 tor_free(body
); tor_free(headers
); tor_free(reason
);
905 if (conn
->purpose
== DIR_PURPOSE_FETCH_DIR
) {
906 /* fetch/process the directory to learn about new routers. */
907 log_fn(LOG_INFO
,"Received directory (size %d) from server '%s:%d'",
908 (int)body_len
, conn
->address
, conn
->port
);
909 if (status_code
== 503 || body_len
== 0) {
910 log_fn(LOG_INFO
,"Empty directory; status %d (\"%s\") Ignoring.",
911 status_code
, reason
);
912 tor_free(body
); tor_free(headers
); tor_free(reason
);
915 if (status_code
!= 200) {
916 log_fn(LOG_WARN
,"Received http status code %d (\"%s\") from server '%s:%d'. I'll try again soon.",
917 status_code
, reason
, conn
->address
, conn
->port
);
918 tor_free(body
); tor_free(headers
); tor_free(reason
);
921 if (router_parse_directory(body
) < 0) {
922 log_fn(LOG_NOTICE
,"I failed to parse the directory I fetched from '%s:%d'. Ignoring.", conn
->address
, conn
->port
);
926 if (conn
->purpose
== DIR_PURPOSE_FETCH_RUNNING_LIST
) {
927 /* just update our list of running routers, if this list is new info */
928 log_fn(LOG_INFO
,"Received running-routers list (size %d)", (int)body_len
);
929 if (status_code
!= 200) {
930 log_fn(LOG_WARN
,"Received http status code %d (\"%s\") from server '%s:%d'. I'll try again soon.",
931 status_code
, reason
, conn
->address
, conn
->port
);
932 tor_free(body
); tor_free(headers
); tor_free(reason
);
935 if (router_parse_runningrouters(body
)<0) {
936 log_fn(LOG_WARN
,"Bad running-routers from server '%s:%d'. I'll try again soon.",
937 conn
->address
, conn
->port
);
938 tor_free(body
); tor_free(headers
); tor_free(reason
);
943 if (conn
->purpose
== DIR_PURPOSE_FETCH_NETWORKSTATUS
) {
944 smartlist_t
*which
= NULL
;
946 log_fn(LOG_INFO
,"Received networkstatus objects (size %d) from server '%s:%d'",(int) body_len
, conn
->address
, conn
->port
);
947 if (status_code
!= 200) {
948 log_fn(LOG_WARN
,"Received http status code %d (\"%s\") from server '%s:%d' while fetching \"/tor/status/%s\". I'll try again soon.",
949 status_code
, reason
, conn
->address
, conn
->port
,
950 conn
->requested_resource
);
951 tor_free(body
); tor_free(headers
); tor_free(reason
);
952 connection_dir_download_networkstatus_failed(conn
);
955 if (conn
->requested_resource
&&
956 !strcmpstart(conn
->requested_resource
,"fp/")) {
957 which
= smartlist_create();
958 dir_split_resource_into_fingerprints(conn
->requested_resource
+3,
963 char *next
= strstr(cp
, "\nnetwork-status-version");
966 /* learn from it, and then remove it from 'which' */
967 if (router_set_networkstatus(cp
, time(NULL
), NS_FROM_DIR
, which
)<0)
976 routers_update_all_from_networkstatus(); /*launches router downloads*/
977 directory_info_has_arrived(time(NULL
), 0);
979 if (smartlist_len(which
)) {
980 dir_networkstatus_download_failed(which
);
982 SMARTLIST_FOREACH(which
, char *, cp
, tor_free(cp
));
983 smartlist_free(which
);
987 if (conn
->purpose
== DIR_PURPOSE_FETCH_SERVERDESC
) {
988 smartlist_t
*which
= NULL
;
990 log_fn(LOG_INFO
,"Received server info (size %d) from server '%s:%d'",
991 (int)body_len
, conn
->address
, conn
->port
);
992 if (conn
->requested_resource
&&
993 !strcmpstart(conn
->requested_resource
,"fp/")) {
994 which
= smartlist_create();
995 dir_split_resource_into_fingerprints(conn
->requested_resource
+3,
997 n_asked_for
= smartlist_len(which
);
999 if (status_code
!= 200) {
1000 int no_warn
= status_code
== 404 ||
1001 (status_code
== 400 && !strcmp(reason
, "Servers unavailable."));
1002 /* 404 means that it didn't have them; no big deal.
1003 * Older (pre-0.1.1.8) servers said 400 Servers unavailable instead. */
1004 log_fn(no_warn
? LOG_INFO
: LOG_WARN
,
1005 "Received http status code %d (\"%s\") from server '%s:%d' while fetching \"/tor/server/%s\". I'll try again soon.",
1006 status_code
, reason
, conn
->address
, conn
->port
,
1007 conn
->requested_resource
);
1009 connection_dir_download_routerdesc_failed(conn
);
1011 dir_routerdesc_download_failed(which
);
1012 SMARTLIST_FOREACH(which
, char *, cp
, tor_free(cp
));
1013 smartlist_free(which
);
1015 tor_free(body
); tor_free(headers
); tor_free(reason
);
1018 /* Learn the routers, assuming we requested by fingerprint or "all".
1019 * Right now, we only use "authority" to fetch ourself, so we don't want
1020 * to risk replacing ourself with a router running at the addr:port we
1023 if (which
|| (conn
->requested_resource
&&
1024 !strcmpstart(conn
->requested_resource
, "all"))) {
1025 /* as we learn from them, we remove them from 'which' */
1026 router_load_routers_from_string(body
, 0, which
);
1027 directory_info_has_arrived(time(NULL
), 0);
1029 if (which
) { /* mark remaining ones as failed */
1030 log_fn(LOG_INFO
, "Received %d/%d routers requested from %s:%d",
1031 n_asked_for
-smartlist_len(which
), n_asked_for
,
1032 conn
->address
, (int)conn
->port
);
1033 if (smartlist_len(which
)) {
1034 dir_routerdesc_download_failed(which
);
1036 SMARTLIST_FOREACH(which
, char *, cp
, tor_free(cp
));
1037 smartlist_free(which
);
1039 if (conn
->requested_resource
&&
1040 !strcmpstart(conn
->requested_resource
,"authority")) {
1041 /* this might have been a dirport reachability test. see if it is. */
1042 routerinfo_t
*me
= router_get_my_routerinfo();
1044 !memcmp(me
->identity_digest
, conn
->identity_digest
, DIGEST_LEN
) &&
1045 me
->addr
== conn
->addr
&&
1046 me
->dir_port
== conn
->port
)
1047 router_dirport_found_reachable();
1051 if (conn
->purpose
== DIR_PURPOSE_UPLOAD_DIR
) {
1052 switch (status_code
) {
1054 log_fn(LOG_INFO
,"eof (status 200) after uploading server descriptor: finished.");
1057 log_fn(LOG_WARN
,"http status 400 (\"%s\") response from dirserver '%s:%d'. Please correct.", reason
, conn
->address
, conn
->port
);
1060 log_fn(LOG_WARN
,"http status 403 (\"%s\") response from dirserver '%s:%d'. 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-server.html", reason
, conn
->address
, conn
->port
);
1063 log_fn(LOG_WARN
,"http status %d (\"%s\") reason unexpected (server '%s:%d').", status_code
, reason
, conn
->address
, conn
->port
);
1066 /* return 0 in all cases, since we don't want to mark any
1067 * dirservers down just because they don't like us. */
1070 if (conn
->purpose
== DIR_PURPOSE_FETCH_RENDDESC
) {
1071 log_fn(LOG_INFO
,"Received rendezvous descriptor (size %d, status %d (\"%s\"))",
1072 (int)body_len
, status_code
, reason
);
1073 switch (status_code
) {
1075 if (rend_cache_store(body
, body_len
) < 0) {
1076 log_fn(LOG_WARN
,"Failed to store rendezvous descriptor.");
1077 /* alice's ap_stream will notice when connection_mark_for_close
1080 /* success. notify pending connections about this. */
1081 conn
->purpose
= DIR_PURPOSE_HAS_FETCHED_RENDDESC
;
1082 rend_client_desc_here(conn
->rend_query
);
1086 /* not there. pending connections will be notified when
1087 * connection_mark_for_close cleans it up. */
1090 log_fn(LOG_WARN
,"http status 400 (\"%s\"). Dirserver didn't like our rendezvous query?", reason
);
1093 log_fn(LOG_WARN
,"http status %d (\"%s\") response unexpected (server '%s:%d').", status_code
, reason
, conn
->address
, conn
->port
);
1098 if (conn
->purpose
== DIR_PURPOSE_UPLOAD_RENDDESC
) {
1099 switch (status_code
) {
1101 log_fn(LOG_INFO
,"Uploading rendezvous descriptor: finished with status 200 (\"%s\")", reason
);
1104 log_fn(LOG_WARN
,"http status 400 (\"%s\") response from dirserver '%s:%d'. Malformed rendezvous descriptor?", reason
, conn
->address
, conn
->port
);
1107 log_fn(LOG_WARN
,"http status %d (\"%s\") response unexpected (server '%s:%d').", status_code
, reason
, conn
->address
, conn
->port
);
1111 tor_free(body
); tor_free(headers
); tor_free(reason
);
1115 /** Called when a directory connection reaches EOF */
1117 connection_dir_reached_eof(connection_t
*conn
)
1120 if (conn
->state
!= DIR_CONN_STATE_CLIENT_READING
) {
1121 log_fn(LOG_INFO
,"conn reached eof, not reading. Closing.");
1122 /* This check is temporary; it's to let us know whether we should consider
1123 * parsing partial serverdesc responses. */
1124 if (conn
->purpose
== DIR_PURPOSE_FETCH_SERVERDESC
&&
1125 buf_datalen(conn
->inbuf
)>=(24*1024)) {
1126 log_fn(LOG_NOTICE
, "Directory connection closed early after downloading %d bytes of descriptors. If this happens often, please file a bug report.",
1127 (int)buf_datalen(conn
->inbuf
));
1129 connection_close_immediate(conn
); /* it was an error; give up on flushing */
1130 connection_mark_for_close(conn
);
1134 retval
= connection_dir_client_reached_eof(conn
);
1135 if (retval
== 0) /* success */
1136 conn
->state
= DIR_CONN_STATE_CLIENT_FINISHED
;
1137 connection_mark_for_close(conn
);
1141 /** Read handler for directory connections. (That's connections <em>to</em>
1142 * directory servers and connections <em>at</em> directory servers.)
1145 connection_dir_process_inbuf(connection_t
*conn
)
1148 tor_assert(conn
->type
== CONN_TYPE_DIR
);
1150 /* Directory clients write, then read data until they receive EOF;
1151 * directory servers read data until they get an HTTP command, then
1152 * write their response (when it's finished flushing, they mark for
1156 /* If we're on the dirserver side, look for a command. */
1157 if (conn
->state
== DIR_CONN_STATE_SERVER_COMMAND_WAIT
) {
1158 if (directory_handle_command(conn
) < 0) {
1159 connection_mark_for_close(conn
);
1165 /* XXX for READ states, might want to make sure inbuf isn't too big */
1167 log_fn(LOG_DEBUG
,"Got data, not eof. Leaving on inbuf.");
1171 /** Create an http response for the client <b>conn</b> out of
1172 * <b>status</b> and <b>reason_phrase</b>. Write it to <b>conn</b>.
1175 write_http_status_line(connection_t
*conn
, int status
,
1176 const char *reason_phrase
)
1179 if (tor_snprintf(buf
, sizeof(buf
), "HTTP/1.0 %d %s\r\n\r\n",
1180 status
, reason_phrase
) < 0) {
1181 log_fn(LOG_WARN
,"Bug: status line too long.");
1184 connection_write_to_buf(buf
, strlen(buf
), conn
);
1187 /** Helper function: return 1 if there are any dir conns of purpose
1188 * <b>purpose</b> that are going elsewhere than our own ORPort/Dirport.
1192 already_fetching_directory(int purpose
)
1196 connection_t
**carray
;
1198 get_connection_array(&carray
,&n
);
1201 if (conn
->type
== CONN_TYPE_DIR
&&
1202 conn
->purpose
== purpose
&&
1203 !conn
->marked_for_close
&&
1204 !router_digest_is_me(conn
->identity_digest
))
1210 /** Helper function: called when a dirserver gets a complete HTTP GET
1211 * request. Look for a request for a directory or for a rendezvous
1212 * service descriptor. On finding one, write a response into
1213 * conn-\>outbuf. If the request is unrecognized, send a 400.
1214 * Always return 0. */
1216 directory_handle_command_get(connection_t
*conn
, char *headers
,
1217 char *body
, size_t body_len
)
1223 char date
[RFC1123_TIME_LEN
+1];
1225 log_fn(LOG_DEBUG
,"Received GET command.");
1227 conn
->state
= DIR_CONN_STATE_SERVER_WRITING
;
1229 if (parse_http_url(headers
, &url
) < 0) {
1230 write_http_status_line(conn
, 400, "Bad request");
1233 log_fn(LOG_DEBUG
,"rewritten url as '%s'.", url
);
1235 if (!strcmp(url
,"/tor/") || !strcmp(url
,"/tor/dir.z")) { /* directory fetch */
1236 int deflated
= !strcmp(url
,"/tor/dir.z");
1237 dlen
= dirserv_get_directory(&cp
, deflated
);
1242 log_fn(LOG_NOTICE
,"Client asked for the mirrored directory, but we don't have a good one yet. Sending 503 Dir not available.");
1243 write_http_status_line(conn
, 503, "Directory unavailable");
1244 /* try to get a new one now */
1245 if (!already_fetching_directory(DIR_PURPOSE_FETCH_DIR
))
1246 directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR
, NULL
, 1);
1250 log_fn(LOG_DEBUG
,"Dumping %sdirectory to client.",
1251 deflated
?"deflated ":"");
1252 format_rfc1123_time(date
, time(NULL
));
1253 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",
1256 deflated
?"application/octet-stream":"text/plain",
1257 deflated
?"deflate":"identity");
1258 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
1259 connection_write_to_buf(cp
, dlen
, conn
);
1263 if (!strcmp(url
,"/tor/running-routers") ||
1264 !strcmp(url
,"/tor/running-routers.z")) { /* running-routers fetch */
1265 int deflated
= !strcmp(url
,"/tor/running-routers.z");
1267 dlen
= dirserv_get_runningrouters(&cp
, deflated
);
1268 if (!dlen
) { /* we failed to create/cache cp */
1269 write_http_status_line(conn
, 503, "Directory unavailable");
1270 /* try to get a new one now */
1271 if (!already_fetching_directory(DIR_PURPOSE_FETCH_RUNNING_LIST
))
1272 directory_get_from_dirserver(DIR_PURPOSE_FETCH_RUNNING_LIST
, NULL
, 1);
1276 format_rfc1123_time(date
, time(NULL
));
1277 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",
1280 deflated
?"application/octet-stream":"text/plain",
1281 deflated
?"deflate":"identity");
1282 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
1283 connection_write_to_buf(cp
, strlen(cp
), conn
);
1287 if (!strcmpstart(url
,"/tor/status/")) {
1288 /* v2 network status fetch. */
1289 size_t url_len
= strlen(url
);
1290 int deflated
= !strcmp(url
+url_len
-2, ".z");
1291 smartlist_t
*dir_objs
= smartlist_create();
1292 const char *key
= url
+ strlen("/tor/status/");
1294 url
[url_len
-2] = '\0';
1295 if (dirserv_get_networkstatus_v2(dir_objs
, key
)) {
1296 smartlist_free(dir_objs
);
1300 if (!smartlist_len(dir_objs
)) { /* we failed to create/cache cp */
1301 write_http_status_line(conn
, 503, "Network status object unavailable");
1302 smartlist_free(dir_objs
);
1306 SMARTLIST_FOREACH(dir_objs
, cached_dir_t
*, d
,
1307 dlen
+= deflated
?d
->dir_z_len
:d
->dir_len
);
1308 format_rfc1123_time(date
, time(NULL
));
1309 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",
1312 deflated
?"application/octet-stream":"text/plain",
1313 deflated
?"deflate":"identity");
1314 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
1315 SMARTLIST_FOREACH(dir_objs
, cached_dir_t
*, d
,
1318 connection_write_to_buf(d
->dir_z
, d
->dir_z_len
, conn
);
1320 connection_write_to_buf(d
->dir
, d
->dir_len
, conn
);
1322 smartlist_free(dir_objs
);
1326 if (!strcmpstart(url
,"/tor/server/")) {
1327 size_t url_len
= strlen(url
);
1328 int deflated
= !strcmp(url
+url_len
-2, ".z");
1331 smartlist_t
*descs
= smartlist_create();
1333 url
[url_len
-2] = '\0';
1334 res
= dirserv_get_routerdescs(descs
, url
, &msg
);
1337 write_http_status_line(conn
, 404, msg
);
1340 format_rfc1123_time(date
, time(NULL
));
1341 SMARTLIST_FOREACH(descs
, routerinfo_t
*, ri
,
1342 len
+= ri
->signed_descriptor_len
);
1344 size_t compressed_len
;
1346 char *inp
= tor_malloc(len
+smartlist_len(descs
)+1);
1348 SMARTLIST_FOREACH(descs
, routerinfo_t
*, ri
,
1350 memcpy(cp
, ri
->signed_descriptor
,
1351 ri
->signed_descriptor_len
);
1352 cp
+= ri
->signed_descriptor_len
;
1356 /* XXXX This could be way more efficiently handled; let's see if it
1357 * shows up under oprofile. */
1358 if (tor_gzip_compress(&compressed
, &compressed_len
,
1359 inp
, cp
-inp
, ZLIB_METHOD
)<0) {
1361 smartlist_free(descs
);
1365 tor_snprintf(tmp
, sizeof(tmp
), "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\nContent-Type: application/octet-stream\r\nContent-Encoding: deflate\r\n\r\n",
1367 (int)compressed_len
);
1368 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
1369 connection_write_to_buf(compressed
, compressed_len
, conn
);
1370 tor_free(compressed
);
1372 tor_snprintf(tmp
, sizeof(tmp
), "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\nContent-Type: text/plain\r\n\r\n",
1375 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
1376 SMARTLIST_FOREACH(descs
, routerinfo_t
*, ri
,
1377 connection_write_to_buf(ri
->signed_descriptor
,
1378 ri
->signed_descriptor_len
,
1382 smartlist_free(descs
);
1386 if (!strcmpstart(url
,"/tor/rendezvous/") ||
1387 !strcmpstart(url
,"/tor/rendezvous1/")) {
1388 /* rendezvous descriptor fetch */
1391 int versioned
= !strcmpstart(url
,"/tor/rendezvous1/");
1392 const char *query
= url
+strlen("/tor/rendezvous/")+(versioned
?1:0);
1394 if (!authdir_mode(get_options())) {
1395 /* We don't hand out rend descs. In fact, it could be a security
1396 * risk, since rend_cache_lookup_desc() below would provide it
1397 * if we're gone to the site recently, and 404 if we haven't.
1400 write_http_status_line(conn
, 400, "Nonauthoritative directory does not not store rendezvous descriptors");
1404 switch (rend_cache_lookup_desc(query
, versioned
?-1:0, &descp
, &desc_len
)) {
1406 format_rfc1123_time(date
, time(NULL
));
1407 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",
1409 (int)desc_len
); /* can't include descp here, because it's got nuls */
1410 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
1411 connection_write_to_buf(descp
, desc_len
, conn
);
1413 case 0: /* well-formed but not present */
1414 write_http_status_line(conn
, 404, "Not found");
1416 case -1: /* not well-formed */
1417 write_http_status_line(conn
, 400, "Bad request");
1424 /* we didn't recognize the url */
1425 write_http_status_line(conn
, 404, "Not found");
1430 /** Helper function: called when a dirserver gets a complete HTTP POST
1431 * request. Look for an uploaded server descriptor or rendezvous
1432 * service descriptor. On finding one, process it and write a
1433 * response into conn-\>outbuf. If the request is unrecognized, send a
1434 * 400. Always return 0. */
1436 directory_handle_command_post(connection_t
*conn
, char *headers
,
1437 char *body
, size_t body_len
)
1440 char *origin
= NULL
;
1443 log_fn(LOG_DEBUG
,"Received POST command.");
1445 conn
->state
= DIR_CONN_STATE_SERVER_WRITING
;
1447 if (!authdir_mode(get_options())) {
1448 /* we just provide cached directories; we don't want to
1449 * receive anything. */
1450 write_http_status_line(conn
, 400, "Nonauthoritative directory does not accept posted server descriptors");
1454 if (parse_http_url(headers
, &url
) < 0) {
1455 write_http_status_line(conn
, 400, "Bad request");
1458 log_fn(LOG_DEBUG
,"rewritten url as '%s'.", url
);
1459 origin
= http_get_origin(headers
, conn
);
1461 if (!strcmp(url
,"/tor/")) { /* server descriptor post */
1463 int r
= dirserv_add_descriptor(body
, &msg
);
1466 dirserv_get_directory(&cp
, 0); /* rebuild and write to disk */
1471 log_fn(LOG_NOTICE
,"Rejected descriptor from %s.", origin
);
1472 /* malformed descriptor, or something wrong */
1473 write_http_status_line(conn
, 400, msg
);
1475 case 0: /* accepted but discarded */
1476 case 2: /* accepted */
1477 write_http_status_line(conn
, 200, msg
);
1483 if (!strcmpstart(url
,"/tor/rendezvous/publish")) {
1484 /* rendezvous descriptor post */
1485 if (rend_cache_store(body
, body_len
) < 0)
1486 write_http_status_line(conn
, 400, "Invalid service descriptor rejected");
1488 write_http_status_line(conn
, 200, "Service descriptor stored");
1492 /* we didn't recognize the url */
1493 write_http_status_line(conn
, 404, "Not found");
1502 /** Called when a dirserver receives data on a directory connection;
1503 * looks for an HTTP request. If the request is complete, remove it
1504 * from the inbuf, try to process it; otherwise, leave it on the
1505 * buffer. Return a 0 on success, or -1 on error.
1508 directory_handle_command(connection_t
*conn
)
1510 char *headers
=NULL
, *body
=NULL
;
1515 tor_assert(conn
->type
== CONN_TYPE_DIR
);
1517 switch (fetch_from_buf_http(conn
->inbuf
,
1518 &headers
, MAX_HEADERS_SIZE
,
1519 &body
, &body_len
, MAX_BODY_SIZE
, 0)) {
1520 case -1: /* overflow */
1521 log_fn(LOG_WARN
,"Invalid input from address '%s'. Closing.", conn
->address
);
1524 log_fn(LOG_DEBUG
,"command not all here yet.");
1526 /* case 1, fall through */
1529 log_fn(LOG_DEBUG
,"headers '%s', body '%s'.", headers
, body
);
1531 if (!strncasecmp(headers
,"GET",3))
1532 r
= directory_handle_command_get(conn
, headers
, body
, body_len
);
1533 else if (!strncasecmp(headers
,"POST",4))
1534 r
= directory_handle_command_post(conn
, headers
, body
, body_len
);
1536 log_fn(LOG_WARN
,"Got headers '%s' with unknown command. Closing.", headers
);
1540 tor_free(headers
); tor_free(body
);
1544 /** Write handler for directory connections; called when all data has
1545 * been flushed. Close the connection or wait for a response as
1549 connection_dir_finished_flushing(connection_t
*conn
)
1552 tor_assert(conn
->type
== CONN_TYPE_DIR
);
1554 switch (conn
->state
) {
1555 case DIR_CONN_STATE_CLIENT_SENDING
:
1556 log_fn(LOG_DEBUG
,"client finished sending command.");
1557 conn
->state
= DIR_CONN_STATE_CLIENT_READING
;
1558 connection_stop_writing(conn
);
1560 case DIR_CONN_STATE_SERVER_WRITING
:
1561 log_fn(LOG_DEBUG
,"Finished writing server response. Closing.");
1562 connection_mark_for_close(conn
);
1565 log_fn(LOG_WARN
,"Bug: called in unexpected state %d.", conn
->state
);
1566 tor_fragile_assert();
1572 /** Connected handler for directory connections: begin sending data to the
1575 connection_dir_finished_connecting(connection_t
*conn
)
1578 tor_assert(conn
->type
== CONN_TYPE_DIR
);
1579 tor_assert(conn
->state
== DIR_CONN_STATE_CONNECTING
);
1581 log_fn(LOG_DEBUG
,"Dir connection to router %s:%u established.",
1582 conn
->address
,conn
->port
);
1584 conn
->state
= DIR_CONN_STATE_CLIENT_SENDING
; /* start flushing conn */
1588 /** Called when one or more networkstatus fetches have failed (with uppercase
1589 * fingerprints listed in <b>failed</>). Mark those fingerprints has having
1592 dir_networkstatus_download_failed(smartlist_t
*failed
)
1594 SMARTLIST_FOREACH(failed
, const char *, fp
,
1596 char digest
[DIGEST_LEN
];
1597 trusted_dir_server_t
*dir
;
1598 base16_decode(digest
, DIGEST_LEN
, fp
, strlen(fp
));
1599 dir
= router_get_trusteddirserver_by_digest(digest
);
1601 ++dir
->n_networkstatus_failures
;
1605 /** Called when one or more networkstatus fetches have failed (with uppercase
1606 * fingerprints listed in <b>failed</>). */
1608 dir_routerdesc_download_failed(smartlist_t
*failed
)
1610 char digest
[DIGEST_LEN
];
1611 local_routerstatus_t
*rs
;
1612 time_t now
= time(NULL
);
1613 int server
= server_mode(get_options()) && get_options()->DirPort
;
1614 SMARTLIST_FOREACH(failed
, const char *, cp
,
1616 base16_decode(digest
, DIGEST_LEN
, cp
, strlen(cp
));
1617 rs
= router_get_combined_status_by_digest(digest
);
1618 if (!rs
|| rs
->n_download_failures
>= MAX_ROUTERDESC_DOWNLOAD_FAILURES
)
1620 ++rs
->n_download_failures
;
1622 switch (rs
->n_download_failures
) {
1623 case 1: rs
->next_attempt_at
= 0; break;
1624 case 2: rs
->next_attempt_at
= 0; break;
1625 case 3: rs
->next_attempt_at
= now
+60; break;
1626 case 4: rs
->next_attempt_at
= now
+60; break;
1627 case 5: rs
->next_attempt_at
= now
+60*2; break;
1628 case 6: rs
->next_attempt_at
= now
+60*5; break;
1629 case 7: rs
->next_attempt_at
= now
+60*15; break;
1630 default: rs
->next_attempt_at
= TIME_MAX
; break;
1633 switch (rs
->n_download_failures
) {
1634 case 1: rs
->next_attempt_at
= 0; break;
1635 case 2: rs
->next_attempt_at
= now
+60; break;
1636 case 3: rs
->next_attempt_at
= now
+60*5; break;
1637 case 4: rs
->next_attempt_at
= now
+60*10; break;
1638 default: rs
->next_attempt_at
= TIME_MAX
; break;
1641 if (rs
->next_attempt_at
== 0)
1642 log_fn(LOG_DEBUG
, "%s failed %d time(s); I'll try again immediately.",
1643 cp
, (int)rs
->n_download_failures
);
1644 else if (rs
->next_attempt_at
< TIME_MAX
)
1645 log_fn(LOG_DEBUG
, "%s failed %d time(s); I'll try again in %d seconds.",
1646 cp
, (int)rs
->n_download_failures
, (int)(rs
->next_attempt_at
-now
));
1648 log_fn(LOG_DEBUG
, "%s failed %d time(s); Giving up for a while.",
1649 cp
, (int)rs
->n_download_failures
);
1652 /* update_router_descriptor_downloads(time(NULL)); */
1655 /* Given a directory <b>resource</b> request generated by us, containing zero
1656 * or more strings separated by plus signs, followed optionally by ".z", store
1657 * the strings, in order, into <b>fp_out</b>. If <b>compressed_out</b> is
1658 * non-NULL, set it to 1 if the resource ends in ".z", else set it to 0. If
1659 * decode_hex is true, then delete all elements that aren't hex digests, and
1663 dir_split_resource_into_fingerprints(const char *resource
,
1664 smartlist_t
*fp_out
, int *compressed_out
,
1667 smartlist_split_string(fp_out
, resource
, "+", 0, 0);
1669 *compressed_out
= 0;
1670 if (smartlist_len(fp_out
)) {
1671 char *last
= smartlist_get(fp_out
,smartlist_len(fp_out
)-1);
1672 size_t last_len
= strlen(last
);
1673 if (last_len
> 2 && !strcmp(last
+last_len
-2, ".z")) {
1674 last
[last_len
-2] = '\0';
1676 *compressed_out
= 1;
1681 char *cp
, *d
= NULL
;
1682 for (i
= 0; i
< smartlist_len(fp_out
); ++i
) {
1683 cp
= smartlist_get(fp_out
, i
);
1684 if (strlen(cp
) != HEX_DIGEST_LEN
) {
1685 smartlist_del(fp_out
, i
--);
1688 d
= tor_malloc_zero(DIGEST_LEN
);
1689 if (base16_decode(d
, DIGEST_LEN
, cp
, HEX_DIGEST_LEN
)<0) {
1690 smartlist_del(fp_out
, i
--);
1693 smartlist_set(fp_out
, i
, d
);