1 /* Copyright 2001-2004 Roger Dingledine.
2 * Copyright 2004-2006 Roger Dingledine, Nick Mathewson. */
3 /* See LICENSE for licensing information */
5 const char directory_c_id
[] =
12 * \brief Code to send and fetch directories and router
13 * descriptors via HTTP. Directories use dirserv.c to generate the
14 * results; clients use routers.c to parse them.
17 /* In-points to directory.c:
19 * - directory_post_to_dirservers(), called from
20 * router_upload_dir_desc_to_dirservers() in router.c
21 * upload_service_descriptor() in rendservice.c
22 * - directory_get_from_dirserver(), called from
23 * rend_client_refetch_renddesc() in rendclient.c
24 * run_scheduled_events() in main.c
26 * - connection_dir_process_inbuf(), called from
27 * connection_process_inbuf() in connection.c
28 * - connection_dir_finished_flushing(), called from
29 * connection_finished_flushing() in connection.c
30 * - connection_dir_finished_connecting(), called from
31 * connection_finished_connecting() in connection.c
34 directory_initiate_command(const char *address
, uint32_t addr
, uint16_t port
,
36 const char *digest
, uint8_t purpose
,
37 int private_connection
, const char *resource
,
38 const char *payload
, size_t payload_len
);
41 directory_send_command(connection_t
*conn
, const char *platform
,
42 int purpose
, const char *resource
,
43 const char *payload
, size_t payload_len
);
44 static int directory_handle_command(connection_t
*conn
);
45 static int body_is_plausible(const char *body
, size_t body_len
, int purpose
);
46 static int purpose_is_private(uint8_t purpose
);
47 static char *http_get_header(const char *headers
, const char *which
);
48 static char *http_get_origin(const char *headers
, connection_t
*conn
);
49 static void connection_dir_download_networkstatus_failed(connection_t
*conn
);
50 static void connection_dir_download_routerdesc_failed(connection_t
*conn
);
51 static void dir_networkstatus_download_failed(smartlist_t
*failed
);
52 static void dir_routerdesc_download_failed(smartlist_t
*failed
);
53 static void note_request(const char *key
, size_t bytes
);
55 /********* START VARIABLES **********/
57 static addr_policy_t
*dir_policy
= NULL
;
59 #define ALLOW_DIRECTORY_TIME_SKEW 30*60 /* 30 minutes */
61 /********* END VARIABLES ************/
63 /** Parse get_options()->DirPolicy, and put the processed version in
64 * &dir_policy. Ignore port specifiers.
67 parse_dir_policy(void)
71 addr_policy_free(dir_policy
);
74 config_parse_addr_policy(get_options()->DirPolicy
, &dir_policy
, -1);
75 /* ports aren't used. */
76 for (n
=dir_policy
; n
; n
= n
->next
) {
82 /** Free storage used to hold parsed directory policy */
86 addr_policy_free(dir_policy
);
90 /** Return 1 if <b>addr</b> is permitted to connect to our dir port,
91 * based on <b>dir_policy</b>. Else return 0.
94 dir_policy_permits_address(uint32_t addr
)
98 if (!dir_policy
) /* 'no dir policy' means 'accept' */
100 a
= router_compare_addr_to_addr_policy(addr
, 1, dir_policy
);
101 if (a
==ADDR_POLICY_REJECTED
)
103 else if (a
==ADDR_POLICY_ACCEPTED
)
105 log_warn(LD_BUG
, "Bug: got unexpected 'maybe' answer from dir policy");
109 /** Return true iff the directory purpose 'purpose' must use an
110 * anonymous connection to a directory. */
112 purpose_is_private(uint8_t purpose
)
114 if (get_options()->AllDirActionsPrivate
)
116 if (purpose
== DIR_PURPOSE_FETCH_DIR
||
117 purpose
== DIR_PURPOSE_UPLOAD_DIR
||
118 purpose
== DIR_PURPOSE_FETCH_RUNNING_LIST
||
119 purpose
== DIR_PURPOSE_FETCH_NETWORKSTATUS
||
120 purpose
== DIR_PURPOSE_FETCH_SERVERDESC
)
125 /** Start a connection to every known directory server, using
126 * connection purpose 'purpose' and uploading the payload 'payload'
127 * (length 'payload_len'). The purpose should be one of
128 * 'DIR_PURPOSE_UPLOAD_DIR' or 'DIR_PURPOSE_UPLOAD_RENDDESC'.
131 directory_post_to_dirservers(uint8_t purpose
, const char *payload
,
134 smartlist_t
*dirservers
;
138 router_get_trusted_dir_servers(&dirservers
);
139 tor_assert(dirservers
);
140 /* Only old dirservers handle rendezvous descriptor publishing. */
141 post_to_v1_only
= (purpose
== DIR_PURPOSE_UPLOAD_RENDDESC
);
142 /* This tries dirservers which we believe to be down, but ultimately, that's
143 * harmless, and we may as well err on the side of getting things uploaded.
145 SMARTLIST_FOREACH(dirservers
, trusted_dir_server_t
*, ds
,
147 routerstatus_t
*rs
= &(ds
->fake_status
);
148 if (post_to_v1_only
&& !ds
->is_v1_authority
)
150 post_via_tor
= purpose_is_private(purpose
) ||
151 !fascist_firewall_allows_address_dir(ds
->addr
, ds
->dir_port
);
152 directory_initiate_command_routerstatus(rs
, purpose
, post_via_tor
,
153 NULL
, payload
, payload_len
);
157 /** Start a connection to a random running directory server, using
158 * connection purpose 'purpose' and requesting 'resource'.
159 * If <b>retry_if_no_servers</b>, then if all the possible servers seem
160 * down, mark them up and try again.
163 directory_get_from_dirserver(uint8_t purpose
, const char *resource
,
164 int retry_if_no_servers
)
166 routerstatus_t
*rs
= NULL
;
167 or_options_t
*options
= get_options();
168 int prefer_authority
= server_mode(options
) && options
->DirPort
!= 0;
169 int directconn
= !purpose_is_private(purpose
);
171 int need_v1_support
= purpose
== DIR_PURPOSE_FETCH_DIR
||
172 purpose
== DIR_PURPOSE_FETCH_RUNNING_LIST
;
173 int need_v2_support
= purpose
== DIR_PURPOSE_FETCH_NETWORKSTATUS
||
174 purpose
== DIR_PURPOSE_FETCH_SERVERDESC
;
176 if (!options
->FetchServerDescriptors
&&
177 (need_v1_support
|| need_v2_support
))
181 if (prefer_authority
) {
182 /* only ask authdirservers, and don't ask myself */
183 rs
= router_pick_trusteddirserver(need_v1_support
, 1, 1,
184 retry_if_no_servers
);
187 /* anybody with a non-zero dirport will do */
188 rs
= router_pick_directory_server(1, 1, need_v2_support
,
189 retry_if_no_servers
);
192 if (purpose
== DIR_PURPOSE_FETCH_DIR
)
194 else if (purpose
== DIR_PURPOSE_FETCH_RUNNING_LIST
)
195 which
= "status list";
196 else if (purpose
== DIR_PURPOSE_FETCH_NETWORKSTATUS
)
197 which
= "network status";
198 else // if (purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS)
199 which
= "server descriptors";
201 "No router found for %s; falling back to dirserver list",
203 rs
= router_pick_trusteddirserver(1, 1, 1,
204 retry_if_no_servers
);
206 directconn
= 0; /* last resort: try routing it via Tor */
211 /* Never use fascistfirewall; we're going via Tor. */
212 if (purpose
== DIR_PURPOSE_FETCH_RENDDESC
) {
213 /* only ask authdirservers, any of them will do */
214 rs
= router_pick_trusteddirserver(0, 0, 0, retry_if_no_servers
);
216 /* anybody with a non-zero dirport will do. Disregard firewalls. */
217 rs
= router_pick_directory_server(1, 0, need_v2_support
,
218 retry_if_no_servers
);
219 /* If we have any hope of building an indirect conn, we know some router
220 * descriptors. If (rs==NULL), we can't build circuits anyway, so
221 * there's no point in falling back to the authorities in this case. */
226 directory_initiate_command_routerstatus(rs
, purpose
, !directconn
,
230 "No running dirservers known. Will try again later. "
231 "(purpose %d)", purpose
);
232 if (!purpose_is_private(purpose
)) {
233 /* remember we tried them all and failed. */
234 directory_all_unreachable(time(NULL
));
239 /** Launch a new connection to the directory server <b>router</b> to upload or
240 * download a service or rendezvous descriptor. <b>purpose</b> determines what
241 * kind of directory connection we're launching, and must be one of
242 * DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC}.
244 * When uploading, <b>payload</b> and <b>payload_len</b> determine the content
245 * of the HTTP post. Otherwise, <b>payload</b> should be NULL.
247 * When fetching a rendezvous descriptor, <b>resource</b> is the service ID we
251 directory_initiate_command_router(routerinfo_t
*router
,
253 int private_connection
,
254 const char *resource
,
258 directory_initiate_command(router
->address
, router
->addr
, router
->dir_port
,
260 router
->cache_info
.identity_digest
,
261 purpose
, private_connection
, resource
,
262 payload
, payload_len
);
265 /** Launch a new connection to the directory server <b>status</b> to upload or
266 * download a service or rendezvous descriptor. <b>purpose</b> determines what
267 * kind of directory connection we're launching, and must be one of
268 * DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC}.
270 * When uploading, <b>payload</b> and <b>payload_len</b> determine the content
271 * of the HTTP post. Otherwise, <b>payload</b> should be NULL.
273 * When fetching a rendezvous descriptor, <b>resource</b> is the service ID we
277 directory_initiate_command_routerstatus(routerstatus_t
*status
,
279 int private_connection
,
280 const char *resource
,
284 const char *platform
= NULL
;
285 routerinfo_t
*router
;
286 char address_buf
[INET_NTOA_BUF_LEN
];
289 if ((router
= router_get_by_digest(status
->identity_digest
))) {
290 platform
= router
->platform
;
291 address
= router
->address
;
293 in
.s_addr
= htonl(status
->addr
);
294 tor_inet_ntoa(&in
, address_buf
, sizeof(address_buf
));
295 address
= address_buf
;
297 directory_initiate_command(address
, status
->addr
, status
->dir_port
,
298 platform
, status
->identity_digest
,
299 purpose
, private_connection
, resource
,
300 payload
, payload_len
);
303 /** Called when we are unable to complete the client's request to a
304 * directory server: Mark the router as down and try again if possible.
307 connection_dir_request_failed(connection_t
*conn
)
309 if (router_digest_is_me(conn
->identity_digest
))
310 return; /* this was a test fetch. don't retry. */
311 router_mark_as_down(conn
->identity_digest
); /* don't try him again */
312 if (conn
->purpose
== DIR_PURPOSE_FETCH_DIR
||
313 conn
->purpose
== DIR_PURPOSE_FETCH_RUNNING_LIST
) {
314 log_info(LD_DIR
, "Giving up on directory server at '%s:%d'; retrying",
315 conn
->address
, conn
->port
);
316 directory_get_from_dirserver(conn
->purpose
, NULL
,
317 0 /* don't retry_if_no_servers */);
318 } else if (conn
->purpose
== DIR_PURPOSE_FETCH_NETWORKSTATUS
) {
319 log_info(LD_DIR
, "Giving up on directory server at '%s'; retrying",
321 connection_dir_download_networkstatus_failed(conn
);
322 } else if (conn
->purpose
== DIR_PURPOSE_FETCH_SERVERDESC
) {
323 log_info(LD_DIR
, "Giving up on directory server at '%s'; retrying",
325 connection_dir_download_routerdesc_failed(conn
);
329 /** Called when an attempt to download one or more network status
330 * documents on connection <b>conn</b> failed. Decide whether to
331 * retry the fetch now, later, or never.
334 connection_dir_download_networkstatus_failed(connection_t
*conn
)
336 if (!conn
->requested_resource
) {
337 /* We never reached directory_send_command, which means that we never
338 * opened a network connection. Either we're out of sockets, or the
339 * network is down. Either way, retrying would be pointless. */
342 if (!strcmpstart(conn
->requested_resource
, "all")) {
343 /* We're a non-authoritative directory cache; try again. */
344 directory_get_from_dirserver(conn
->purpose
, "all.z",
345 0 /* don't retry_if_no_servers */);
346 } else if (!strcmpstart(conn
->requested_resource
, "fp/")) {
347 /* We were trying to download by fingerprint; mark them all as having
348 * failed, and possibly retry them later.*/
349 smartlist_t
*failed
= smartlist_create();
350 dir_split_resource_into_fingerprints(conn
->requested_resource
+3,
352 if (smartlist_len(failed
)) {
353 dir_networkstatus_download_failed(failed
);
354 SMARTLIST_FOREACH(failed
, char *, cp
, tor_free(cp
));
356 smartlist_free(failed
);
360 /** Called when an attempt to download one or more router descriptors
361 * on connection <b>conn</b> failed.
364 connection_dir_download_routerdesc_failed(connection_t
*conn
)
366 /* Try again. No need to increment the failure count for routerdescs, since
367 * it's not their fault.*/
368 /* update_router_descriptor_downloads(time(NULL)); */
371 /** Helper for directory_initiate_command_(router|trusted_dir): send the
372 * command to a server whose address is <b>address</b>, whose IP is
373 * <b>addr</b>, whose directory port is <b>dir_port</b>, whose tor version is
374 * <b>platform</b>, and whose identity key digest is <b>digest</b>. The
375 * <b>platform</b> argument is optional; the others are required. */
377 directory_initiate_command(const char *address
, uint32_t addr
,
378 uint16_t dir_port
, const char *platform
,
379 const char *digest
, uint8_t purpose
,
380 int private_connection
, const char *resource
,
381 const char *payload
, size_t payload_len
)
387 tor_assert(dir_port
);
391 case DIR_PURPOSE_FETCH_DIR
:
392 log_debug(LD_DIR
,"initiating directory fetch");
394 case DIR_PURPOSE_FETCH_RENDDESC
:
395 log_debug(LD_DIR
,"initiating hidden-service descriptor fetch");
397 case DIR_PURPOSE_UPLOAD_DIR
:
398 log_debug(LD_OR
,"initiating server descriptor upload");
400 case DIR_PURPOSE_UPLOAD_RENDDESC
:
401 log_debug(LD_REND
,"initiating hidden-service descriptor upload");
403 case DIR_PURPOSE_FETCH_RUNNING_LIST
:
404 log_debug(LD_DIR
,"initiating running-routers fetch");
406 case DIR_PURPOSE_FETCH_NETWORKSTATUS
:
407 log_debug(LD_DIR
,"initiating network-status fetch");
409 case DIR_PURPOSE_FETCH_SERVERDESC
:
410 log_debug(LD_DIR
,"initiating server descriptor fetch");
413 log_err(LD_BUG
, "Unrecognized directory connection purpose.");
417 conn
= connection_new(CONN_TYPE_DIR
);
419 /* set up conn so it's got all the data we need to remember */
421 conn
->port
= dir_port
;
422 conn
->address
= tor_strdup(address
);
423 memcpy(conn
->identity_digest
, digest
, DIGEST_LEN
);
425 conn
->purpose
= purpose
;
427 /* give it an initial state */
428 conn
->state
= DIR_CONN_STATE_CONNECTING
;
430 if (!private_connection
) {
431 /* then we want to connect directly */
433 if (get_options()->HttpProxy
) {
434 addr
= get_options()->HttpProxyAddr
;
435 dir_port
= get_options()->HttpProxyPort
;
438 switch (connection_connect(conn
, conn
->address
, addr
, dir_port
)) {
440 connection_dir_request_failed(conn
); /* retry if we want */
441 connection_free(conn
);
444 conn
->state
= DIR_CONN_STATE_CLIENT_SENDING
; /* start flushing conn */
447 /* queue the command on the outbuf */
448 directory_send_command(conn
, platform
, purpose
, resource
,
449 payload
, payload_len
);
450 connection_watch_events(conn
, EV_READ
| EV_WRITE
);
451 /* writable indicates finish, readable indicates broken link,
452 error indicates broken link in windowsland. */
454 } else { /* we want to connect via tor */
455 /* make an AP connection
456 * populate it and add it at the right state
457 * socketpair and hook up both sides
459 conn
->s
= connection_ap_make_bridge(conn
->address
, conn
->port
);
461 log_warn(LD_NET
,"Making AP bridge to dirserver failed.");
462 connection_mark_for_close(conn
);
466 if (connection_add(conn
) < 0) {
467 log_warn(LD_NET
,"Unable to add AP bridge to dirserver.");
468 connection_mark_for_close(conn
);
471 conn
->state
= DIR_CONN_STATE_CLIENT_SENDING
;
472 /* queue the command on the outbuf */
473 directory_send_command(conn
, platform
, purpose
, resource
,
474 payload
, payload_len
);
475 connection_watch_events(conn
, EV_READ
| EV_WRITE
);
479 /** Queue an appropriate HTTP command on conn-\>outbuf. The other args
480 * are as in directory_initiate_command.
483 directory_send_command(connection_t
*conn
, const char *platform
,
484 int purpose
, const char *resource
,
485 const char *payload
, size_t payload_len
)
487 char proxystring
[256];
488 char proxyauthstring
[256];
489 char hoststring
[128];
492 const char *httpcommand
= NULL
;
496 tor_assert(conn
->type
== CONN_TYPE_DIR
);
498 tor_free(conn
->requested_resource
);
500 conn
->requested_resource
= tor_strdup(resource
);
502 /* come up with a string for which Host: we want */
503 if (conn
->port
== 80) {
504 strlcpy(hoststring
, conn
->address
, sizeof(hoststring
));
506 tor_snprintf(hoststring
, sizeof(hoststring
),"%s:%d",
507 conn
->address
, conn
->port
);
510 /* come up with some proxy lines, if we're using one. */
511 if (get_options()->HttpProxy
) {
512 char *base64_authenticator
=NULL
;
513 const char *authenticator
= get_options()->HttpProxyAuthenticator
;
515 tor_snprintf(proxystring
, sizeof(proxystring
),"http://%s", hoststring
);
517 base64_authenticator
= alloc_http_authenticator(authenticator
);
518 if (!base64_authenticator
)
519 log_warn(LD_BUG
, "Encoding http authenticator failed");
521 if (base64_authenticator
) {
522 tor_snprintf(proxyauthstring
, sizeof(proxyauthstring
),
523 "\r\nProxy-Authorization: Basic %s",
524 base64_authenticator
);
525 tor_free(base64_authenticator
);
527 proxyauthstring
[0] = 0;
531 proxyauthstring
[0] = 0;
535 case DIR_PURPOSE_FETCH_DIR
:
536 tor_assert(!resource
);
537 tor_assert(!payload
);
539 "Asking for compressed directory from server running %s",
540 platform
?escaped(platform
):"<unknown version>");
542 url
= tor_strdup("/tor/dir.z");
544 case DIR_PURPOSE_FETCH_RUNNING_LIST
:
545 tor_assert(!resource
);
546 tor_assert(!payload
);
548 url
= tor_strdup("/tor/running-routers");
550 case DIR_PURPOSE_FETCH_NETWORKSTATUS
:
552 len
= strlen(resource
)+32;
553 url
= tor_malloc(len
);
554 tor_snprintf(url
, len
, "/tor/status/%s", resource
);
556 case DIR_PURPOSE_FETCH_SERVERDESC
:
558 len
= strlen(resource
)+32;
559 url
= tor_malloc(len
);
560 tor_snprintf(url
, len
, "/tor/server/%s", resource
);
562 case DIR_PURPOSE_UPLOAD_DIR
:
563 tor_assert(!resource
);
565 httpcommand
= "POST";
566 url
= tor_strdup("/tor/");
568 case DIR_PURPOSE_FETCH_RENDDESC
:
569 tor_assert(resource
);
570 tor_assert(!payload
);
572 /* this must be true or we wouldn't be doing the lookup */
573 tor_assert(strlen(resource
) <= REND_SERVICE_ID_LEN
);
574 /* This breaks the function abstraction. */
575 strlcpy(conn
->rend_query
, resource
, sizeof(conn
->rend_query
));
578 /* Request the most recent versioned descriptor. */
580 //tor_snprintf(url, sizeof(url), "/tor/rendezvous1/%s", resource);
581 len
= strlen(resource
)+32;
582 url
= tor_malloc(len
);
583 tor_snprintf(url
, len
, "/tor/rendezvous/%s", resource
);
585 case DIR_PURPOSE_UPLOAD_RENDDESC
:
586 tor_assert(!resource
);
588 httpcommand
= "POST";
589 url
= tor_strdup("/tor/rendezvous/publish");
596 if (strlen(proxystring
) + strlen(url
) >= 4096) {
598 "Bug: squid does not like URLs longer than 4095 bytes, this "
599 "one is %d bytes long: %s%s",
600 (int)(strlen(proxystring
) + strlen(url
)), proxystring
, url
);
603 tor_snprintf(request
, sizeof(request
), "%s %s", httpcommand
, proxystring
);
604 connection_write_to_buf(request
, strlen(request
), conn
);
605 connection_write_to_buf(url
, strlen(url
), conn
);
608 if (!strcmp(httpcommand
, "GET") && !payload
) {
609 tor_snprintf(request
, sizeof(request
),
610 " HTTP/1.0\r\nHost: %s%s\r\n\r\n",
614 tor_snprintf(request
, sizeof(request
),
615 " HTTP/1.0\r\nContent-Length: %lu\r\nHost: %s%s\r\n\r\n",
616 payload
? (unsigned long)payload_len
: 0,
620 connection_write_to_buf(request
, strlen(request
), conn
);
623 /* then send the payload afterwards too */
624 connection_write_to_buf(payload
, payload_len
, conn
);
628 /** Parse an HTTP request string <b>headers</b> of the form
630 * "\%s [http[s]://]\%s HTTP/1..."
632 * If it's well-formed, strdup the second \%s into *<b>url</b>, and
633 * null-terminate it. If the url doesn't start with "/tor/", rewrite it
634 * so it does. Return 0.
635 * Otherwise, return -1.
638 parse_http_url(char *headers
, char **url
)
640 char *s
, *start
, *tmp
;
642 s
= (char *)eat_whitespace_no_nl(headers
);
644 s
= (char *)find_whitespace(s
); /* get past GET/POST */
646 s
= (char *)eat_whitespace_no_nl(s
);
648 start
= s
; /* this is it, assuming it's valid */
649 s
= (char *)find_whitespace(start
);
652 /* tolerate the http[s] proxy style of putting the hostname in the url */
653 if (s
-start
>= 4 && !strcmpstart(start
,"http")) {
657 if (s
-tmp
>= 3 && !strcmpstart(tmp
,"://")) {
658 tmp
= strchr(tmp
+3, '/');
659 if (tmp
&& tmp
< s
) {
660 log_debug(LD_DIR
,"Skipping over 'http[s]://hostname' string");
666 if (s
-start
< 5 || strcmpstart(start
,"/tor/")) { /* need to rewrite it */
667 *url
= tor_malloc(s
- start
+ 5);
668 strlcpy(*url
,"/tor", s
-start
+5);
669 strlcat((*url
)+4, start
, s
-start
+1);
671 *url
= tor_strndup(start
, s
-start
);
676 /** Return a copy of the first HTTP header in <b>headers</b> whose key is
677 * <b>which</b>. The key should be given with a terminating colon and space;
678 * this function copies everything after, up to but not including the
679 * following \\r\\n. */
681 http_get_header(const char *headers
, const char *which
)
683 const char *cp
= headers
;
685 if (!strcmpstart(cp
, which
)) {
688 if ((eos
= strchr(cp
,'\r')))
689 return tor_strndup(cp
, eos
-cp
);
691 return tor_strdup(cp
);
693 cp
= strchr(cp
, '\n');
700 /** Allocate and return a string describing the source of an HTTP request with
701 * headers <b>headers</b> received on <b>conn</b>. The format is either
702 * "'1.2.3.4'", or "'1.2.3.4' (forwarded for '5.6.7.8')".
705 http_get_origin(const char *headers
, connection_t
*conn
)
709 fwd
= http_get_header(headers
, "Forwarded-For: ");
711 fwd
= http_get_header(headers
, "X-Forwarded-For: ");
713 size_t len
= strlen(fwd
)+strlen(conn
->address
)+32;
714 char *result
= tor_malloc(len
);
715 tor_snprintf(result
, len
, "'%s' (forwarded for %s)", conn
->address
,
720 size_t len
= strlen(conn
->address
)+3;
721 char *result
= tor_malloc(len
);
722 tor_snprintf(result
, len
, "'%s'", conn
->address
);
727 /** Parse an HTTP response string <b>headers</b> of the form
729 * "HTTP/1.\%d \%d\%s\r\n...".
732 * If it's well-formed, assign the status code to *<b>code</b> and
733 * return 0. Otherwise, return -1.
735 * On success: If <b>date</b> is provided, set *date to the Date
736 * header in the http headers, or 0 if no such header is found. If
737 * <b>compression</b> is provided, set *<b>compression</b> to the
738 * compression method given in the Content-Encoding header, or 0 if no
739 * such header is found, or -1 if the value of the header is not
740 * recognized. If <b>reason</b> is provided, strdup the reason string
744 parse_http_response(const char *headers
, int *code
, time_t *date
,
745 int *compression
, char **reason
)
748 char datestr
[RFC1123_TIME_LEN
+1];
749 smartlist_t
*parsed_headers
;
753 while (TOR_ISSPACE(*headers
)) headers
++; /* tolerate leading whitespace */
755 if (sscanf(headers
, "HTTP/1.%d %d", &n1
, &n2
) < 2 ||
756 (n1
!= 0 && n1
!= 1) ||
757 (n2
< 100 || n2
>= 600)) {
758 log_warn(LD_HTTP
,"Failed to parse header %s",escaped(headers
));
763 parsed_headers
= smartlist_create();
764 smartlist_split_string(parsed_headers
, headers
, "\n",
765 SPLIT_SKIP_SPACE
|SPLIT_IGNORE_BLANK
, -1);
767 smartlist_t
*status_line_elements
= smartlist_create();
768 tor_assert(smartlist_len(parsed_headers
));
769 smartlist_split_string(status_line_elements
,
770 smartlist_get(parsed_headers
, 0),
771 " ", SPLIT_SKIP_SPACE
|SPLIT_IGNORE_BLANK
, 3);
772 tor_assert(smartlist_len(status_line_elements
) <= 3);
773 if (smartlist_len(status_line_elements
) == 3) {
774 *reason
= smartlist_get(status_line_elements
, 2);
775 smartlist_set(status_line_elements
, 2, NULL
); /* Prevent free */
777 SMARTLIST_FOREACH(status_line_elements
, char *, cp
, tor_free(cp
));
778 smartlist_free(status_line_elements
);
782 SMARTLIST_FOREACH(parsed_headers
, const char *, s
,
783 if (!strcmpstart(s
, "Date: ")) {
784 strlcpy(datestr
, s
+6, sizeof(datestr
));
785 /* This will do nothing on failure, so we don't need to check
786 the result. We shouldn't warn, since there are many other valid
787 date formats besides the one we use. */
788 parse_rfc1123_time(datestr
, date
);
793 const char *enc
= NULL
;
794 SMARTLIST_FOREACH(parsed_headers
, const char *, s
,
795 if (!strcmpstart(s
, "Content-Encoding: ")) {
798 if (!enc
|| !strcmp(enc
, "identity")) {
800 } else if (!strcmp(enc
, "deflate") || !strcmp(enc
, "x-deflate")) {
801 *compression
= ZLIB_METHOD
;
802 } else if (!strcmp(enc
, "gzip") || !strcmp(enc
, "x-gzip")) {
803 *compression
= GZIP_METHOD
;
805 log_info(LD_HTTP
, "Unrecognized content encoding: %s. Trying to deal.",
810 SMARTLIST_FOREACH(parsed_headers
, char *, s
, tor_free(s
));
811 smartlist_free(parsed_headers
);
816 /** Return true iff <b>body</b> doesn't start with a plausible router or
817 * running-list or directory opening. This is a sign of possible compression.
820 body_is_plausible(const char *body
, size_t len
, int purpose
)
824 return 1; /* empty bodies don't need decompression */
827 if (purpose
!= DIR_PURPOSE_FETCH_RENDDESC
) {
828 if (!strcmpstart(body
,"router") ||
829 !strcmpstart(body
,"signed-directory") ||
830 !strcmpstart(body
,"network-status") ||
831 !strcmpstart(body
,"running-routers"))
834 if (!TOR_ISPRINT(body
[i
]) && !TOR_ISSPACE(body
[i
]))
843 /** We are a client, and we've finished reading the server's
844 * response. Parse and it and act appropriately.
846 * If we're still happy with using this directory server in the future, return
847 * 0. Otherwise return -1; and the caller should consider trying the request
850 * The caller will take care of marking the connection for close.
853 connection_dir_client_reached_eof(connection_t
*conn
)
858 size_t body_len
=0, orig_len
=0;
860 time_t now
, date_header
=0;
865 int allow_partial
= conn
->purpose
== DIR_PURPOSE_FETCH_SERVERDESC
;
866 int was_compressed
=0;
868 switch (fetch_from_buf_http(conn
->inbuf
,
869 &headers
, MAX_HEADERS_SIZE
,
870 &body
, &body_len
, MAX_DIR_SIZE
,
872 case -1: /* overflow */
873 log_warn(LD_PROTOCOL
,
874 "'fetch' response too large (server '%s:%d'). Closing.",
875 conn
->address
, conn
->port
);
879 "'fetch' response not all here, but we're at eof. Closing.");
881 /* case 1, fall through */
885 if (parse_http_response(headers
, &status_code
, &date_header
,
886 &compression
, &reason
) < 0) {
887 log_warn(LD_HTTP
,"Unparseable headers (server '%s:%d'). Closing.",
888 conn
->address
, conn
->port
);
889 tor_free(body
); tor_free(headers
);
892 if (!reason
) reason
= tor_strdup("[no reason given]");
895 "Received response from directory server '%s:%d': %d %s",
896 conn
->address
, conn
->port
, status_code
, escaped(reason
));
898 if (date_header
> 0) {
900 delta
= now
-date_header
;
901 if (abs(delta
)>ALLOW_DIRECTORY_TIME_SKEW
) {
902 log_fn(router_digest_is_trusted_dir(conn
->identity_digest
) ?
905 "Received directory with skewed time (server '%s:%d'): "
906 "we are %d minutes %s, or the directory is %d minutes %s.",
907 conn
->address
, conn
->port
,
908 abs(delta
)/60, delta
>0 ? "ahead" : "behind",
909 abs(delta
)/60, delta
>0 ? "behind" : "ahead");
910 skewed
= 1; /* don't check the recommended-versions line */
912 log_debug(LD_HTTP
, "Time on received directory is within tolerance; "
913 "we are %d seconds skewed. (That's okay.)", delta
);
917 if (status_code
== 503) {
918 log_info(LD_DIR
,"Received http status code %d (%s) from server "
919 "'%s:%d'. I'll try again soon.",
920 status_code
, escaped(reason
), conn
->address
, conn
->port
);
921 tor_free(body
); tor_free(headers
); tor_free(reason
);
925 plausible
= body_is_plausible(body
, body_len
, conn
->purpose
);
926 if (compression
|| !plausible
) {
927 char *new_body
= NULL
;
929 int guessed
= detect_compression_method(body
, body_len
);
930 if (compression
<= 0 || guessed
!= compression
) {
931 /* Tell the user if we don't believe what we're told about compression.*/
932 const char *description1
, *description2
;
933 if (compression
== ZLIB_METHOD
)
934 description1
= "as deflated";
935 else if (compression
== GZIP_METHOD
)
936 description1
= "as gzipped";
937 else if (compression
== 0)
938 description1
= "as uncompressed";
940 description1
= "with an unknown Content-Encoding";
941 if (guessed
== ZLIB_METHOD
)
942 description2
= "deflated";
943 else if (guessed
== GZIP_METHOD
)
944 description2
= "gzipped";
946 description2
= "confusing binary junk";
948 description2
= "uncompressed";
950 log_info(LD_HTTP
, "HTTP body from server '%s:%d' was labeled %s, "
951 "but it seems to be %s.%s",
952 conn
->address
, conn
->port
, description1
, description2
,
953 (compression
>0 && guessed
>0)?" Trying both.":"");
955 /* Try declared compression first if we can. */
957 tor_gzip_uncompress(&new_body
, &new_len
, body
, body_len
, compression
,
958 allow_partial
, LOG_PROTOCOL_WARN
);
959 /* Okay, if that didn't work, and we think that it was compressed
960 * differently, try that. */
961 if (!new_body
&& guessed
> 0 && compression
!= guessed
)
962 tor_gzip_uncompress(&new_body
, &new_len
, body
, body_len
, guessed
,
963 allow_partial
, LOG_PROTOCOL_WARN
);
964 /* If we're pretty sure that we have a compressed directory, and
965 * we didn't manage to uncompress it, then warn and bail. */
966 if (!plausible
&& !new_body
) {
967 log_fn(LOG_PROTOCOL_WARN
, LD_HTTP
,
968 "Unable to decompress HTTP body (server '%s:%d').",
969 conn
->address
, conn
->port
);
970 tor_free(body
); tor_free(headers
); tor_free(reason
);
981 if (conn
->purpose
== DIR_PURPOSE_FETCH_DIR
) {
982 /* fetch/process the directory to cache it. */
983 log_info(LD_DIR
,"Received directory (size %d) from server '%s:%d'",
984 (int)body_len
, conn
->address
, conn
->port
);
985 if (status_code
!= 200) {
986 log_warn(LD_DIR
,"Received http status code %d (%s) from server "
987 "'%s:%d'. I'll try again soon.",
988 status_code
, escaped(reason
), conn
->address
, conn
->port
);
989 tor_free(body
); tor_free(headers
); tor_free(reason
);
992 if (router_parse_directory(body
) < 0) {
993 log_notice(LD_DIR
,"I failed to parse the directory I fetched from "
994 "'%s:%d'. Ignoring.", conn
->address
, conn
->port
);
996 note_request(was_compressed
?"dl/dir.z":"dl/dir", orig_len
);
999 if (conn
->purpose
== DIR_PURPOSE_FETCH_RUNNING_LIST
) {
1000 /* just update our list of running routers, if this list is new info */
1001 log_info(LD_DIR
,"Received running-routers list (size %d)", (int)body_len
);
1002 if (status_code
!= 200) {
1003 log_warn(LD_DIR
,"Received http status code %d (%s) from server "
1004 "'%s:%d'. I'll try again soon.",
1005 status_code
, escaped(reason
), conn
->address
, conn
->port
);
1006 tor_free(body
); tor_free(headers
); tor_free(reason
);
1009 if (router_parse_runningrouters(body
)<0) {
1011 "Bad running-routers from server '%s:%d'. I'll try again soon.",
1012 conn
->address
, conn
->port
);
1013 tor_free(body
); tor_free(headers
); tor_free(reason
);
1016 note_request(was_compressed
?"dl/running-routers.z":
1017 "dl/running-routers", orig_len
);
1020 if (conn
->purpose
== DIR_PURPOSE_FETCH_NETWORKSTATUS
) {
1021 smartlist_t
*which
= NULL
;
1023 log_info(LD_DIR
,"Received networkstatus objects (size %d) from server "
1024 "'%s:%d'",(int) body_len
, conn
->address
, conn
->port
);
1025 if (status_code
!= 200) {
1027 "Received http status code %d (%s) from server "
1028 "'%s:%d' while fetching \"/tor/status/%s\". I'll try again soon.",
1029 status_code
, escaped(reason
), conn
->address
, conn
->port
,
1030 conn
->requested_resource
);
1031 tor_free(body
); tor_free(headers
); tor_free(reason
);
1032 connection_dir_download_networkstatus_failed(conn
);
1035 note_request(was_compressed
?"dl/status.z":"dl/status", orig_len
);
1036 if (conn
->requested_resource
&&
1037 !strcmpstart(conn
->requested_resource
,"fp/")) {
1038 which
= smartlist_create();
1039 dir_split_resource_into_fingerprints(conn
->requested_resource
+3,
1044 char *next
= strstr(cp
, "\nnetwork-status-version");
1047 /* learn from it, and then remove it from 'which' */
1048 if (router_set_networkstatus(cp
, time(NULL
), NS_FROM_DIR
, which
)<0)
1057 routers_update_all_from_networkstatus(); /*launches router downloads*/
1058 directory_info_has_arrived(time(NULL
), 0);
1060 if (smartlist_len(which
)) {
1061 dir_networkstatus_download_failed(which
);
1063 SMARTLIST_FOREACH(which
, char *, cp
, tor_free(cp
));
1064 smartlist_free(which
);
1068 if (conn
->purpose
== DIR_PURPOSE_FETCH_SERVERDESC
) {
1069 smartlist_t
*which
= NULL
;
1070 int n_asked_for
= 0;
1071 log_info(LD_DIR
,"Received server info (size %d) from server '%s:%d'",
1072 (int)body_len
, conn
->address
, conn
->port
);
1073 note_request(was_compressed
?"dl/server.z":"dl/server", orig_len
);
1074 if (conn
->requested_resource
&&
1075 !strcmpstart(conn
->requested_resource
,"d/")) {
1076 which
= smartlist_create();
1077 dir_split_resource_into_fingerprints(conn
->requested_resource
+2,
1079 n_asked_for
= smartlist_len(which
);
1081 if (status_code
!= 200) {
1082 int dir_okay
= status_code
== 404 ||
1083 (status_code
== 400 && !strcmp(reason
, "Servers unavailable."));
1084 /* 404 means that it didn't have them; no big deal.
1085 * Older (pre-0.1.1.8) servers said 400 Servers unavailable instead. */
1086 log_fn(dir_okay
? LOG_INFO
: LOG_WARN
, LD_DIR
,
1087 "Received http status code %d (%s) from server '%s:%d' "
1088 "while fetching \"/tor/server/%s\". I'll try again soon.",
1089 status_code
, escaped(reason
), conn
->address
, conn
->port
,
1090 conn
->requested_resource
);
1092 connection_dir_download_routerdesc_failed(conn
);
1094 dir_routerdesc_download_failed(which
);
1095 SMARTLIST_FOREACH(which
, char *, cp
, tor_free(cp
));
1096 smartlist_free(which
);
1098 tor_free(body
); tor_free(headers
); tor_free(reason
);
1099 return dir_okay
? 0 : -1;
1101 /* Learn the routers, assuming we requested by fingerprint or "all".
1102 * Right now, we only use "authority" to fetch ourself, so we don't want
1103 * to risk replacing ourself with a router running at the addr:port we
1106 if (which
|| (conn
->requested_resource
&&
1107 !strcmpstart(conn
->requested_resource
, "all"))) {
1108 /* as we learn from them, we remove them from 'which' */
1109 router_load_routers_from_string(body
, 0, which
);
1110 directory_info_has_arrived(time(NULL
), 0);
1112 if (which
) { /* mark remaining ones as failed */
1113 log_info(LD_DIR
, "Received %d/%d routers requested from %s:%d",
1114 n_asked_for
-smartlist_len(which
), n_asked_for
,
1115 conn
->address
, (int)conn
->port
);
1116 if (smartlist_len(which
)) {
1117 dir_routerdesc_download_failed(which
);
1119 SMARTLIST_FOREACH(which
, char *, cp
, tor_free(cp
));
1120 smartlist_free(which
);
1122 if (conn
->requested_resource
&&
1123 !strcmpstart(conn
->requested_resource
,"authority")) {
1124 /* this might have been a dirport reachability test. see if it is. */
1125 routerinfo_t
*me
= router_get_my_routerinfo();
1127 router_digest_is_me(conn
->identity_digest
) &&
1128 me
->addr
== conn
->addr
&&
1129 me
->dir_port
== conn
->port
)
1130 router_dirport_found_reachable();
1134 if (conn
->purpose
== DIR_PURPOSE_UPLOAD_DIR
) {
1135 switch (status_code
) {
1137 log_info(LD_GENERAL
,"eof (status 200) after uploading server "
1138 "descriptor: finished.");
1141 log_warn(LD_GENERAL
,"http status 400 (%s) response from "
1142 "dirserver '%s:%d'. Please correct.",
1143 escaped(reason
), conn
->address
, conn
->port
);
1146 log_warn(LD_GENERAL
,
1147 "http status 403 (%s) response from dirserver "
1148 "'%s:%d'. Is your clock skewed? Have you mailed us your key "
1149 "fingerprint? Are you using the right key? Are you using a "
1150 "private IP address? See http://tor.eff.org/doc/"
1151 "tor-doc-server.html",escaped(reason
), conn
->address
, conn
->port
);
1154 log_warn(LD_GENERAL
,
1155 "http status %d (%s) reason unexpected (server '%s:%d').",
1156 status_code
, escaped(reason
), conn
->address
, conn
->port
);
1159 /* return 0 in all cases, since we don't want to mark any
1160 * dirservers down just because they don't like us. */
1163 if (conn
->purpose
== DIR_PURPOSE_FETCH_RENDDESC
) {
1164 log_info(LD_REND
,"Received rendezvous descriptor (size %d, status %d "
1166 (int)body_len
, status_code
, escaped(reason
));
1167 switch (status_code
) {
1169 if (rend_cache_store(body
, body_len
) < 0) {
1170 log_warn(LD_REND
,"Failed to store rendezvous descriptor.");
1171 /* alice's ap_stream will notice when connection_mark_for_close
1174 /* success. notify pending connections about this. */
1175 conn
->purpose
= DIR_PURPOSE_HAS_FETCHED_RENDDESC
;
1176 rend_client_desc_here(conn
->rend_query
);
1180 /* not there. pending connections will be notified when
1181 * connection_mark_for_close cleans it up. */
1185 "http status 400 (%s). Dirserver didn't like our "
1186 "rendezvous query?", escaped(reason
));
1189 log_warn(LD_REND
,"http status %d (%s) response unexpected (server "
1191 status_code
, escaped(reason
), conn
->address
, conn
->port
);
1196 if (conn
->purpose
== DIR_PURPOSE_UPLOAD_RENDDESC
) {
1197 switch (status_code
) {
1200 "Uploading rendezvous descriptor: finished with status "
1201 "200 (%s)", escaped(reason
));
1204 log_warn(LD_REND
,"http status 400 (%s) response from dirserver "
1205 "'%s:%d'. Malformed rendezvous descriptor?",
1206 escaped(reason
), conn
->address
, conn
->port
);
1209 log_warn(LD_REND
,"http status %d (%s) response unexpected (server "
1211 status_code
, escaped(reason
), conn
->address
, conn
->port
);
1215 tor_free(body
); tor_free(headers
); tor_free(reason
);
1219 /** Called when a directory connection reaches EOF */
1221 connection_dir_reached_eof(connection_t
*conn
)
1224 if (conn
->state
!= DIR_CONN_STATE_CLIENT_READING
) {
1225 log_info(LD_HTTP
,"conn reached eof, not reading. Closing.");
1226 connection_close_immediate(conn
); /* error: give up on flushing */
1227 connection_mark_for_close(conn
);
1231 retval
= connection_dir_client_reached_eof(conn
);
1232 if (retval
== 0) /* success */
1233 conn
->state
= DIR_CONN_STATE_CLIENT_FINISHED
;
1234 connection_mark_for_close(conn
);
1238 /** Read handler for directory connections. (That's connections <em>to</em>
1239 * directory servers and connections <em>at</em> directory servers.)
1242 connection_dir_process_inbuf(connection_t
*conn
)
1245 tor_assert(conn
->type
== CONN_TYPE_DIR
);
1247 /* Directory clients write, then read data until they receive EOF;
1248 * directory servers read data until they get an HTTP command, then
1249 * write their response (when it's finished flushing, they mark for
1253 /* If we're on the dirserver side, look for a command. */
1254 if (conn
->state
== DIR_CONN_STATE_SERVER_COMMAND_WAIT
) {
1255 if (directory_handle_command(conn
) < 0) {
1256 connection_mark_for_close(conn
);
1262 /* XXX for READ states, might want to make sure inbuf isn't too big */
1264 if (!conn
->inbuf_reached_eof
)
1265 log_debug(LD_HTTP
,"Got data, not eof. Leaving on inbuf.");
1269 /** Create an http response for the client <b>conn</b> out of
1270 * <b>status</b> and <b>reason_phrase</b>. Write it to <b>conn</b>.
1273 write_http_status_line(connection_t
*conn
, int status
,
1274 const char *reason_phrase
)
1277 if (tor_snprintf(buf
, sizeof(buf
), "HTTP/1.0 %d %s\r\n\r\n",
1278 status
, reason_phrase
) < 0) {
1279 log_warn(LD_BUG
,"Bug: status line too long.");
1282 connection_write_to_buf(buf
, strlen(buf
), conn
);
1285 /** Helper function: return 1 if there are any dir conns of purpose
1286 * <b>purpose</b> that are going elsewhere than our own ORPort/Dirport.
1290 already_fetching_directory(int purpose
)
1294 connection_t
**carray
;
1296 get_connection_array(&carray
,&n
);
1299 if (conn
->type
== CONN_TYPE_DIR
&&
1300 conn
->purpose
== purpose
&&
1301 !conn
->marked_for_close
&&
1302 !router_digest_is_me(conn
->identity_digest
))
1308 #undef INSTRUMENT_DOWNLOADS
1310 #ifdef INSTRUMENT_DOWNLOADS
1312 static strmap_t
*request_bytes_map
= NULL
;
1316 note_request(const char *key
, size_t bytes
)
1319 if (!request_bytes_map
)
1320 request_bytes_map
= strmap_new();
1322 n
= strmap_get(request_bytes_map
, key
);
1324 n
= tor_malloc_zero(sizeof(uint64_t));
1325 strmap_set(request_bytes_map
, key
, n
);
1332 directory_dump_request_log(void)
1337 strmap_iter_t
*iter
;
1339 if (!request_bytes_map
)
1340 request_bytes_map
= strmap_new();
1342 lines
= smartlist_create();
1344 for (iter
= strmap_iter_init(request_bytes_map
);
1345 !strmap_iter_done(iter
);
1346 iter
= strmap_iter_next(request_bytes_map
, iter
)) {
1350 strmap_iter_get(iter
, &key
, &val
);
1352 tor_snprintf(tmp
, sizeof(tmp
), "%s "U64_FORMAT
"\n",
1353 key
, U64_PRINTF_ARG(*n
));
1354 smartlist_add(lines
, tor_strdup(tmp
));
1356 smartlist_sort_strings(lines
);
1357 result
= smartlist_join_strings(lines
, "", 0, NULL
);
1358 SMARTLIST_FOREACH(lines
, char *, cp
, tor_free(cp
));
1359 smartlist_free(lines
);
1364 note_request(const char *key
, size_t bytes
)
1370 directory_dump_request_log(void)
1372 return tor_strdup("Not supported.");
1376 /** Helper function: called when a dirserver gets a complete HTTP GET
1377 * request. Look for a request for a directory or for a rendezvous
1378 * service descriptor. On finding one, write a response into
1379 * conn-\>outbuf. If the request is unrecognized, send a 400.
1380 * Always return 0. */
1382 directory_handle_command_get(connection_t
*conn
, char *headers
,
1383 char *body
, size_t body_len
)
1389 char date
[RFC1123_TIME_LEN
+1];
1391 log_debug(LD_DIRSERV
,"Received GET command.");
1393 conn
->state
= DIR_CONN_STATE_SERVER_WRITING
;
1395 if (parse_http_url(headers
, &url
) < 0) {
1396 write_http_status_line(conn
, 400, "Bad request");
1399 log_debug(LD_DIRSERV
,"rewritten url as '%s'.", url
);
1401 if (!strcmp(url
,"/tor/") || !strcmp(url
,"/tor/dir.z")) { /* dir fetch */
1402 int deflated
= !strcmp(url
,"/tor/dir.z");
1403 dlen
= dirserv_get_directory(&cp
, deflated
);
1406 log_notice(LD_DIRSERV
,"Client asked for the mirrored directory, but we "
1407 "don't have a good one yet. Sending 503 Dir not available.");
1408 write_http_status_line(conn
, 503, "Directory unavailable");
1409 /* try to get a new one now */
1410 if (!already_fetching_directory(DIR_PURPOSE_FETCH_DIR
))
1411 directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR
, NULL
, 1);
1416 if (global_write_bucket_empty()) {
1417 log_info(LD_DIRSERV
,
1418 "Client asked for the mirrored directory, but we've been "
1419 "writing too many bytes lately. Sending 503 Dir busy.");
1420 write_http_status_line(conn
, 503, "Directory busy, try again later");
1425 note_request(url
, dlen
);
1428 log_debug(LD_DIRSERV
,"Dumping %sdirectory to client.",
1429 deflated
?"deflated ":"");
1430 format_rfc1123_time(date
, time(NULL
));
1431 tor_snprintf(tmp
, sizeof(tmp
),
1432 "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n"
1433 "Content-Type: %s\r\nContent-Encoding: %s\r\n\r\n",
1436 deflated
?"application/octet-stream":"text/plain",
1437 deflated
?"deflate":"identity");
1438 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
1439 connection_write_to_buf(cp
, dlen
, conn
);
1443 if (!strcmp(url
,"/tor/running-routers") ||
1444 !strcmp(url
,"/tor/running-routers.z")) { /* running-routers fetch */
1445 int deflated
= !strcmp(url
,"/tor/running-routers.z");
1446 dlen
= dirserv_get_runningrouters(&cp
, deflated
);
1447 note_request(url
, dlen
);
1449 if (!dlen
) { /* we failed to create/cache cp */
1450 write_http_status_line(conn
, 503, "Directory unavailable");
1451 /* try to get a new one now */
1452 if (!already_fetching_directory(DIR_PURPOSE_FETCH_RUNNING_LIST
))
1453 directory_get_from_dirserver(DIR_PURPOSE_FETCH_RUNNING_LIST
, NULL
, 1);
1457 format_rfc1123_time(date
, time(NULL
));
1458 tor_snprintf(tmp
, sizeof(tmp
),
1459 "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n"
1460 "Content-Type: %s\r\nContent-Encoding: %s\r\n\r\n",
1463 deflated
?"application/octet-stream":"text/plain",
1464 deflated
?"deflate":"identity");
1465 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
1466 connection_write_to_buf(cp
, strlen(cp
), conn
);
1470 if (!strcmpstart(url
,"/tor/status/")) {
1471 /* v2 network status fetch. */
1472 size_t url_len
= strlen(url
);
1473 int deflated
= !strcmp(url
+url_len
-2, ".z");
1474 smartlist_t
*dir_objs
= smartlist_create();
1475 const char *request_type
= NULL
;
1476 const char *key
= url
+ strlen("/tor/status/");
1478 url
[url_len
-2] = '\0';
1479 if (dirserv_get_networkstatus_v2(dir_objs
, key
)) {
1480 smartlist_free(dir_objs
);
1483 if (!strcmpstart(key
, "fp/"))
1484 request_type
= deflated
?"/tor/status/fp.z":"/tor/status/fp";
1485 else if (!strcmpstart(key
, "authority"))
1486 request_type
= deflated
?"/tor/status/authority.z":
1487 "/tor/status/authority";
1488 else if (!strcmpstart(key
, "all"))
1489 request_type
= deflated
?"/tor/status/all.z":"/tor/status/all";
1491 request_type
= "/tor/status/?";
1493 if (!smartlist_len(dir_objs
)) { /* we failed to create/cache cp */
1494 write_http_status_line(conn
, 503, "Network status object unavailable");
1495 smartlist_free(dir_objs
);
1499 SMARTLIST_FOREACH(dir_objs
, cached_dir_t
*, d
,
1500 dlen
+= deflated
?d
->dir_z_len
:d
->dir_len
);
1501 note_request(request_type
,dlen
);
1502 format_rfc1123_time(date
, time(NULL
));
1503 tor_snprintf(tmp
, sizeof(tmp
),
1504 "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n"
1505 "Content-Type: %s\r\nContent-Encoding: %s\r\n\r\n",
1508 deflated
?"application/octet-stream":"text/plain",
1509 deflated
?"deflate":"identity");
1510 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
1511 SMARTLIST_FOREACH(dir_objs
, cached_dir_t
*, d
,
1514 connection_write_to_buf(d
->dir_z
, d
->dir_z_len
, conn
);
1516 connection_write_to_buf(d
->dir
, d
->dir_len
, conn
);
1518 smartlist_free(dir_objs
);
1522 if (!strcmpstart(url
,"/tor/server/")) {
1523 size_t url_len
= strlen(url
);
1524 int deflated
= !strcmp(url
+url_len
-2, ".z");
1527 smartlist_t
*descs
= smartlist_create();
1528 const char *request_type
= NULL
;
1530 url
[url_len
-2] = '\0';
1531 res
= dirserv_get_routerdescs(descs
, url
, &msg
);
1533 if (!strcmpstart(url
, "/tor/server/fp/"))
1534 request_type
= deflated
?"/tor/server/fp.z":"/tor/server/fp";
1535 else if (!strcmpstart(url
, "/tor/server/authority"))
1536 request_type
= deflated
?"/tor/server/authority.z":
1537 "/tor/server/authority";
1538 else if (!strcmpstart(url
, "/tor/server/all"))
1539 request_type
= deflated
?"/tor/server/all.z":"/tor/server/all";
1540 else if (!strcmpstart(url
, "/tor/server/d/"))
1541 request_type
= deflated
?"/tor/server/d.z":"/tor/server/d";
1543 request_type
= "/tor/server/?";
1546 write_http_status_line(conn
, 404, msg
);
1549 format_rfc1123_time(date
, time(NULL
));
1550 SMARTLIST_FOREACH(descs
, signed_descriptor_t
*, ri
,
1551 len
+= ri
->signed_descriptor_len
);
1553 size_t compressed_len
;
1555 char *inp
= tor_malloc(len
+smartlist_len(descs
)+1);
1557 SMARTLIST_FOREACH(descs
, signed_descriptor_t
*, ri
,
1559 const char *body
= signed_descriptor_get_body(ri
);
1560 memcpy(cp
, body
, ri
->signed_descriptor_len
);
1561 cp
+= ri
->signed_descriptor_len
;
1565 /* XXXX This could be way more efficiently handled; let's see if it
1566 * shows up under oprofile. */
1567 if (tor_gzip_compress(&compressed
, &compressed_len
,
1568 inp
, cp
-inp
, ZLIB_METHOD
)<0) {
1570 smartlist_free(descs
);
1574 tor_snprintf(tmp
, sizeof(tmp
),
1575 "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n"
1576 "Content-Type: application/octet-stream\r\n"
1577 "Content-Encoding: deflate\r\n\r\n",
1579 (int)compressed_len
);
1580 note_request(request_type
, compressed_len
);
1581 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
1582 connection_write_to_buf(compressed
, compressed_len
, conn
);
1583 tor_free(compressed
);
1585 tor_snprintf(tmp
, sizeof(tmp
),
1586 "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n"
1587 "Content-Type: text/plain\r\n\r\n",
1590 note_request(request_type
, len
);
1591 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
1592 SMARTLIST_FOREACH(descs
, signed_descriptor_t
*, ri
,
1594 const char *body
= signed_descriptor_get_body(ri
);
1595 connection_write_to_buf(body
, ri
->signed_descriptor_len
, conn
);
1599 smartlist_free(descs
);
1603 if (!strcmpstart(url
,"/tor/rendezvous/") ||
1604 !strcmpstart(url
,"/tor/rendezvous1/")) {
1605 /* rendezvous descriptor fetch */
1608 int versioned
= !strcmpstart(url
,"/tor/rendezvous1/");
1609 const char *query
= url
+strlen("/tor/rendezvous/")+(versioned
?1:0);
1611 if (!authdir_mode(get_options())) {
1612 /* We don't hand out rend descs. In fact, it could be a security
1613 * risk, since rend_cache_lookup_desc() below would provide it
1614 * if we're gone to the site recently, and 404 if we haven't.
1617 write_http_status_line(conn
, 400, "Nonauthoritative directory does not "
1618 "store rendezvous descriptors");
1622 switch (rend_cache_lookup_desc(query
, versioned
?-1:0, &descp
, &desc_len
)) {
1624 format_rfc1123_time(date
, time(NULL
));
1625 tor_snprintf(tmp
, sizeof(tmp
),
1626 "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n"
1627 "Content-Type: application/octet-stream\r\n\r\n",
1630 note_request("/tor/rendezvous?/", desc_len
);
1631 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
1632 /* need to send descp separately, because it may include nuls */
1633 connection_write_to_buf(descp
, desc_len
, conn
);
1635 case 0: /* well-formed but not present */
1636 write_http_status_line(conn
, 404, "Not found");
1638 case -1: /* not well-formed */
1639 write_http_status_line(conn
, 400, "Bad request");
1646 if (!strcmpstart(url
,"/tor/bytes.txt")) {
1647 char *bytes
= directory_dump_request_log();
1648 size_t len
= strlen(bytes
);
1649 format_rfc1123_time(date
, time(NULL
));
1650 tor_snprintf(tmp
, sizeof(tmp
),
1651 "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n"
1652 "Content-Type: text/plain\r\n\r\n",
1655 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
1656 connection_write_to_buf(bytes
, len
, conn
);
1662 /* we didn't recognize the url */
1663 write_http_status_line(conn
, 404, "Not found");
1668 /** Helper function: called when a dirserver gets a complete HTTP POST
1669 * request. Look for an uploaded server descriptor or rendezvous
1670 * service descriptor. On finding one, process it and write a
1671 * response into conn-\>outbuf. If the request is unrecognized, send a
1672 * 400. Always return 0. */
1674 directory_handle_command_post(connection_t
*conn
, char *headers
,
1675 char *body
, size_t body_len
)
1678 char *origin
= NULL
;
1681 log_debug(LD_DIRSERV
,"Received POST command.");
1683 conn
->state
= DIR_CONN_STATE_SERVER_WRITING
;
1685 if (!authdir_mode(get_options())) {
1686 /* we just provide cached directories; we don't want to
1687 * receive anything. */
1688 write_http_status_line(conn
, 400, "Nonauthoritative directory does not "
1689 "accept posted server descriptors");
1693 if (parse_http_url(headers
, &url
) < 0) {
1694 write_http_status_line(conn
, 400, "Bad request");
1697 log_debug(LD_DIRSERV
,"rewritten url as '%s'.", url
);
1698 origin
= http_get_origin(headers
, conn
);
1700 if (!strcmp(url
,"/tor/")) { /* server descriptor post */
1702 int r
= dirserv_add_descriptor(body
, &msg
);
1705 dirserv_get_directory(&cp
, 0); /* rebuild and write to disk */
1710 log_notice(LD_DIRSERV
,"Rejected router descriptor from %s.", origin
);
1711 /* malformed descriptor, or something wrong */
1712 write_http_status_line(conn
, 400, msg
);
1714 case 0: /* accepted but discarded */
1715 case 2: /* accepted */
1716 write_http_status_line(conn
, 200, msg
);
1722 if (!strcmpstart(url
,"/tor/rendezvous/publish")) {
1723 /* rendezvous descriptor post */
1724 if (rend_cache_store(body
, body_len
) < 0) {
1725 // char tmp[1024*2+1];
1726 log_fn(LOG_PROTOCOL_WARN
, LD_DIRSERV
,
1727 "Rejected rend descriptor (length %d) from %s.",
1728 (int)body_len
, origin
);
1730 if (body_len
<= 1024) {
1731 base16_encode(tmp
, sizeof(tmp
), body
, body_len
);
1732 log_notice(LD_DIRSERV
,"Body was: %s", escaped(tmp
));
1735 write_http_status_line(conn
, 400, "Invalid service descriptor rejected");
1737 write_http_status_line(conn
, 200, "Service descriptor stored");
1742 /* we didn't recognize the url */
1743 write_http_status_line(conn
, 404, "Not found");
1751 /** Called when a dirserver receives data on a directory connection;
1752 * looks for an HTTP request. If the request is complete, remove it
1753 * from the inbuf, try to process it; otherwise, leave it on the
1754 * buffer. Return a 0 on success, or -1 on error.
1757 directory_handle_command(connection_t
*conn
)
1759 char *headers
=NULL
, *body
=NULL
;
1764 tor_assert(conn
->type
== CONN_TYPE_DIR
);
1766 switch (fetch_from_buf_http(conn
->inbuf
,
1767 &headers
, MAX_HEADERS_SIZE
,
1768 &body
, &body_len
, MAX_BODY_SIZE
, 0)) {
1769 case -1: /* overflow */
1770 log_warn(LD_DIRSERV
,
1771 "Invalid input from address '%s'. Closing.", conn
->address
);
1774 log_debug(LD_DIRSERV
,"command not all here yet.");
1776 /* case 1, fall through */
1779 //log_debug(LD_DIRSERV,"headers %s, body %s.", headers, body);
1781 if (!strncasecmp(headers
,"GET",3))
1782 r
= directory_handle_command_get(conn
, headers
, body
, body_len
);
1783 else if (!strncasecmp(headers
,"POST",4))
1784 r
= directory_handle_command_post(conn
, headers
, body
, body_len
);
1786 log_warn(LD_PROTOCOL
,"Got headers %s with unknown command. Closing.",
1791 tor_free(headers
); tor_free(body
);
1795 /** Write handler for directory connections; called when all data has
1796 * been flushed. Close the connection or wait for a response as
1800 connection_dir_finished_flushing(connection_t
*conn
)
1803 tor_assert(conn
->type
== CONN_TYPE_DIR
);
1805 switch (conn
->state
) {
1806 case DIR_CONN_STATE_CLIENT_SENDING
:
1807 log_debug(LD_DIR
,"client finished sending command.");
1808 conn
->state
= DIR_CONN_STATE_CLIENT_READING
;
1809 connection_stop_writing(conn
);
1811 case DIR_CONN_STATE_SERVER_WRITING
:
1812 log_debug(LD_DIRSERV
,"Finished writing server response. Closing.");
1813 connection_mark_for_close(conn
);
1816 log_warn(LD_BUG
,"Bug: called in unexpected state %d.", conn
->state
);
1817 tor_fragile_assert();
1823 /** Connected handler for directory connections: begin sending data to the
1826 connection_dir_finished_connecting(connection_t
*conn
)
1829 tor_assert(conn
->type
== CONN_TYPE_DIR
);
1830 tor_assert(conn
->state
== DIR_CONN_STATE_CONNECTING
);
1832 log_debug(LD_HTTP
,"Dir connection to router %s:%u established.",
1833 conn
->address
,conn
->port
);
1835 conn
->state
= DIR_CONN_STATE_CLIENT_SENDING
; /* start flushing conn */
1839 /** Called when one or more networkstatus fetches have failed (with uppercase
1840 * fingerprints listed in <b>failed</>). Mark those fingerprints as having
1843 dir_networkstatus_download_failed(smartlist_t
*failed
)
1845 SMARTLIST_FOREACH(failed
, const char *, fp
,
1847 char digest
[DIGEST_LEN
];
1848 trusted_dir_server_t
*dir
;
1849 base16_decode(digest
, DIGEST_LEN
, fp
, strlen(fp
));
1850 dir
= router_get_trusteddirserver_by_digest(digest
);
1853 ++dir
->n_networkstatus_failures
;
1857 /** Called when one or more networkstatus fetches have failed (with uppercase
1858 * fingerprints listed in <b>failed</>). */
1860 dir_routerdesc_download_failed(smartlist_t
*failed
)
1862 char digest
[DIGEST_LEN
];
1863 local_routerstatus_t
*rs
;
1864 time_t now
= time(NULL
);
1865 int server
= server_mode(get_options()) && get_options()->DirPort
;
1866 SMARTLIST_FOREACH(failed
, const char *, cp
,
1868 base16_decode(digest
, DIGEST_LEN
, cp
, strlen(cp
));
1869 rs
= router_get_combined_status_by_digest(digest
);
1870 if (!rs
|| rs
->n_download_failures
>= MAX_ROUTERDESC_DOWNLOAD_FAILURES
)
1872 ++rs
->n_download_failures
;
1874 switch (rs
->n_download_failures
) {
1875 case 1: rs
->next_attempt_at
= 0; break;
1876 case 2: rs
->next_attempt_at
= 0; break;
1877 case 3: rs
->next_attempt_at
= now
+60; break;
1878 case 4: rs
->next_attempt_at
= now
+60; break;
1879 case 5: rs
->next_attempt_at
= now
+60*2; break;
1880 case 6: rs
->next_attempt_at
= now
+60*5; break;
1881 case 7: rs
->next_attempt_at
= now
+60*15; break;
1882 default: rs
->next_attempt_at
= TIME_MAX
; break;
1885 switch (rs
->n_download_failures
) {
1886 case 1: rs
->next_attempt_at
= 0; break;
1887 case 2: rs
->next_attempt_at
= now
+60; break;
1888 case 3: rs
->next_attempt_at
= now
+60*5; break;
1889 case 4: rs
->next_attempt_at
= now
+60*10; break;
1890 default: rs
->next_attempt_at
= TIME_MAX
; break;
1893 if (rs
->next_attempt_at
== 0)
1894 log_debug(LD_DIR
, "%s failed %d time(s); I'll try again immediately.",
1895 cp
, (int)rs
->n_download_failures
);
1896 else if (rs
->next_attempt_at
< TIME_MAX
)
1897 log_debug(LD_DIR
, "%s failed %d time(s); I'll try again in %d seconds.",
1898 cp
, (int)rs
->n_download_failures
,
1899 (int)(rs
->next_attempt_at
-now
));
1901 log_debug(LD_DIR
, "%s failed %d time(s); Giving up for a while.",
1902 cp
, (int)rs
->n_download_failures
);
1905 /* update_router_descriptor_downloads(time(NULL)); */
1908 /* Given a directory <b>resource</b> request, containing zero
1909 * or more strings separated by plus signs, followed optionally by ".z", store
1910 * the strings, in order, into <b>fp_out</b>. If <b>compressed_out</b> is
1911 * non-NULL, set it to 1 if the resource ends in ".z", else set it to 0. If
1912 * decode_hex is true, then delete all elements that aren't hex digests, and
1916 dir_split_resource_into_fingerprints(const char *resource
,
1917 smartlist_t
*fp_out
, int *compressed_out
,
1922 old_len
= smartlist_len(fp_out
);
1923 smartlist_split_string(fp_out
, resource
, "+", 0, 0);
1925 *compressed_out
= 0;
1926 if (smartlist_len(fp_out
) > old_len
) {
1927 char *last
= smartlist_get(fp_out
,smartlist_len(fp_out
)-1);
1928 size_t last_len
= strlen(last
);
1929 if (last_len
> 2 && !strcmp(last
+last_len
-2, ".z")) {
1930 last
[last_len
-2] = '\0';
1932 *compressed_out
= 1;
1937 char *cp
, *d
= NULL
;
1938 for (i
= old_len
; i
< smartlist_len(fp_out
); ++i
) {
1939 cp
= smartlist_get(fp_out
, i
);
1940 if (strlen(cp
) != HEX_DIGEST_LEN
) {
1942 "Skipping digest %s with non-standard length.", escaped(cp
));
1943 smartlist_del(fp_out
, i
--);
1946 d
= tor_malloc_zero(DIGEST_LEN
);
1947 if (base16_decode(d
, DIGEST_LEN
, cp
, HEX_DIGEST_LEN
)<0) {
1948 log_info(LD_DIR
, "Skipping non-decodable digest %s", escaped(cp
));
1949 smartlist_del(fp_out
, i
--);
1952 smartlist_set(fp_out
, i
, d
);