1 /* Copyright 2001-2004 Roger Dingledine.
2 * Copyright 2004 Roger Dingledine, Nick Mathewson. */
3 /* See LICENSE for licensing information */
5 const char directory_c_id
[] = "$Id$";
11 * \brief Implement directory HTTP protocol.
14 /* In-points to directory.c:
16 * - directory_post_to_dirservers(), called from
17 * router_upload_dir_desc_to_dirservers() in router.c
18 * upload_service_descriptor() in rendservice.c
19 * - directory_get_from_dirserver(), called from
20 * rend_client_refetch_renddesc() in rendclient.c
21 * run_scheduled_events() in main.c
23 * - connection_dir_process_inbuf(), called from
24 * connection_process_inbuf() in connection.c
25 * - connection_dir_finished_flushing(), called from
26 * connection_finished_flushing() in connection.c
27 * - connection_dir_finished_connecting(), called from
28 * connection_finished_connecting() in connection.c
32 directory_initiate_command_router(routerinfo_t
*router
, uint8_t purpose
,
34 const char *payload
, size_t payload_len
);
36 directory_initiate_command_trusted_dir(trusted_dir_server_t
*dirserv
,
37 uint8_t purpose
, const char *resource
,
38 const char *payload
, size_t payload_len
);
40 directory_initiate_command(const char *address
, uint32_t addr
, uint16_t port
,
42 const char *digest
, uint8_t purpose
,
44 const char *payload
, size_t payload_len
);
47 directory_send_command(connection_t
*conn
, const char *platform
,
48 int purpose
, const char *resource
,
49 const char *payload
, size_t payload_len
);
50 static int directory_handle_command(connection_t
*conn
);
51 static int body_is_plausible(const char *body
, size_t body_len
, int purpose
);
53 /********* START VARIABLES **********/
55 static addr_policy_t
*dir_policy
= NULL
;
57 #if 0 /* commented out for now, since for now what clients send is
58 different from what servers want to receive */
59 /** URL for publishing rendezvous descriptors. */
60 char rend_publish_string
[] = "/tor/rendezvous/publish";
61 /** Prefix for downloading rendezvous descriptors. */
62 char rend_fetch_url
[] = "/tor/rendezvous/";
65 #define MAX_HEADERS_SIZE 50000
66 #define MAX_BODY_SIZE 500000
68 #define ALLOW_DIRECTORY_TIME_SKEW 30*60
70 /********* END VARIABLES ************/
72 /** Parse get_options()->DirPolicy, and put the processed version in
73 * &dir_policy. Ignore port specifiers.
76 parse_dir_policy(void)
80 addr_policy_free(dir_policy
);
83 config_parse_addr_policy(get_options()->DirPolicy
, &dir_policy
);
84 /* ports aren't used. */
85 for (n
=dir_policy
; n
; n
= n
->next
) {
91 /** Return 1 if <b>addr</b> is permitted to connect to our dir port,
92 * based on <b>dir_policy</b>. Else return 0.
94 int 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
);
106 log_fn(LOG_WARN
, "Bug: got unexpected 'maybe' answer from dir policy");
110 /** Start a connection to every known directory server, using
111 * connection purpose 'purpose' and uploading the payload 'payload'
112 * (length 'payload_len'). The purpose should be one of
113 * 'DIR_PURPOSE_UPLOAD_DIR' or 'DIR_PURPOSE_UPLOAD_RENDDESC'.
116 directory_post_to_dirservers(uint8_t purpose
, const char *payload
,
119 smartlist_t
*dirservers
;
121 router_get_trusted_dir_servers(&dirservers
);
122 tor_assert(dirservers
);
123 /* This tries dirservers which we believe to be down, but ultimately, that's
124 * harmless, and we may as well err on the side of getting things uploaded.
126 SMARTLIST_FOREACH(dirservers
, trusted_dir_server_t
*, ds
,
128 /* Pay attention to fascistfirewall when we're uploading a
129 * router descriptor, but not when uploading a service
130 * descriptor -- those use Tor. */
131 if (get_options()->FascistFirewall
&& purpose
== DIR_PURPOSE_UPLOAD_DIR
&&
132 !get_options()->HttpProxy
) {
133 if (!smartlist_string_num_isin(get_options()->FirewallPorts
, ds
->dir_port
))
136 directory_initiate_command_trusted_dir(ds
, purpose
, NULL
,
137 payload
, payload_len
);
141 /** Start a connection to a random running directory server, using
142 * connection purpose 'purpose' requesting 'resource'. The purpose
143 * should be one of 'DIR_PURPOSE_FETCH_DIR',
144 * 'DIR_PURPOSE_FETCH_RENDDESC', 'DIR_PURPOSE_FETCH_RUNNING_LIST.'
145 * If <b>retry_if_no_servers</b>, then if all the possible servers seem
146 * down, mark them up and try again.
149 directory_get_from_dirserver(uint8_t purpose
, const char *resource
,
150 int retry_if_no_servers
)
152 routerinfo_t
*r
= NULL
;
153 trusted_dir_server_t
*ds
= NULL
;
154 int fascistfirewall
= get_options()->FascistFirewall
;
155 int directconn
= purpose
== DIR_PURPOSE_FETCH_DIR
||
156 purpose
== DIR_PURPOSE_FETCH_RUNNING_LIST
;
157 int fetch_fresh_first
= advertised_server_mode();
160 if (fetch_fresh_first
) {
161 /* only ask authdirservers, and don't ask myself */
162 ds
= router_pick_trusteddirserver(1, fascistfirewall
,
163 retry_if_no_servers
);
166 /* anybody with a non-zero dirport will do */
167 r
= router_pick_directory_server(1, fascistfirewall
,
168 purpose
==DIR_PURPOSE_FETCH_RUNNING_LIST
,
169 retry_if_no_servers
);
171 log_fn(LOG_INFO
, "No router found for %s; falling back to dirserver list",
172 purpose
== DIR_PURPOSE_FETCH_RUNNING_LIST
173 ? "status list" : "directory");
174 ds
= router_pick_trusteddirserver(1, fascistfirewall
,
175 retry_if_no_servers
);
178 } else { // (purpose == DIR_PURPOSE_FETCH_RENDDESC)
179 /* only ask authdirservers, any of them will do */
180 /* Never use fascistfirewall; we're going via Tor. */
181 ds
= router_pick_trusteddirserver(0, 0, retry_if_no_servers
);
185 directory_initiate_command_router(r
, purpose
, resource
, NULL
, 0);
187 directory_initiate_command_trusted_dir(ds
, purpose
, resource
, NULL
, 0);
189 log_fn(LOG_NOTICE
,"No running dirservers known. Not trying. (purpose %d)",
192 /* remember we tried them all and failed. */
193 directory_all_unreachable(time(NULL
));
198 /** Launch a new connection to the directory server <b>router</b> to upload or
199 * download a service or rendezvous descriptor. <b>purpose</b> determines what
200 * kind of directory connection we're launching, and must be one of
201 * DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC}.
203 * When uploading, <b>payload</b> and <b>payload_len</b> determine the content
204 * of the HTTP post. Otherwise, <b>payload</b> should be NULL.
206 * When fetching a rendezvous descriptor, <b>resource</b> is the service ID we
210 directory_initiate_command_router(routerinfo_t
*router
, uint8_t purpose
,
211 const char *resource
,
212 const char *payload
, size_t payload_len
)
214 directory_initiate_command(router
->address
, router
->addr
, router
->dir_port
,
215 router
->platform
, router
->identity_digest
,
216 purpose
, resource
, payload
, payload_len
);
219 /** As directory_initiate_command_router, but send the command to a trusted
220 * directory server <b>dirserv</b>. **/
222 directory_initiate_command_trusted_dir(trusted_dir_server_t
*dirserv
,
223 uint8_t purpose
, const char *resource
,
224 const char *payload
, size_t payload_len
)
226 directory_initiate_command(dirserv
->address
, dirserv
->addr
,dirserv
->dir_port
,
227 NULL
, dirserv
->digest
, purpose
, resource
, payload
, payload_len
);
230 /** Called when we are unable to complete our connection to a
231 * directory server: Mark the router as down and try again if possible.
234 connection_dir_connect_failed(connection_t
*conn
)
236 router_mark_as_down(conn
->identity_digest
); /* don't try him again */
237 if (conn
->purpose
== DIR_PURPOSE_FETCH_DIR
||
238 conn
->purpose
== DIR_PURPOSE_FETCH_RUNNING_LIST
) {
239 log_fn(LOG_INFO
, "Giving up on directory server at '%s'; retrying",
241 directory_get_from_dirserver(conn
->purpose
, NULL
,
242 0 /* don't retry_if_no_servers */);
246 /** Helper for directory_initiate_command_(router|trusted_dir): send the
247 * command to a server whose address is <b>address</b>, whose IP is
248 * <b>addr</b>, whose directory port is <b>dir_port</b>, whose tor version is
249 * <b>platform</b>, and whose identity key digest is <b>digest</b>. The
250 * <b>platform</b> argument is optional; the others are required. */
252 directory_initiate_command(const char *address
, uint32_t addr
,
253 uint16_t dir_port
, const char *platform
,
254 const char *digest
, uint8_t purpose
,
255 const char *resource
,
256 const char *payload
, size_t payload_len
)
262 tor_assert(dir_port
);
266 case DIR_PURPOSE_FETCH_DIR
:
267 log_fn(LOG_DEBUG
,"initiating directory fetch");
269 case DIR_PURPOSE_FETCH_RENDDESC
:
270 log_fn(LOG_DEBUG
,"initiating hidden-service descriptor fetch");
272 case DIR_PURPOSE_UPLOAD_DIR
:
273 log_fn(LOG_DEBUG
,"initiating server descriptor upload");
275 case DIR_PURPOSE_UPLOAD_RENDDESC
:
276 log_fn(LOG_DEBUG
,"initiating hidden-service descriptor upload");
278 case DIR_PURPOSE_FETCH_RUNNING_LIST
:
279 log_fn(LOG_DEBUG
,"initiating running-routers fetch");
282 log_fn(LOG_ERR
, "Unrecognized directory connection purpose.");
286 conn
= connection_new(CONN_TYPE_DIR
);
288 /* set up conn so it's got all the data we need to remember */
290 conn
->port
= dir_port
;
292 if (get_options()->HttpProxy
) {
293 addr
= get_options()->HttpProxyAddr
;
294 dir_port
= get_options()->HttpProxyPort
;
297 conn
->address
= tor_strdup(address
);
298 /* conn->nickname = tor_strdup(router->nickname); */
299 /* tor_assert(router->identity_pkey); */
300 /* conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey); */
301 /* crypto_pk_get_digest(conn->identity_pkey, conn->identity_digest); */
302 memcpy(conn
->identity_digest
, digest
, DIGEST_LEN
);
304 conn
->purpose
= purpose
;
306 /* give it an initial state */
307 conn
->state
= DIR_CONN_STATE_CONNECTING
;
309 if (purpose
== DIR_PURPOSE_FETCH_DIR
||
310 purpose
== DIR_PURPOSE_UPLOAD_DIR
||
311 purpose
== DIR_PURPOSE_FETCH_RUNNING_LIST
) {
312 /* then we want to connect directly */
313 switch (connection_connect(conn
, conn
->address
, addr
, dir_port
)) {
315 connection_dir_connect_failed(conn
);
316 connection_free(conn
);
319 conn
->state
= DIR_CONN_STATE_CLIENT_SENDING
; /* start flushing conn */
322 /* queue the command on the outbuf */
323 directory_send_command(conn
, platform
, purpose
, resource
,
324 payload
, payload_len
);
325 connection_watch_events(conn
, EV_READ
| EV_WRITE
);
326 /* writable indicates finish, readable indicates broken link,
327 error indicates broken link in windowsland. */
329 } else { /* we want to connect via tor */
330 /* make an AP connection
331 * populate it and add it at the right state
332 * socketpair and hook up both sides
334 conn
->s
= connection_ap_make_bridge(conn
->address
, conn
->port
);
336 log_fn(LOG_WARN
,"Making AP bridge to dirserver failed.");
337 connection_mark_for_close(conn
);
341 conn
->state
= DIR_CONN_STATE_CLIENT_SENDING
;
342 connection_add(conn
);
343 /* queue the command on the outbuf */
344 directory_send_command(conn
, platform
, purpose
, resource
,
345 payload
, payload_len
);
346 connection_watch_events(conn
, EV_READ
| EV_WRITE
);
350 /** Queue an appropriate HTTP command on conn-\>outbuf. The other args
351 * are as in directory_initiate_command.
354 directory_send_command(connection_t
*conn
, const char *platform
,
355 int purpose
, const char *resource
,
356 const char *payload
, size_t payload_len
) {
358 char proxystring
[128];
359 char hoststring
[128];
362 const char *httpcommand
= NULL
;
365 tor_assert(conn
->type
== CONN_TYPE_DIR
);
367 /* If we don't know the platform, assume it's up-to-date. */
368 use_newer
= platform
? tor_version_as_new_as(platform
, "0.0.9pre1"):1;
370 if (conn
->port
== 80) {
371 strlcpy(hoststring
, conn
->address
, sizeof(hoststring
));
373 tor_snprintf(hoststring
, sizeof(hoststring
),"%s:%d",conn
->address
, conn
->port
);
375 if (get_options()->HttpProxy
) {
376 tor_snprintf(proxystring
, sizeof(proxystring
),"http://%s", hoststring
);
382 case DIR_PURPOSE_FETCH_DIR
:
383 tor_assert(!resource
);
384 tor_assert(!payload
);
385 log_fn(LOG_DEBUG
, "Asking for %scompressed directory from server running %s",
386 use_newer
?"":"un", platform
?platform
:"<unknown version>");
388 strlcpy(url
, use_newer
? "/tor/dir.z" : "/", sizeof(url
));
390 case DIR_PURPOSE_FETCH_RUNNING_LIST
:
391 tor_assert(!resource
);
392 tor_assert(!payload
);
394 strlcpy(url
, use_newer
? "/tor/running-routers" : "/running-routers", sizeof(url
));
396 case DIR_PURPOSE_UPLOAD_DIR
:
397 tor_assert(!resource
);
399 httpcommand
= "POST";
400 strlcpy(url
, use_newer
? "/tor/" : "/", sizeof(url
));
402 case DIR_PURPOSE_FETCH_RENDDESC
:
403 tor_assert(resource
);
404 tor_assert(!payload
);
406 /* this must be true or we wouldn't be doing the lookup */
407 tor_assert(strlen(resource
) <= REND_SERVICE_ID_LEN
);
408 /* This breaks the function abstraction. */
409 strlcpy(conn
->rend_query
, resource
, sizeof(conn
->rend_query
));
412 tor_snprintf(url
, sizeof(url
), "%s/rendezvous/%s", use_newer
? "/tor" : "", resource
);
415 case DIR_PURPOSE_UPLOAD_RENDDESC
:
416 tor_assert(!resource
);
418 httpcommand
= "POST";
419 tor_snprintf(url
, sizeof(url
), "%s/rendezvous/publish", use_newer
? "/tor" : "");
423 tor_snprintf(tmp
, sizeof(tmp
), "%s %s%s HTTP/1.0\r\nContent-Length: %lu\r\nHost: %s\r\n\r\n",
427 payload
? (unsigned long)payload_len
: 0,
429 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
432 /* then send the payload afterwards too */
433 connection_write_to_buf(payload
, payload_len
, conn
);
437 /** Parse an HTTP request string <b>headers</b> of the form
438 * "\%s [http[s]://]\%s HTTP/1..."
439 * If it's well-formed, strdup the second \%s into *<b>url</b>, and
440 * null-terminate it. If the url doesn't start with "/tor/", rewrite it
441 * so it does. Return 0.
442 * Otherwise, return -1.
445 parse_http_url(char *headers
, char **url
)
447 char *s
, *start
, *tmp
;
449 s
= (char *)eat_whitespace_no_nl(headers
);
451 s
= (char *)find_whitespace(s
); /* get past GET/POST */
453 s
= (char *)eat_whitespace_no_nl(s
);
455 start
= s
; /* this is it, assuming it's valid */
456 s
= (char *)find_whitespace(start
);
459 /* tolerate the http[s] proxy style of putting the hostname in the url */
460 if (s
-start
>= 4 && !strcmpstart(start
,"http")) {
464 if (s
-tmp
>= 3 && !strcmpstart(tmp
,"://")) {
465 tmp
= strchr(tmp
+3, '/');
466 if (tmp
&& tmp
< s
) {
467 log_fn(LOG_DEBUG
,"Skipping over 'http[s]://hostname' string");
473 if (s
-start
< 5 || strcmpstart(start
,"/tor/")) { /* need to rewrite it */
474 *url
= tor_malloc(s
- start
+ 5);
475 strlcpy(*url
,"/tor", s
-start
+5);
476 strlcat((*url
)+4, start
, s
-start
+1);
478 *url
= tor_strndup(start
, s
-start
);
483 /** Parse an HTTP response string <b>headers</b> of the form
484 * "HTTP/1.\%d \%d\%s\r\n...".
485 * If it's well-formed, assign *<b>code</b> and return 0.
486 * If <b>date</b> is provided, set *date to the Date header in the
487 * http headers, or 0 if no such header is found. If <b>compression</b>
488 * is provided, set *<b>compression</b> to the compression method given
489 * in the Content-Encoding header, or 0 if no such header is found, or -1
490 * if the value of the header is not recognized.
491 * Otherwise, return -1.
494 parse_http_response(const char *headers
, int *code
, time_t *date
,
498 char datestr
[RFC1123_TIME_LEN
+1];
499 smartlist_t
*parsed_headers
;
503 while (TOR_ISSPACE(*headers
)) headers
++; /* tolerate leading whitespace */
505 if (sscanf(headers
, "HTTP/1.%d %d", &n1
, &n2
) < 2 ||
506 (n1
!= 0 && n1
!= 1) ||
507 (n2
< 100 || n2
>= 600)) {
508 log_fn(LOG_WARN
,"Failed to parse header '%s'",headers
);
513 parsed_headers
= smartlist_create();
514 smartlist_split_string(parsed_headers
, headers
, "\n",
515 SPLIT_SKIP_SPACE
|SPLIT_IGNORE_BLANK
, -1);
518 SMARTLIST_FOREACH(parsed_headers
, const char *, s
,
519 if (!strcmpstart(s
, "Date: ")) {
520 strlcpy(datestr
, s
+6, sizeof(datestr
));
521 /* This will do nothing on failure, so we don't need to check
522 the result. We shouldn't warn, since there are many other valid
523 date formats besides the one we use. */
524 parse_rfc1123_time(datestr
, date
);
529 const char *enc
= NULL
;
530 SMARTLIST_FOREACH(parsed_headers
, const char *, s
,
531 if (!strcmpstart(s
, "Content-Encoding: ")) {
534 if (!enc
|| !strcmp(enc
, "identity")) {
536 } else if (!strcmp(enc
, "deflate") || !strcmp(enc
, "x-deflate")) {
537 *compression
= ZLIB_METHOD
;
538 } else if (!strcmp(enc
, "gzip") || !strcmp(enc
, "x-gzip")) {
539 *compression
= GZIP_METHOD
;
541 log_fn(LOG_INFO
, "Unrecognized content encoding: '%s'", enc
);
545 SMARTLIST_FOREACH(parsed_headers
, char *, s
, tor_free(s
));
546 smartlist_free(parsed_headers
);
551 /** Return true iff <b>body</b> doesn't start with a plausible router or
552 * running-list or directory opening. This is a sign of possible compression.
555 body_is_plausible(const char *body
, size_t len
, int purpose
)
559 return 1; /* empty bodies don't need decompression */
562 if (purpose
!= DIR_PURPOSE_FETCH_RENDDESC
) {
563 if (!strcmpstart(body
,"router") ||
564 !strcmpstart(body
,"signed-directory") ||
565 !strcmpstart(body
,"network-status") ||
566 !strcmpstart(body
,"running-routers"))
569 if (!TOR_ISPRINT(body
[i
]) && !TOR_ISSPACE(body
[i
]))
578 /** We are a client, and we've finished reading the server's
579 * response. Parse and it and act appropriately.
581 * Return -1 if an error has occurred, or 0 normally. The caller
582 * will take care of marking the connection for close.
585 connection_dir_client_reached_eof(connection_t
*conn
)
591 time_t now
, date_header
=0;
597 switch (fetch_from_buf_http(conn
->inbuf
,
598 &headers
, MAX_HEADERS_SIZE
,
599 &body
, &body_len
, MAX_DIR_SIZE
)) {
600 case -1: /* overflow */
601 log_fn(LOG_WARN
,"'fetch' response too large (server '%s'). Failing.", conn
->address
);
604 log_fn(LOG_INFO
,"'fetch' response not all here, but we're at eof. Closing.");
606 /* case 1, fall through */
609 if (parse_http_response(headers
, &status_code
, &date_header
,
611 log_fn(LOG_WARN
,"Unparseable headers (server '%s'). Closing.", conn
->address
);
612 tor_free(body
); tor_free(headers
);
615 if (date_header
> 0) {
617 delta
= now
-date_header
;
618 if (abs(delta
)>ALLOW_DIRECTORY_TIME_SKEW
) {
619 routerinfo_t
*router
= router_get_by_digest(conn
->identity_digest
);
620 log_fn((router
&& router
->is_verified
) ? LOG_WARN
: LOG_INFO
,
621 "Received directory with skewed time (server '%s'): we are %d minutes %s, or the directory is %d minutes %s.",
623 abs(delta
)/60, delta
>0 ? "ahead" : "behind",
624 abs(delta
)/60, delta
>0 ? "behind" : "ahead");
625 skewed
= 1; /* don't check the recommended-versions line */
627 log_fn(LOG_INFO
, "Time on received directory is within tolerance; we are %d seconds skewed. (That's okay.)", delta
);
631 plausible
= body_is_plausible(body
, body_len
, conn
->purpose
);
632 if (compression
|| !plausible
) {
633 char *new_body
= NULL
;
635 int guessed
= detect_compression_method(body
, body_len
);
636 if (compression
<= 0 || guessed
!= compression
) {
637 /* Tell the user if we don't believe what we're told about compression.*/
638 const char *description1
, *description2
;
639 if (compression
== ZLIB_METHOD
)
640 description1
= "as deflated";
641 else if (compression
== GZIP_METHOD
)
642 description1
= "as gzipped";
643 else if (compression
== 0)
644 description1
= "as uncompressed";
646 description1
= "with an unknown Content-Encoding";
647 if (guessed
== ZLIB_METHOD
)
648 description2
= "deflated";
649 else if (guessed
== GZIP_METHOD
)
650 description2
= "gzipped";
652 description2
= "confusing binary junk";
654 description2
= "uncompressed";
656 log_fn(LOG_INFO
, "HTTP body from server '%s' was labeled %s,"
657 "but it seems to be %s.%s",
658 conn
->address
, description1
, description2
,
659 (compression
>0 && guessed
>0)?" Trying both.":"");
661 /* Try declared compression first if we can. */
663 tor_gzip_uncompress(&new_body
, &new_len
, body
, body_len
, compression
);
664 /* Okay, if that didn't work, and we think that it was compressed
665 * differently, try that. */
666 if (!new_body
&& guessed
> 0 && compression
!= guessed
)
667 tor_gzip_uncompress(&new_body
, &new_len
, body
, body_len
, guessed
);
668 /* If we're pretty sure that we have a compressed directory, and
669 * we didn't manage to uncompress it, then warn and bail. */
670 if (!plausible
&& !new_body
) {
671 log_fn(LOG_WARN
, "Unable to decompress HTTP body (server '%s').", conn
->address
);
672 tor_free(body
); tor_free(headers
);
682 if (conn
->purpose
== DIR_PURPOSE_FETCH_DIR
) {
683 /* fetch/process the directory to learn about new routers. */
684 log_fn(LOG_INFO
,"Received directory (size %d) from server '%s'",
685 (int)body_len
, conn
->address
);
686 if (status_code
== 503 || body_len
== 0) {
687 log_fn(LOG_INFO
,"Empty directory. Ignoring.");
688 tor_free(body
); tor_free(headers
);
691 if (status_code
!= 200) {
692 log_fn(LOG_WARN
,"Received http status code %d from server '%s'. Failing.",
693 status_code
, conn
->address
);
694 tor_free(body
); tor_free(headers
);
697 if (router_load_routerlist_from_directory(body
, NULL
, skewed
, 0) < 0) {
698 log_fn(LOG_NOTICE
,"I failed to parse the directory I fetched from %s:%d. Ignoring.", conn
->address
, conn
->port
);
700 log_fn(LOG_INFO
,"updated routers.");
702 directory_has_arrived(time(NULL
)); /* do things we've been waiting to do */
705 if (conn
->purpose
== DIR_PURPOSE_FETCH_RUNNING_LIST
) {
706 running_routers_t
*rrs
;
708 /* just update our list of running routers, if this list is new info */
709 log_fn(LOG_INFO
,"Received running-routers list (size %d)", (int)body_len
);
710 if (status_code
!= 200) {
711 log_fn(LOG_WARN
,"Received http status code %d from server '%s'. Failing.",
712 status_code
, conn
->address
);
713 tor_free(body
); tor_free(headers
);
716 if (!(rrs
= router_parse_runningrouters(body
, 1))) {
717 log_fn(LOG_WARN
, "Can't parse runningrouters list (server '%s')", conn
->address
);
718 tor_free(body
); tor_free(headers
);
721 router_get_routerlist(&rl
);
723 routerlist_update_from_runningrouters(rl
,rrs
);
724 running_routers_free(rrs
);
727 if (conn
->purpose
== DIR_PURPOSE_UPLOAD_DIR
) {
728 switch (status_code
) {
730 log_fn(LOG_INFO
,"eof (status 200) after uploading server descriptor: finished.");
733 log_fn(LOG_WARN
,"http status 400 (bad request) response from dirserver '%s'. Malformed server descriptor?", conn
->address
);
736 log_fn(LOG_WARN
,"http status 403 (unapproved server) response from dirserver '%s'. Is your clock skewed? Have you mailed us your key fingerprint? Are you using the right key? Are you using a private IP address? See http://tor.eff.org/doc/tor-doc.html#server.", conn
->address
);
739 log_fn(LOG_WARN
,"http status %d response unrecognized (server '%s').", status_code
, conn
->address
);
744 if (conn
->purpose
== DIR_PURPOSE_FETCH_RENDDESC
) {
745 log_fn(LOG_INFO
,"Received rendezvous descriptor (size %d, status code %d)",
746 (int)body_len
, status_code
);
747 switch (status_code
) {
749 if (rend_cache_store(body
, body_len
) < 0) {
750 log_fn(LOG_WARN
,"Failed to store rendezvous descriptor.");
751 /* alice's ap_stream will notice when connection_mark_for_close
754 /* success. notify pending connections about this. */
755 conn
->purpose
= DIR_PURPOSE_HAS_FETCHED_RENDDESC
;
756 rend_client_desc_here(conn
->rend_query
);
760 /* not there. pending connections will be notified when
761 * connection_mark_for_close cleans it up. */
764 log_fn(LOG_WARN
,"http status 400 (bad request). Dirserver didn't like our rendezvous query?");
769 if (conn
->purpose
== DIR_PURPOSE_UPLOAD_RENDDESC
) {
770 switch (status_code
) {
772 log_fn(LOG_INFO
,"eof (status 200) after uploading rendezvous descriptor: finished.");
775 log_fn(LOG_WARN
,"http status 400 (bad request) response from dirserver. Malformed rendezvous descriptor?");
778 log_fn(LOG_WARN
,"http status %d response unrecognized.", status_code
);
782 tor_free(body
); tor_free(headers
);
786 int connection_dir_reached_eof(connection_t
*conn
) {
788 if (conn
->state
!= DIR_CONN_STATE_CLIENT_READING
) {
789 log_fn(LOG_INFO
,"conn reached eof, not reading. Closing.");
790 connection_close_immediate(conn
); /* it was an error; give up on flushing */
791 connection_mark_for_close(conn
);
795 retval
= connection_dir_client_reached_eof(conn
);
796 connection_mark_for_close(conn
);
800 /** Read handler for directory connections. (That's connections <em>to</em>
801 * directory servers and connections <em>at</em> directory servers.)
803 int connection_dir_process_inbuf(connection_t
*conn
) {
806 tor_assert(conn
->type
== CONN_TYPE_DIR
);
808 /* Directory clients write, then read data until they receive EOF;
809 * directory servers read data until they get an HTTP command, then
810 * write their response (when it's finished flushing, they mark for
814 /* If we're on the dirserver side, look for a command. */
815 if (conn
->state
== DIR_CONN_STATE_SERVER_COMMAND_WAIT
) {
816 if (directory_handle_command(conn
) < 0) {
817 connection_mark_for_close(conn
);
823 /* XXX for READ states, might want to make sure inbuf isn't too big */
825 log_fn(LOG_DEBUG
,"Got data, not eof. Leaving on inbuf.");
829 /** Create an http response for the client <b>conn</b> out of
830 * <b>status</b> and <b>reason_phrase</b>. Write it to <b>conn</b>.
833 write_http_status_line(connection_t
*conn
, int status
,
834 const char *reason_phrase
)
837 if (tor_snprintf(buf
, sizeof(buf
), "HTTP/1.0 %d %s\r\n\r\n",
838 status
, reason_phrase
) < 0) {
839 log_fn(LOG_WARN
,"Bug: status line too long.");
842 connection_write_to_buf(buf
, strlen(buf
), conn
);
845 /** Helper function: called when a dirserver gets a complete HTTP GET
846 * request. Look for a request for a directory or for a rendezvous
847 * service descriptor. On finding one, write a response into
848 * conn-\>outbuf. If the request is unrecognized, send a 400.
849 * Always return 0. */
851 directory_handle_command_get(connection_t
*conn
, char *headers
,
852 char *body
, size_t body_len
)
858 char date
[RFC1123_TIME_LEN
+1];
860 log_fn(LOG_DEBUG
,"Received GET command.");
862 conn
->state
= DIR_CONN_STATE_SERVER_WRITING
;
864 if (parse_http_url(headers
, &url
) < 0) {
865 write_http_status_line(conn
, 400, "Bad request");
868 log_fn(LOG_INFO
,"rewritten url as '%s'.", url
);
870 if (!strcmp(url
,"/tor/") || !strcmp(url
,"/tor/dir.z")) { /* directory fetch */
871 int deflated
= !strcmp(url
,"/tor/dir.z");
872 dlen
= dirserv_get_directory(&cp
, deflated
);
877 log_fn(LOG_NOTICE
,"Client asked for the mirrored directory, but we don't have a good one yet. Sending 503 Dir not available.");
878 write_http_status_line(conn
, 503, "Directory unavailable");
882 log_fn(LOG_DEBUG
,"Dumping %sdirectory to client.",
883 deflated
?"deflated ":"");
884 format_rfc1123_time(date
, time(NULL
));
885 tor_snprintf(tmp
, sizeof(tmp
), "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\nContent-Type: text/plain\r\nContent-Encoding: %s\r\n\r\n",
888 deflated
?"deflate":"identity");
889 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
890 connection_write_to_buf(cp
, dlen
, conn
);
894 if (!strcmp(url
,"/tor/running-routers") ||
895 !strcmp(url
,"/tor/running-routers.z")) { /* running-routers fetch */
896 int deflated
= !strcmp(url
,"/tor/dir.z");
898 dlen
= dirserv_get_runningrouters(&cp
, deflated
);
899 if (!dlen
) { /* we failed to create/cache cp */
900 write_http_status_line(conn
, 503, "Directory unavailable");
904 format_rfc1123_time(date
, time(NULL
));
905 tor_snprintf(tmp
, sizeof(tmp
), "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\nContent-Type: text/plain\r\nContent-Encoding: %s\r\n\r\n",
908 deflated
?"deflate":"identity");
909 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
910 connection_write_to_buf(cp
, strlen(cp
), conn
);
914 if (!strcmpstart(url
,"/tor/rendezvous/")) {
915 /* rendezvous descriptor fetch */
919 if (!authdir_mode(get_options())) {
920 /* We don't hand out rend descs. In fact, it could be a security
921 * risk, since rend_cache_lookup_desc() below would provide it
922 * if we're gone to the site recently, and 404 if we haven't.
925 write_http_status_line(conn
, 400, "Nonauthoritative directory does not not store rendezvous descriptors.");
929 switch (rend_cache_lookup_desc(url
+strlen("/tor/rendezvous/"), &descp
, &desc_len
)) {
931 format_rfc1123_time(date
, time(NULL
));
932 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",
934 (int)desc_len
); /* can't include descp here, because it's got nuls */
935 connection_write_to_buf(tmp
, strlen(tmp
), conn
);
936 connection_write_to_buf(descp
, desc_len
, conn
);
938 case 0: /* well-formed but not present */
939 write_http_status_line(conn
, 404, "Not found");
941 case -1: /* not well-formed */
942 write_http_status_line(conn
, 400, "Bad request");
949 /* we didn't recognize the url */
950 write_http_status_line(conn
, 404, "Not found");
955 /** Helper function: called when a dirserver gets a complete HTTP POST
956 * request. Look for an uploaded server descriptor or rendezvous
957 * service descriptor. On finding one, process it and write a
958 * response into conn-\>outbuf. If the request is unrecognized, send a
959 * 400. Always return 0. */
961 directory_handle_command_post(connection_t
*conn
, char *headers
,
962 char *body
, size_t body_len
)
967 log_fn(LOG_DEBUG
,"Received POST command.");
969 conn
->state
= DIR_CONN_STATE_SERVER_WRITING
;
971 if (!authdir_mode(get_options())) {
972 /* we just provide cached directories; we don't want to
973 * receive anything. */
974 write_http_status_line(conn
, 400, "Nonauthoritative directory does not not store server descriptors.");
978 if (parse_http_url(headers
, &url
) < 0) {
979 write_http_status_line(conn
, 400, "Bad request");
982 log_fn(LOG_INFO
,"rewritten url as '%s'.", url
);
984 if (!strcmp(url
,"/tor/")) { /* server descriptor post */
987 switch (dirserv_add_descriptor(&cp
, &msg
)) {
990 /* malformed descriptor, or something wrong */
991 write_http_status_line(conn
, 400, msg
?msg
:"Malformed or unacceptable server descriptor");
994 /* descriptor was well-formed but server has not been approved */
995 write_http_status_line(conn
, 200, msg
?msg
:"Unverified server descriptor accepted");
998 dirserv_get_directory(&cp
, 0); /* rebuild and write to disk */
999 write_http_status_line(conn
, 200, msg
?msg
:"Verified server descriptor accepted");
1006 if (!strcmpstart(url
,"/tor/rendezvous/publish")) {
1007 /* rendezvous descriptor post */
1008 if (rend_cache_store(body
, body_len
) < 0)
1009 write_http_status_line(conn
, 400, "Invalid service descriptor rejected");
1011 write_http_status_line(conn
, 200, "Service descriptor stored");
1016 /* we didn't recognize the url */
1017 write_http_status_line(conn
, 404, "Not found");
1022 /** Called when a dirserver receives data on a directory connection;
1023 * looks for an HTTP request. If the request is complete, remove it
1024 * from the inbuf, try to process it; otherwise, leave it on the
1025 * buffer. Return a 0 on success, or -1 on error.
1027 static int directory_handle_command(connection_t
*conn
) {
1028 char *headers
=NULL
, *body
=NULL
;
1033 tor_assert(conn
->type
== CONN_TYPE_DIR
);
1035 switch (fetch_from_buf_http(conn
->inbuf
,
1036 &headers
, MAX_HEADERS_SIZE
,
1037 &body
, &body_len
, MAX_BODY_SIZE
)) {
1038 case -1: /* overflow */
1039 log_fn(LOG_WARN
,"Invalid input. Closing.");
1042 log_fn(LOG_DEBUG
,"command not all here yet.");
1044 /* case 1, fall through */
1047 log_fn(LOG_DEBUG
,"headers '%s', body '%s'.", headers
, body
);
1049 if (!strncasecmp(headers
,"GET",3))
1050 r
= directory_handle_command_get(conn
, headers
, body
, body_len
);
1051 else if (!strncasecmp(headers
,"POST",4))
1052 r
= directory_handle_command_post(conn
, headers
, body
, body_len
);
1054 log_fn(LOG_WARN
,"Got headers '%s' with unknown command. Closing.", headers
);
1058 tor_free(headers
); tor_free(body
);
1062 /** Write handler for directory connections; called when all data has
1063 * been flushed. Close the connection or wait for a response as
1066 int connection_dir_finished_flushing(connection_t
*conn
) {
1069 tor_assert(conn
->type
== CONN_TYPE_DIR
);
1071 switch (conn
->state
) {
1072 case DIR_CONN_STATE_CLIENT_SENDING
:
1073 log_fn(LOG_DEBUG
,"client finished sending command.");
1074 conn
->state
= DIR_CONN_STATE_CLIENT_READING
;
1075 connection_stop_writing(conn
);
1077 case DIR_CONN_STATE_SERVER_WRITING
:
1078 log_fn(LOG_INFO
,"Finished writing server response. Closing.");
1079 connection_mark_for_close(conn
);
1082 log_fn(LOG_WARN
,"Bug: called in unexpected state %d.", conn
->state
);
1091 /** Connected handler for directory connections: begin sending data to the
1093 int connection_dir_finished_connecting(connection_t
*conn
)
1096 tor_assert(conn
->type
== CONN_TYPE_DIR
);
1097 tor_assert(conn
->state
== DIR_CONN_STATE_CONNECTING
);
1099 log_fn(LOG_INFO
,"Dir connection to router %s:%u established.",
1100 conn
->address
,conn
->port
);
1102 conn
->state
= DIR_CONN_STATE_CLIENT_SENDING
; /* start flushing conn */