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 warn(LD_BUG
, "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
;
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.
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
;
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
);
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
);
191 if (purpose
== DIR_PURPOSE_FETCH_DIR
)
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";
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
);
204 directconn
= 0; /* last resort: try routing it via Tor */
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
);
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
);
221 directory_initiate_command_router(r
, purpose
, !directconn
,
224 directory_initiate_command_trusted_dir(ds
, purpose
, !directconn
,
228 "No running dirservers known. Will try again later. (purpose %d)",
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
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>. **/
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.
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",
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",
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.
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. */
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,
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.
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. */
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
)
357 tor_assert(dir_port
);
361 case DIR_PURPOSE_FETCH_DIR
:
362 debug(LD_DIR
,"initiating directory fetch");
364 case DIR_PURPOSE_FETCH_RENDDESC
:
365 debug(LD_DIR
,"initiating hidden-service descriptor fetch");
367 case DIR_PURPOSE_UPLOAD_DIR
:
368 debug(LD_OR
,"initiating server descriptor upload");
370 case DIR_PURPOSE_UPLOAD_RENDDESC
:
371 debug(LD_REND
,"initiating hidden-service descriptor upload");
373 case DIR_PURPOSE_FETCH_RUNNING_LIST
:
374 debug(LD_DIR
,"initiating running-routers fetch");
376 case DIR_PURPOSE_FETCH_NETWORKSTATUS
:
377 debug(LD_DIR
,"initiating network-status fetch");
379 case DIR_PURPOSE_FETCH_SERVERDESC
:
380 debug(LD_DIR
,"initiating server descriptor fetch");
383 err(LD_BUG
, "Unrecognized directory connection purpose.");
387 conn
= connection_new(CONN_TYPE_DIR
);
389 /* set up conn so it's got all the data we need to remember */
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
)) {
410 connection_dir_request_failed(conn
); /* retry if we want */
411 connection_free(conn
);
414 conn
->state
= DIR_CONN_STATE_CLIENT_SENDING
; /* start flushing conn */
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
);
431 warn(LD_NET
,"Making AP bridge to dirserver failed.");
432 connection_mark_for_close(conn
);
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.
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];
458 const char *httpcommand
= NULL
;
462 tor_assert(conn
->type
== CONN_TYPE_DIR
);
464 tor_free(conn
->requested_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
));
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
);
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
);
492 proxyauthstring
[0] = 0;
496 proxyauthstring
[0] = 0;
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>");
506 url
= tor_strdup("/tor/dir.z");
508 case DIR_PURPOSE_FETCH_RUNNING_LIST
:
509 tor_assert(!resource
);
510 tor_assert(!payload
);
512 url
= tor_strdup("/tor/running-routers");
514 case DIR_PURPOSE_FETCH_NETWORKSTATUS
:
516 len
= strlen(resource
)+32;
517 url
= tor_malloc(len
);
518 tor_snprintf(url
, len
, "/tor/status/%s", resource
);
520 case DIR_PURPOSE_FETCH_SERVERDESC
:
522 len
= strlen(resource
)+32;
523 url
= tor_malloc(len
);
524 tor_snprintf(url
, len
, "/tor/server/%s", resource
);
526 case DIR_PURPOSE_UPLOAD_DIR
:
527 tor_assert(!resource
);
529 httpcommand
= "POST";
530 url
= tor_strdup("/tor/");
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
));
542 /* Request the most recent versioned descriptor. */
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
);
549 case DIR_PURPOSE_UPLOAD_RENDDESC
:
550 tor_assert(!resource
);
552 httpcommand
= "POST";
553 url
= tor_strdup("/tor/rendezvous/publish");
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
);
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,
568 connection_write_to_buf(request
, strlen(request
), conn
);
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
578 * "\%s [http[s]://]\%s HTTP/1..."
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.
586 parse_http_url(char *headers
, char **url
)
588 char *s
, *start
, *tmp
;
590 s
= (char *)eat_whitespace_no_nl(headers
);
592 s
= (char *)find_whitespace(s
); /* get past GET/POST */
594 s
= (char *)eat_whitespace_no_nl(s
);
596 start
= s
; /* this is it, assuming it's valid */
597 s
= (char *)find_whitespace(start
);
600 /* tolerate the http[s] proxy style of putting the hostname in the url */
601 if (s
-start
>= 4 && !strcmpstart(start
,"http")) {
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");
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);
619 *url
= tor_strndup(start
, s
-start
);
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. */
629 http_get_header(const char *headers
, const char *which
)
631 const char *cp
= headers
;
633 if (!strcmpstart(cp
, which
)) {
636 if ((eos
= strchr(cp
,'\r')))
637 return tor_strndup(cp
, eos
-cp
);
639 return tor_strdup(cp
);
641 cp
= strchr(cp
, '\n');
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')".
653 http_get_origin(const char *headers
, connection_t
*conn
)
657 fwd
= http_get_header(headers
, "Forwarded-For: ");
659 fwd
= http_get_header(headers
, "X-Forwarded-For: ");
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
);
667 size_t len
= strlen(conn
->address
)+3;
668 char *result
= tor_malloc(len
);
669 tor_snprintf(result
, len
, "'%s'", conn
->address
);
674 /** Parse an HTTP response string <b>headers</b> of the form
676 * "HTTP/1.\%d \%d\%s\r\n...".
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
691 parse_http_response(const char *headers
, int *code
, time_t *date
,
692 int *compression
, char **reason
)
695 char datestr
[RFC1123_TIME_LEN
+1];
696 smartlist_t
*parsed_headers
;
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
);
710 parsed_headers
= smartlist_create();
711 smartlist_split_string(parsed_headers
, headers
, "\n",
712 SPLIT_SKIP_SPACE
|SPLIT_IGNORE_BLANK
, -1);
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
);
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
);
740 const char *enc
= NULL
;
741 SMARTLIST_FOREACH(parsed_headers
, const char *, s
,
742 if (!strcmpstart(s
, "Content-Encoding: ")) {
745 if (!enc
|| !strcmp(enc
, "identity")) {
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
;
752 info(LD_HTTP
, "Unrecognized content encoding: '%s'. Trying to deal.", enc
);
756 SMARTLIST_FOREACH(parsed_headers
, char *, s
, tor_free(s
));
757 smartlist_free(parsed_headers
);
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.
766 body_is_plausible(const char *body
, size_t len
, int purpose
)
770 return 1; /* empty bodies don't need decompression */
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"))
780 if (!TOR_ISPRINT(body
[i
]) && !TOR_ISSPACE(body
[i
]))
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.
799 connection_dir_client_reached_eof(connection_t
*conn
)
806 time_t now
, date_header
=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
,
817 case -1: /* overflow */
818 warn(LD_PROTOCOL
,"'fetch' response too large (server '%s:%d'). Closing.", conn
->address
, conn
->port
);
821 info(LD_HTTP
,"'fetch' response not all here, but we're at eof. Closing.");
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
);
832 if (!reason
) reason
= tor_strdup("[no reason given]");
835 "Received response from directory server '%s:%d': %d \"%s\"",
836 conn
->address
, conn
->port
, status_code
, reason
);
838 if (date_header
> 0) {
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
,
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 */
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
;
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";
869 description1
= "with an unknown Content-Encoding";
870 if (guessed
== ZLIB_METHOD
)
871 description2
= "deflated";
872 else if (guessed
== GZIP_METHOD
)
873 description2
= "gzipped";
875 description2
= "confusing binary junk";
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. */
886 tor_gzip_uncompress(&new_body
, &new_len
, body
, body_len
, compression
,
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
,
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
);
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
);
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
);
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
);
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
);
946 if (conn
->purpose
== DIR_PURPOSE_FETCH_NETWORKSTATUS
) {
947 smartlist_t
*which
= NULL
;
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
);
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,
966 char *next
= strstr(cp
, "\nnetwork-status-version");
969 /* learn from it, and then remove it from 'which' */
970 if (router_set_networkstatus(cp
, time(NULL
), NS_FROM_DIR
, which
)<0)
979 routers_update_all_from_networkstatus(); /*launches router downloads*/
980 directory_info_has_arrived(time(NULL
), 0);
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
;
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,
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
);
1012 connection_dir_download_routerdesc_failed(conn
);
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
);
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
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();
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
) {
1057 info(LD_GENERAL
,"eof (status 200) after uploading server descriptor: finished.");
1060 warn(LD_GENERAL
,"http status 400 (\"%s\") response from dirserver '%s:%d'. Please correct.", reason
, conn
->address
, conn
->port
);
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
);
1070 warn(LD_GENERAL
,"http status %d (\"%s\") reason unexpected (server '%s:%d').", status_code
, reason
, conn
->address
, conn
->port
);
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
) {
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
1087 /* success. notify pending connections about this. */
1088 conn
->purpose
= DIR_PURPOSE_HAS_FETCHED_RENDDESC
;
1089 rend_client_desc_here(conn
->rend_query
);
1093 /* not there. pending connections will be notified when
1094 * connection_mark_for_close cleans it up. */
1097 warn(LD_REND
,"http status 400 (\"%s\"). Dirserver didn't like our rendezvous query?", reason
);
1100 warn(LD_REND
,"http status %d (\"%s\") response unexpected (server '%s:%d').", status_code
, reason
, conn
->address
, conn
->port
);
1105 if (conn
->purpose
== DIR_PURPOSE_UPLOAD_RENDDESC
) {
1106 switch (status_code
) {
1108 info(LD_REND
,"Uploading rendezvous descriptor: finished with status 200 (\"%s\")", reason
);
1111 warn(LD_REND
,"http status 400 (\"%s\") response from dirserver '%s:%d'. Malformed rendezvous descriptor?", reason
, conn
->address
, conn
->port
);
1114 warn(LD_REND
,"http status %d (\"%s\") response unexpected (server '%s:%d').", status_code
, reason
, conn
->address
, conn
->port
);
1118 tor_free(body
); tor_free(headers
); tor_free(reason
);
1122 /** Called when a directory connection reaches EOF */
1124 connection_dir_reached_eof(connection_t
*conn
)
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
);
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
);
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
)
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
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
);
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.");
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>.
1182 write_http_status_line(connection_t
*conn
, int status
,
1183 const char *reason_phrase
)
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.");
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.
1199 already_fetching_directory(int purpose
)
1203 connection_t
**carray
;
1205 get_connection_array(&carray
,&n
);
1208 if (conn
->type
== CONN_TYPE_DIR
&&
1209 conn
->purpose
== purpose
&&
1210 !conn
->marked_for_close
&&
1211 !router_digest_is_me(conn
->identity_digest
))
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. */
1223 directory_handle_command_get(connection_t
*conn
, char *headers
,
1224 char *body
, size_t body_len
)
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");
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
);
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);
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",
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
);
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");
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);
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",
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
);
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/");
1301 url
[url_len
-2] = '\0';
1302 if (dirserv_get_networkstatus_v2(dir_objs
, key
)) {
1303 smartlist_free(dir_objs
);
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
);
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",
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
,
1325 connection_write_to_buf(d
->dir_z
, d
->dir_z_len
, conn
);
1327 connection_write_to_buf(d
->dir
, d
->dir_len
, conn
);
1329 smartlist_free(dir_objs
);
1333 if (!strcmpstart(url
,"/tor/server/")) {
1334 size_t url_len
= strlen(url
);
1335 int deflated
= !strcmp(url
+url_len
-2, ".z");
1338 smartlist_t
*descs
= smartlist_create();
1340 url
[url_len
-2] = '\0';
1341 res
= dirserv_get_routerdescs(descs
, url
, &msg
);
1344 write_http_status_line(conn
, 404, msg
);
1347 format_rfc1123_time(date
, time(NULL
));
1348 SMARTLIST_FOREACH(descs
, signed_descriptor_t
*, ri
,
1349 len
+= ri
->signed_descriptor_len
);
1351 size_t compressed_len
;
1353 char *inp
= tor_malloc(len
+smartlist_len(descs
)+1);
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
;
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) {
1368 smartlist_free(descs
);
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",
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
);
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",
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
,
1394 smartlist_free(descs
);
1398 if (!strcmpstart(url
,"/tor/rendezvous/") ||
1399 !strcmpstart(url
,"/tor/rendezvous1/")) {
1400 /* rendezvous descriptor fetch */
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.
1412 write_http_status_line(conn
, 400, "Nonauthoritative directory does not not store rendezvous descriptors");
1416 switch (rend_cache_lookup_desc(query
, versioned
?-1:0, &descp
, &desc_len
)) {
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",
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
);
1425 case 0: /* well-formed but not present */
1426 write_http_status_line(conn
, 404, "Not found");
1428 case -1: /* not well-formed */
1429 write_http_status_line(conn
, 400, "Bad request");
1436 /* we didn't recognize the url */
1437 write_http_status_line(conn
, 404, "Not found");
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. */
1448 directory_handle_command_post(connection_t
*conn
, char *headers
,
1449 char *body
, size_t body_len
)
1452 char *origin
= 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");
1466 if (parse_http_url(headers
, &url
) < 0) {
1467 write_http_status_line(conn
, 400, "Bad request");
1470 debug(LD_DIRSERV
,"rewritten url as '%s'.", url
);
1471 origin
= http_get_origin(headers
, conn
);
1473 if (!strcmp(url
,"/tor/")) { /* server descriptor post */
1475 int r
= dirserv_add_descriptor(body
, &msg
);
1478 dirserv_get_directory(&cp
, 0); /* rebuild and write to disk */
1483 notice(LD_DIRSERV
,"Rejected descriptor from %s.", origin
);
1484 /* malformed descriptor, or something wrong */
1485 write_http_status_line(conn
, 400, msg
);
1487 case 0: /* accepted but discarded */
1488 case 2: /* accepted */
1489 write_http_status_line(conn
, 200, msg
);
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");
1500 write_http_status_line(conn
, 200, "Service descriptor stored");
1504 /* we didn't recognize the url */
1505 write_http_status_line(conn
, 404, "Not found");
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.
1520 directory_handle_command(connection_t
*conn
)
1522 char *headers
=NULL
, *body
=NULL
;
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 */
1534 "Invalid input from address '%s'. Closing.", conn
->address
);
1537 debug(LD_DIRSERV
,"command not all here yet.");
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
);
1549 warn(LD_PROTOCOL
,"Got headers '%s' with unknown command. Closing.", headers
);
1553 tor_free(headers
); tor_free(body
);
1557 /** Write handler for directory connections; called when all data has
1558 * been flushed. Close the connection or wait for a response as
1562 connection_dir_finished_flushing(connection_t
*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
);
1573 case DIR_CONN_STATE_SERVER_WRITING
:
1574 debug(LD_DIRSERV
,"Finished writing server response. Closing.");
1575 connection_mark_for_close(conn
);
1578 warn(LD_BUG
,"Bug: called in unexpected state %d.", conn
->state
);
1579 tor_fragile_assert();
1585 /** Connected handler for directory connections: begin sending data to the
1588 connection_dir_finished_connecting(connection_t
*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 */
1601 /** Called when one or more networkstatus fetches have failed (with uppercase
1602 * fingerprints listed in <b>failed</>). Mark those fingerprints has having
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
);
1615 ++dir
->n_networkstatus_failures
;
1619 /** Called when one or more networkstatus fetches have failed (with uppercase
1620 * fingerprints listed in <b>failed</>). */
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
)
1634 ++rs
->n_download_failures
;
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;
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
));
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
1677 dir_split_resource_into_fingerprints(const char *resource
,
1678 smartlist_t
*fp_out
, int *compressed_out
,
1683 old_len
= smartlist_len(fp_out
);
1684 smartlist_split_string(fp_out
, resource
, "+", 0, 0);
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';
1693 *compressed_out
= 1;
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
--);
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
--);
1712 smartlist_set(fp_out
, i
, d
);