new config option DirAllowPrivateAddresses for authdirservers.
[tor.git] / src / or / directory.c
blob696e113486b4233f90ca636f40ca3be2de752eab
1 /* Copyright 2001-2004 Roger Dingledine.
2 * Copyright 2004 Roger Dingledine, Nick Mathewson. */
3 /* See LICENSE for licensing information */
4 /* $Id$ */
5 const char directory_c_id[] = "$Id$";
7 #include "or.h"
9 /**
10 * \file directory.c
11 * \brief Implement directory HTTP protocol.
12 **/
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
22 * do_hup() 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
31 static void
32 directory_initiate_command_router(routerinfo_t *router, uint8_t purpose,
33 const char *resource,
34 const char *payload, size_t payload_len);
35 static void
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);
39 static void
40 directory_initiate_command(const char *address, uint32_t addr, uint16_t port,
41 const char *platform,
42 const char *digest, uint8_t purpose,
43 const char *resource,
44 const char *payload, size_t payload_len);
46 static void
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);
52 /********* START VARIABLES **********/
54 static addr_policy_t *dir_policy = NULL;
56 #if 0 /* commented out for now, since for now what clients send is
57 different from what servers want to receive */
58 /** URL for publishing rendezvous descriptors. */
59 char rend_publish_string[] = "/tor/rendezvous/publish";
60 /** Prefix for downloading rendezvous descriptors. */
61 char rend_fetch_url[] = "/tor/rendezvous/";
62 #endif
64 #define MAX_HEADERS_SIZE 50000
65 #define MAX_BODY_SIZE 500000
67 #define ALLOW_DIRECTORY_TIME_SKEW 30*60
69 /********* END VARIABLES ************/
71 /** Parse get_options()->DirPolicy, and put the processed version in
72 * &dir_policy. Ignore port specifiers.
74 void
75 parse_dir_policy(void)
77 addr_policy_t *n;
78 if (dir_policy) {
79 addr_policy_free(dir_policy);
80 dir_policy = NULL;
82 config_parse_addr_policy(get_options()->DirPolicy, &dir_policy);
83 /* ports aren't used. */
84 for (n=dir_policy; n; n = n->next) {
85 n->prt_min = 1;
86 n->prt_max = 65535;
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.
93 int dir_policy_permits_address(uint32_t addr)
95 int a;
97 if (!dir_policy) /* 'no dir policy' means 'accept' */
98 return 1;
99 a = router_compare_addr_to_addr_policy(addr, 1, dir_policy);
100 if (a==-1)
101 return 0;
102 else if (a==0)
103 return 1;
104 tor_assert(a==1);
105 log_fn(LOG_WARN, "Bug: got unexpected 'maybe' answer from dir policy");
106 return 0;
109 /** Start a connection to every known directory server, using
110 * connection purpose 'purpose' and uploading the payload 'payload'
111 * (length 'payload_len'). The purpose should be one of
112 * 'DIR_PURPOSE_UPLOAD_DIR' or 'DIR_PURPOSE_UPLOAD_RENDDESC'.
114 void
115 directory_post_to_dirservers(uint8_t purpose, const char *payload,
116 size_t payload_len)
118 smartlist_t *dirservers;
119 char buf[16];
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 tor_snprintf(buf,sizeof(buf),"%d",ds->dir_port);
134 if (!smartlist_string_isin(get_options()->FirewallPorts, buf))
135 continue;
137 directory_initiate_command_trusted_dir(ds, purpose, NULL,
138 payload, payload_len);
142 /** Start a connection to a random running directory server, using
143 * connection purpose 'purpose' requesting 'resource'. The purpose
144 * should be one of 'DIR_PURPOSE_FETCH_DIR',
145 * 'DIR_PURPOSE_FETCH_RENDDESC', 'DIR_PURPOSE_FETCH_RUNNING_LIST.'
146 * If <b>retry_if_no_servers</b>, then if all the possible servers seem
147 * down, mark them up and try again.
149 void
150 directory_get_from_dirserver(uint8_t purpose, const char *resource,
151 int retry_if_no_servers)
153 routerinfo_t *r = NULL;
154 trusted_dir_server_t *ds = NULL;
155 int fascistfirewall = get_options()->FascistFirewall;
157 if (purpose == DIR_PURPOSE_FETCH_DIR ||
158 purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
159 if (advertised_server_mode()) {
160 /* only ask authdirservers, and don't ask myself */
161 ds = router_pick_trusteddirserver(1, fascistfirewall,
162 retry_if_no_servers);
163 } else {
164 /* anybody with a non-zero dirport will do */
165 r = router_pick_directory_server(1, fascistfirewall,
166 purpose==DIR_PURPOSE_FETCH_RUNNING_LIST,
167 retry_if_no_servers);
168 if (!r) {
169 log_fn(LOG_INFO, "No router found for %s; falling back to dirserver list",
170 purpose == DIR_PURPOSE_FETCH_RUNNING_LIST
171 ? "status list" : "directory");
172 ds = router_pick_trusteddirserver(1, fascistfirewall,
173 retry_if_no_servers);
176 } else { // (purpose == DIR_PURPOSE_FETCH_RENDDESC)
177 /* only ask authdirservers, any of them will do */
178 /* Never use fascistfirewall; we're going via Tor. */
179 ds = router_pick_trusteddirserver(0, 0, retry_if_no_servers);
182 if (r)
183 directory_initiate_command_router(r, purpose, resource, NULL, 0);
184 else if (ds)
185 directory_initiate_command_trusted_dir(ds, purpose, resource, NULL, 0);
186 else {
187 log_fn(LOG_WARN,"No running dirservers known. Not trying. (purpose %d)", purpose);
191 /** Launch a new connection to the directory server <b>router</b> to upload or
192 * download a service or rendezvous descriptor. <b>purpose</b> determines what
193 * kind of directory connection we're launching, and must be one of
194 * DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC}.
196 * When uploading, <b>payload</b> and <b>payload_len</b> determine the content
197 * of the HTTP post. Otherwise, <b>payload</b> should be NULL.
199 * When fetching a rendezvous descriptor, <b>resource</b> is the service ID we
200 * want to fetch.
202 static void
203 directory_initiate_command_router(routerinfo_t *router, uint8_t purpose,
204 const char *resource,
205 const char *payload, size_t payload_len)
207 directory_initiate_command(router->address, router->addr, router->dir_port,
208 router->platform, router->identity_digest,
209 purpose, resource, payload, payload_len);
212 /** As directory_initiate_command_router, but send the command to a trusted
213 * directory server <b>dirserv</b>. **/
214 static void
215 directory_initiate_command_trusted_dir(trusted_dir_server_t *dirserv,
216 uint8_t purpose, const char *resource,
217 const char *payload, size_t payload_len)
219 directory_initiate_command(dirserv->address, dirserv->addr,dirserv->dir_port,
220 NULL, dirserv->digest, purpose, resource, payload, payload_len);
223 /** Called when we are unable to complete our connection to a
224 * directory server: Mark the router as down and try again if possible.
226 void
227 connection_dir_connect_failed(connection_t *conn)
229 router_mark_as_down(conn->identity_digest); /* don't try him again */
230 if (conn->purpose == DIR_PURPOSE_FETCH_DIR ||
231 conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
232 log_fn(LOG_INFO, "Giving up on directory server at '%s'; retrying",
233 conn->address);
234 directory_get_from_dirserver(conn->purpose, NULL,
235 0 /* don't retry_if_no_servers */);
239 /** Helper for directory_initiate_command(router|trusted_dir): send the
240 * command to a server whose address is <b>address</b>, whose IP is
241 * <b>addr</b>, whose directory port is <b>dir_port</b>, whose tor version is
242 * <b>platform</b>, and whose identity key digest is <b>digest</b>. The
243 * <b>platform</b> argument is optional; the others are required. */
244 static void
245 directory_initiate_command(const char *address, uint32_t addr,
246 uint16_t dir_port, const char *platform,
247 const char *digest, uint8_t purpose,
248 const char *resource,
249 const char *payload, size_t payload_len)
251 connection_t *conn;
253 tor_assert(address);
254 tor_assert(addr);
255 tor_assert(dir_port);
256 tor_assert(digest);
258 switch (purpose) {
259 case DIR_PURPOSE_FETCH_DIR:
260 log_fn(LOG_DEBUG,"initiating directory fetch");
261 break;
262 case DIR_PURPOSE_FETCH_RENDDESC:
263 log_fn(LOG_DEBUG,"initiating hidden-service descriptor fetch");
264 break;
265 case DIR_PURPOSE_UPLOAD_DIR:
266 log_fn(LOG_DEBUG,"initiating server descriptor upload");
267 break;
268 case DIR_PURPOSE_UPLOAD_RENDDESC:
269 log_fn(LOG_DEBUG,"initiating hidden-service descriptor upload");
270 break;
271 case DIR_PURPOSE_FETCH_RUNNING_LIST:
272 log_fn(LOG_DEBUG,"initiating running-routers fetch");
273 break;
274 default:
275 log_fn(LOG_ERR, "Unrecognized directory connection purpose.");
276 tor_assert(0);
279 conn = connection_new(CONN_TYPE_DIR);
281 /* set up conn so it's got all the data we need to remember */
282 conn->addr = addr;
283 conn->port = dir_port;
285 if (get_options()->HttpProxy) {
286 addr = get_options()->HttpProxyAddr;
287 dir_port = get_options()->HttpProxyPort;
290 conn->address = tor_strdup(address);
291 /* conn->nickname = tor_strdup(router->nickname); */
292 /* tor_assert(router->identity_pkey); */
293 /* conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey); */
294 /* crypto_pk_get_digest(conn->identity_pkey, conn->identity_digest); */
295 memcpy(conn->identity_digest, digest, DIGEST_LEN);
297 conn->purpose = purpose;
299 /* give it an initial state */
300 conn->state = DIR_CONN_STATE_CONNECTING;
302 if (purpose == DIR_PURPOSE_FETCH_DIR ||
303 purpose == DIR_PURPOSE_UPLOAD_DIR ||
304 purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
305 /* then we want to connect directly */
306 switch (connection_connect(conn, conn->address, addr, dir_port)) {
307 case -1:
308 connection_dir_connect_failed(conn);
309 connection_free(conn);
310 return;
311 case 1:
312 conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
313 /* fall through */
314 case 0:
315 /* queue the command on the outbuf */
316 directory_send_command(conn, platform, purpose, resource,
317 payload, payload_len);
318 connection_watch_events(conn, POLLIN | POLLOUT | POLLERR);
319 /* writable indicates finish, readable indicates broken link,
320 error indicates broken link in windowsland. */
322 } else { /* we want to connect via tor */
323 /* make an AP connection
324 * populate it and add it at the right state
325 * socketpair and hook up both sides
327 conn->s = connection_ap_make_bridge(conn->address, conn->port);
328 if (conn->s < 0) {
329 log_fn(LOG_WARN,"Making AP bridge to dirserver failed.");
330 connection_mark_for_close(conn);
331 return;
334 conn->state = DIR_CONN_STATE_CLIENT_SENDING;
335 connection_add(conn);
336 /* queue the command on the outbuf */
337 directory_send_command(conn, platform, purpose, resource,
338 payload, payload_len);
339 connection_watch_events(conn, POLLIN | POLLOUT | POLLERR);
343 /** Queue an appropriate HTTP command on conn-\>outbuf. The other args
344 * are as in directory_initiate_command.
346 static void
347 directory_send_command(connection_t *conn, const char *platform,
348 int purpose, const char *resource,
349 const char *payload, size_t payload_len) {
350 char tmp[8192];
351 char proxystring[128];
352 char hoststring[128];
353 char url[128];
354 int use_newer = 0;
355 const char *httpcommand = NULL;
357 tor_assert(conn);
358 tor_assert(conn->type == CONN_TYPE_DIR);
360 /* If we don't know the platform, assume it's up-to-date. */
361 use_newer = platform ? tor_version_as_new_as(platform, "0.0.9pre1"):1;
363 if (conn->port == 80) {
364 strlcpy(hoststring, conn->address, sizeof(hoststring));
365 } else {
366 tor_snprintf(hoststring, sizeof(hoststring),"%s:%d",conn->address, conn->port);
368 if (get_options()->HttpProxy) {
369 tor_snprintf(proxystring, sizeof(proxystring),"http://%s", hoststring);
370 } else {
371 proxystring[0] = 0;
374 switch (purpose) {
375 case DIR_PURPOSE_FETCH_DIR:
376 tor_assert(!resource);
377 tor_assert(!payload);
378 log_fn(LOG_DEBUG, "Asking for %scompressed directory from server running %s",
379 use_newer?"":"un", platform?platform:"<unknown version>");
380 httpcommand = "GET";
381 strlcpy(url, use_newer ? "/tor/dir.z" : "/", sizeof(url));
382 break;
383 case DIR_PURPOSE_FETCH_RUNNING_LIST:
384 tor_assert(!resource);
385 tor_assert(!payload);
386 httpcommand = "GET";
387 strlcpy(url, use_newer ? "/tor/running-routers" : "/running-routers", sizeof(url));
388 break;
389 case DIR_PURPOSE_UPLOAD_DIR:
390 tor_assert(!resource);
391 tor_assert(payload);
392 httpcommand = "POST";
393 strlcpy(url, use_newer ? "/tor/" : "/", sizeof(url));
394 break;
395 case DIR_PURPOSE_FETCH_RENDDESC:
396 tor_assert(resource);
397 tor_assert(!payload);
399 /* this must be true or we wouldn't be doing the lookup */
400 tor_assert(strlen(resource) <= REND_SERVICE_ID_LEN);
401 /* This breaks the function abstraction. */
402 strlcpy(conn->rend_query, resource, sizeof(conn->rend_query));
404 httpcommand = "GET";
405 tor_snprintf(url, sizeof(url), "%s/rendezvous/%s", use_newer ? "/tor" : "", resource);
407 break;
408 case DIR_PURPOSE_UPLOAD_RENDDESC:
409 tor_assert(!resource);
410 tor_assert(payload);
411 httpcommand = "POST";
412 tor_snprintf(url, sizeof(url), "%s/rendezvous/publish", use_newer ? "/tor" : "");
413 break;
416 tor_snprintf(tmp, sizeof(tmp), "%s %s%s HTTP/1.0\r\nContent-Length: %lu\r\nHost: %s\r\n\r\n",
417 httpcommand,
418 proxystring,
419 url,
420 payload ? (unsigned long)payload_len : 0,
421 hoststring);
422 connection_write_to_buf(tmp, strlen(tmp), conn);
424 if (payload) {
425 /* then send the payload afterwards too */
426 connection_write_to_buf(payload, payload_len, conn);
430 /** Parse an HTTP request string <b>headers</b> of the form
431 * "\%s [http[s]://]\%s HTTP/1..."
432 * If it's well-formed, strdup the second \%s into *<b>url</b>, and
433 * null-terminate it. If the url doesn't start with "/tor/", rewrite it
434 * so it does. Return 0.
435 * Otherwise, return -1.
437 static int
438 parse_http_url(char *headers, char **url)
440 char *s, *start, *tmp;
442 s = (char *)eat_whitespace_no_nl(headers);
443 if (!*s) return -1;
444 s = (char *)find_whitespace(s); /* get past GET/POST */
445 if (!*s) return -1;
446 s = (char *)eat_whitespace_no_nl(s);
447 if (!*s) return -1;
448 start = s; /* this is it, assuming it's valid */
449 s = (char *)find_whitespace(start);
450 if (!*s) return -1;
452 /* tolerate the http[s] proxy style of putting the hostname in the url */
453 if (s-start >= 4 && !strcmpstart(start,"http")) {
454 tmp = start + 4;
455 if (*tmp == 's')
456 tmp++;
457 if (s-tmp >= 3 && !strcmpstart(tmp,"://")) {
458 tmp = strchr(tmp+3, '/');
459 if (tmp && tmp < s) {
460 log_fn(LOG_DEBUG,"Skipping over 'http[s]://hostname' string");
461 start = tmp;
466 if (s-start < 5 || strcmpstart(start,"/tor/")) { /* need to rewrite it */
467 *url = tor_malloc(s - start + 5);
468 strlcpy(*url,"/tor", s-start+5);
469 strlcat((*url)+4, start, s-start+1);
470 } else {
471 *url = tor_strndup(start, s-start);
473 return 0;
476 /** Parse an HTTP response string <b>headers</b> of the form
477 * "HTTP/1.\%d \%d\%s\r\n...".
478 * If it's well-formed, assign *<b>code</b>, point and return 0.
479 * If <b>date</b> is provided, set *date to the Date header in the
480 * http headers, or 0 if no such header is found.
481 * Otherwise, return -1.
483 static int
484 parse_http_response(const char *headers, int *code, time_t *date,
485 int *compression)
487 int n1, n2;
488 char datestr[RFC1123_TIME_LEN+1];
489 smartlist_t *parsed_headers;
490 tor_assert(headers);
491 tor_assert(code);
493 while (TOR_ISSPACE(*headers)) headers++; /* tolerate leading whitespace */
495 if (sscanf(headers, "HTTP/1.%d %d", &n1, &n2) < 2 ||
496 (n1 != 0 && n1 != 1) ||
497 (n2 < 100 || n2 >= 600)) {
498 log_fn(LOG_WARN,"Failed to parse header '%s'",headers);
499 return -1;
501 *code = n2;
503 parsed_headers = smartlist_create();
504 smartlist_split_string(parsed_headers, headers, "\n",
505 SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
506 if (date) {
507 *date = 0;
508 SMARTLIST_FOREACH(parsed_headers, const char *, s,
509 if (!strcmpstart(s, "Date: ")) {
510 strlcpy(datestr, s+6, sizeof(datestr));
511 /* This will do nothing on failure, so we don't need to check
512 the result. We shouldn't warn, since there are many other valid
513 date formats besides the one we use. */
514 parse_rfc1123_time(datestr, date);
515 break;
518 if (compression) {
519 const char *enc = NULL;
520 SMARTLIST_FOREACH(parsed_headers, const char *, s,
521 if (!strcmpstart(s, "Content-Encoding: ")) {
522 enc = s+18; break;
524 if (!enc || !strcmp(enc, "identity")) {
525 *compression = 0;
526 } else if (!strcmp(enc, "deflate") || !strcmp(enc, "x-deflate")) {
527 *compression = ZLIB_METHOD;
528 } else if (!strcmp(enc, "gzip") || !strcmp(enc, "x-gzip")) {
529 *compression = GZIP_METHOD;
530 } else {
531 log_fn(LOG_WARN, "Unrecognized content encoding: '%s'", enc);
532 *compression = 0;
535 SMARTLIST_FOREACH(parsed_headers, char *, s, tor_free(s));
536 smartlist_free(parsed_headers);
538 return 0;
541 /** We are a client, and we've finished reading the server's
542 * response. Parse and it and act appropriately.
544 * Return -1 if an error has occurred, or 0 normally. The caller
545 * will take care of marking the connection for close.
547 static int
548 connection_dir_client_reached_eof(connection_t *conn)
550 char *body;
551 char *headers;
552 size_t body_len=0;
553 int status_code;
554 time_t now, date_header=0;
555 int delta;
556 int compression;
558 switch (fetch_from_buf_http(conn->inbuf,
559 &headers, MAX_HEADERS_SIZE,
560 &body, &body_len, MAX_DIR_SIZE)) {
561 case -1: /* overflow */
562 log_fn(LOG_WARN,"'fetch' response too large (server '%s'). Failing.", conn->address);
563 return -1;
564 case 0:
565 log_fn(LOG_INFO,"'fetch' response not all here, but we're at eof. Closing.");
566 return -1;
567 /* case 1, fall through */
570 if (parse_http_response(headers, &status_code, &date_header,
571 &compression) < 0) {
572 log_fn(LOG_WARN,"Unparseable headers (server '%s'). Closing.", conn->address);
573 tor_free(body); tor_free(headers);
574 return -1;
576 if (date_header > 0) {
577 now = time(NULL);
578 delta = now-date_header;
579 if (abs(delta)>ALLOW_DIRECTORY_TIME_SKEW) {
580 log_fn(LOG_WARN, "Received directory with skewed time (server '%s'): we are %d minutes %s, or the directory is %d minutes %s.",
581 conn->address,
582 abs(delta)/60, delta>0 ? "ahead" : "behind",
583 abs(delta)/60, delta>0 ? "behind" : "ahead");
584 } else {
585 log_fn(LOG_INFO, "Time on received directory is within tolerance; we are %d seconds skewed. (That's okay.)", delta);
589 if (compression != 0) {
590 char *new_body;
591 size_t new_len;
592 if (tor_gzip_uncompress(&new_body, &new_len, body, body_len, compression)) {
593 log_fn(LOG_WARN, "Unable to decompress HTTP body (server '%s').", conn->address);
594 tor_free(body); tor_free(headers);
595 return -1;
597 tor_free(body);
598 body = new_body;
599 body_len = new_len;
602 if (conn->purpose == DIR_PURPOSE_FETCH_DIR) {
603 /* fetch/process the directory to learn about new routers. */
604 log_fn(LOG_INFO,"Received directory (size %d) from server '%s'",
605 (int)body_len, conn->address);
606 if (status_code == 503 || body_len == 0) {
607 log_fn(LOG_INFO,"Empty directory. Ignoring.");
608 tor_free(body); tor_free(headers);
609 return 0;
611 if (status_code != 200) {
612 log_fn(LOG_WARN,"Received http status code %d from server '%s'. Failing.",
613 status_code, conn->address);
614 tor_free(body); tor_free(headers);
615 return -1;
617 if (router_load_routerlist_from_directory(body, NULL, 1, 0) < 0) {
618 log_fn(LOG_WARN,"I failed to parse the directory I fetched from %s:%d. Ignoring.", conn->address, conn->port);
619 } else {
620 log_fn(LOG_INFO,"updated routers.");
622 directory_has_arrived(time(NULL)); /* do things we've been waiting to do */
625 if (conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
626 running_routers_t *rrs;
627 routerlist_t *rl;
628 /* just update our list of running routers, if this list is new info */
629 log_fn(LOG_INFO,"Received running-routers list (size %d)", (int)body_len);
630 if (status_code != 200) {
631 log_fn(LOG_WARN,"Received http status code %d from server '%s'. Failing.",
632 status_code, conn->address);
633 tor_free(body); tor_free(headers);
634 return -1;
636 if (!(rrs = router_parse_runningrouters(body, 1))) {
637 log_fn(LOG_WARN, "Can't parse runningrouters list (server '%s')", conn->address);
638 tor_free(body); tor_free(headers);
639 return -1;
641 router_get_routerlist(&rl);
642 if (rl)
643 routerlist_update_from_runningrouters(rl,rrs);
644 running_routers_free(rrs);
647 if (conn->purpose == DIR_PURPOSE_UPLOAD_DIR) {
648 switch (status_code) {
649 case 200:
650 log_fn(LOG_INFO,"eof (status 200) after uploading server descriptor: finished.");
651 break;
652 case 400:
653 log_fn(LOG_WARN,"http status 400 (bad request) response from dirserver '%s'. Malformed server descriptor?", conn->address);
654 break;
655 case 403:
656 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);
657 break;
658 default:
659 log_fn(LOG_WARN,"http status %d response unrecognized (server '%s').", status_code, conn->address);
660 break;
664 if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC) {
665 log_fn(LOG_INFO,"Received rendezvous descriptor (size %d, status code %d)",
666 (int)body_len, status_code);
667 switch (status_code) {
668 case 200:
669 if (rend_cache_store(body, body_len) < 0) {
670 log_fn(LOG_WARN,"Failed to store rendezvous descriptor.");
671 /* alice's ap_stream will notice when connection_mark_for_close
672 * cleans it up */
673 } else {
674 /* success. notify pending connections about this. */
675 rend_client_desc_fetched(conn->rend_query, 1);
676 conn->purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
678 break;
679 case 404:
680 /* not there. pending connections will be notified when
681 * connection_mark_for_close cleans it up. */
682 break;
683 case 400:
684 log_fn(LOG_WARN,"http status 400 (bad request). Dirserver didn't like our rendezvous query?");
685 break;
689 if (conn->purpose == DIR_PURPOSE_UPLOAD_RENDDESC) {
690 switch (status_code) {
691 case 200:
692 log_fn(LOG_INFO,"eof (status 200) after uploading rendezvous descriptor: finished.");
693 break;
694 case 400:
695 log_fn(LOG_WARN,"http status 400 (bad request) response from dirserver. Malformed rendezvous descriptor?");
696 break;
697 default:
698 log_fn(LOG_WARN,"http status %d response unrecognized.", status_code);
699 break;
702 tor_free(body); tor_free(headers);
703 return 0;
706 int connection_dir_reached_eof(connection_t *conn) {
707 int retval;
708 if (conn->state != DIR_CONN_STATE_CLIENT_READING) {
709 log_fn(LOG_INFO,"conn reached eof, not reading. Closing.");
710 connection_close_immediate(conn); /* it was an error; give up on flushing */
711 connection_mark_for_close(conn);
712 return -1;
715 retval = connection_dir_client_reached_eof(conn);
716 connection_mark_for_close(conn);
717 return retval;
720 /** Read handler for directory connections. (That's connections <em>to</em>
721 * directory servers and connections <em>at</em> directory servers.)
723 int connection_dir_process_inbuf(connection_t *conn) {
725 tor_assert(conn);
726 tor_assert(conn->type == CONN_TYPE_DIR);
728 /* Directory clients write, then read data until they receive EOF;
729 * directory servers read data until they get an HTTP command, then
730 * write their response (when it's finished flushing, they mark for
731 * close).
734 /* If we're on the dirserver side, look for a command. */
735 if (conn->state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
736 if (directory_handle_command(conn) < 0) {
737 connection_mark_for_close(conn);
738 return -1;
740 return 0;
743 /* XXX for READ states, might want to make sure inbuf isn't too big */
745 log_fn(LOG_DEBUG,"Got data, not eof. Leaving on inbuf.");
746 return 0;
749 static char answer200[] = "HTTP/1.0 200 OK\r\n\r\n";
750 static char answer400[] = "HTTP/1.0 400 Bad request\r\n\r\n";
751 static char answer403[] = "HTTP/1.0 403 Unapproved server\r\n\r\n";
752 static char answer404[] = "HTTP/1.0 404 Not found\r\n\r\n";
753 static char answer503[] = "HTTP/1.0 503 Directory unavailable\r\n\r\n";
755 /** Helper function: called when a dirserver gets a complete HTTP GET
756 * request. Look for a request for a directory or for a rendezvous
757 * service descriptor. On finding one, write a response into
758 * conn-\>outbuf. If the request is unrecognized, send a 400.
759 * Always return 0. */
760 static int
761 directory_handle_command_get(connection_t *conn, char *headers,
762 char *body, size_t body_len)
764 size_t dlen;
765 const char *cp;
766 char *url;
767 char tmp[8192];
768 char date[RFC1123_TIME_LEN+1];
770 log_fn(LOG_DEBUG,"Received GET command.");
772 conn->state = DIR_CONN_STATE_SERVER_WRITING;
774 if (parse_http_url(headers, &url) < 0) {
775 connection_write_to_buf(answer400, strlen(answer400), conn);
776 return 0;
778 log_fn(LOG_INFO,"rewritten url as '%s'.", url);
780 if (!strcmp(url,"/tor/") || !strcmp(url,"/tor/dir.z")) { /* directory fetch */
781 int deflated = !strcmp(url,"/tor/dir.z");
782 dlen = dirserv_get_directory(&cp, deflated);
784 tor_free(url);
786 if (dlen == 0) {
787 log_fn(LOG_NOTICE,"My directory is empty. Closing.");
788 connection_write_to_buf(answer503, strlen(answer503), conn);
789 return 0;
792 log_fn(LOG_DEBUG,"Dumping %sdirectory to client.",
793 deflated?"deflated ":"");
794 format_rfc1123_time(date, time(NULL));
795 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",
796 date,
797 (int)dlen,
798 deflated?"deflate":"identity");
799 connection_write_to_buf(tmp, strlen(tmp), conn);
800 connection_write_to_buf(cp, dlen, conn);
801 return 0;
804 if (!strcmp(url,"/tor/running-routers") ||
805 !strcmp(url,"/tor/running-routers.z")) { /* running-routers fetch */
806 int deflated = !strcmp(url,"/tor/dir.z");
807 tor_free(url);
808 dlen = dirserv_get_runningrouters(&cp, deflated);
809 if (!dlen) { /* we failed to create/cache cp */
810 connection_write_to_buf(answer503, strlen(answer503), conn);
811 return 0;
814 format_rfc1123_time(date, time(NULL));
815 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",
816 date,
817 (int)dlen,
818 deflated?"deflate":"identity");
819 connection_write_to_buf(tmp, strlen(tmp), conn);
820 connection_write_to_buf(cp, strlen(cp), conn);
821 return 0;
824 if (!strcmpstart(url,"/tor/rendezvous/")) {
825 /* rendezvous descriptor fetch */
826 const char *descp;
827 size_t desc_len;
829 if (!authdir_mode(get_options())) {
830 /* We don't hand out rend descs. In fact, it could be a security
831 * risk, since rend_cache_lookup_desc() below would provide it
832 * if we're gone to the site recently, and 404 if we haven't.
834 * Reject. */
835 connection_write_to_buf(answer400, strlen(answer400), conn);
836 tor_free(url);
837 return 0;
839 switch (rend_cache_lookup_desc(url+strlen("/tor/rendezvous/"), &descp, &desc_len)) {
840 case 1: /* valid */
841 format_rfc1123_time(date, time(NULL));
842 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",
843 date,
844 (int)desc_len); /* can't include descp here, because it's got nuls */
845 connection_write_to_buf(tmp, strlen(tmp), conn);
846 connection_write_to_buf(descp, desc_len, conn);
847 break;
848 case 0: /* well-formed but not present */
849 connection_write_to_buf(answer404, strlen(answer404), conn);
850 break;
851 case -1: /* not well-formed */
852 connection_write_to_buf(answer400, strlen(answer400), conn);
853 break;
855 tor_free(url);
856 return 0;
859 /* we didn't recognize the url */
860 connection_write_to_buf(answer404, strlen(answer404), conn);
861 tor_free(url);
862 return 0;
865 /** Helper function: called when a dirserver gets a complete HTTP POST
866 * request. Look for an uploaded server descriptor or rendezvous
867 * service descriptor. On finding one, process it and write a
868 * response into conn-\>outbuf. If the request is unrecognized, send a
869 * 400. Always return 0. */
870 static int
871 directory_handle_command_post(connection_t *conn, char *headers,
872 char *body, size_t body_len)
874 const char *cp;
875 char *url;
877 log_fn(LOG_DEBUG,"Received POST command.");
879 conn->state = DIR_CONN_STATE_SERVER_WRITING;
881 if (!authdir_mode(get_options())) {
882 /* we just provide cached directories; we don't want to
883 * receive anything. */
884 connection_write_to_buf(answer400, strlen(answer400), conn);
885 return 0;
888 if (parse_http_url(headers, &url) < 0) {
889 connection_write_to_buf(answer400, strlen(answer400), conn);
890 return 0;
892 log_fn(LOG_INFO,"rewritten url as '%s'.", url);
894 if (!strcmp(url,"/tor/")) { /* server descriptor post */
895 cp = body;
896 switch (dirserv_add_descriptor(&cp)) {
897 case -1:
898 /* malformed descriptor, or something wrong */
899 connection_write_to_buf(answer400, strlen(answer400), conn);
900 break;
901 case 0:
902 /* descriptor was well-formed but server has not been approved */
903 connection_write_to_buf(answer403, strlen(answer403), conn);
904 break;
905 case 1:
906 dirserv_get_directory(&cp, 0); /* rebuild and write to disk */
907 connection_write_to_buf(answer200, strlen(answer200), conn);
908 break;
910 tor_free(url);
911 return 0;
914 if (!strcmpstart(url,"/tor/rendezvous/publish")) {
915 /* rendezvous descriptor post */
916 if (rend_cache_store(body, body_len) < 0)
917 connection_write_to_buf(answer400, strlen(answer400), conn);
918 else
919 connection_write_to_buf(answer200, strlen(answer200), conn);
920 tor_free(url);
921 return 0;
924 /* we didn't recognize the url */
925 connection_write_to_buf(answer404, strlen(answer404), conn);
926 tor_free(url);
927 return 0;
930 /** Called when a dirserver receives data on a directory connection;
931 * looks for an HTTP request. If the request is complete, remove it
932 * from the inbuf, try to process it; otherwise, leave it on the
933 * buffer. Return a 0 on success, or -1 on error.
935 static int directory_handle_command(connection_t *conn) {
936 char *headers=NULL, *body=NULL;
937 size_t body_len=0;
938 int r;
940 tor_assert(conn);
941 tor_assert(conn->type == CONN_TYPE_DIR);
943 switch (fetch_from_buf_http(conn->inbuf,
944 &headers, MAX_HEADERS_SIZE,
945 &body, &body_len, MAX_BODY_SIZE)) {
946 case -1: /* overflow */
947 log_fn(LOG_WARN,"Invalid input. Closing.");
948 return -1;
949 case 0:
950 log_fn(LOG_DEBUG,"command not all here yet.");
951 return 0;
952 /* case 1, fall through */
955 log_fn(LOG_DEBUG,"headers '%s', body '%s'.", headers, body);
957 if (!strncasecmp(headers,"GET",3))
958 r = directory_handle_command_get(conn, headers, body, body_len);
959 else if (!strncasecmp(headers,"POST",4))
960 r = directory_handle_command_post(conn, headers, body, body_len);
961 else {
962 log_fn(LOG_WARN,"Got headers '%s' with unknown command. Closing.", headers);
963 r = -1;
966 tor_free(headers); tor_free(body);
967 return r;
970 /** Write handler for directory connections; called when all data has
971 * been flushed. Close the connection or wait for a response as
972 * appropriate.
974 int connection_dir_finished_flushing(connection_t *conn) {
976 tor_assert(conn);
977 tor_assert(conn->type == CONN_TYPE_DIR);
979 switch (conn->state) {
980 case DIR_CONN_STATE_CLIENT_SENDING:
981 log_fn(LOG_DEBUG,"client finished sending command.");
982 conn->state = DIR_CONN_STATE_CLIENT_READING;
983 connection_stop_writing(conn);
984 return 0;
985 case DIR_CONN_STATE_SERVER_WRITING:
986 log_fn(LOG_INFO,"Finished writing server response. Closing.");
987 connection_mark_for_close(conn);
988 return 0;
989 default:
990 log_fn(LOG_WARN,"Bug: called in unexpected state %d.", conn->state);
991 return -1;
993 return 0;
996 /** Connected handler for directory connections: begin sending data to the
997 * server */
998 int connection_dir_finished_connecting(connection_t *conn)
1000 tor_assert(conn);
1001 tor_assert(conn->type == CONN_TYPE_DIR);
1002 tor_assert(conn->state == DIR_CONN_STATE_CONNECTING);
1004 log_fn(LOG_INFO,"Dir connection to router %s:%u established.",
1005 conn->address,conn->port);
1007 conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
1008 return 0;