directory.c
上传用户:awang829
上传日期:2019-07-14
资源大小:2356k
文件大小:132k
源码类别:

网络

开发平台:

Unix_Linux

  1.   }
  2.   if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_DIR) {
  3.     switch (status_code) {
  4.       case 200: {
  5.           trusted_dir_server_t *ds =
  6.             router_get_trusteddirserver_by_digest(conn->identity_digest);
  7.           char *rejected_hdr = http_get_header(headers,
  8.                                                "X-Descriptor-Not-New: ");
  9.           int rejected = 0;
  10.           if (rejected_hdr) {
  11.             if (!strcmp(rejected_hdr, "Yes")) {
  12.               log_info(LD_GENERAL,
  13.                        "Authority '%s' declined our descriptor (not new)",
  14.                        ds->nickname);
  15.               /* XXXX use this information; be sure to upload next one
  16.                * sooner. -NM */
  17.               /* XXXX021 On further thought, the task above implies that we're
  18.                * basing our regenerate-descriptor time on when we uploaded the
  19.                * last descriptor, not on the published time of the last
  20.                * descriptor.  If those are different, that's a bad thing to
  21.                * do. -NM */
  22.               rejected = 1;
  23.             }
  24.             tor_free(rejected_hdr);
  25.           }
  26.           log_info(LD_GENERAL,"eof (status 200) after uploading server "
  27.                    "descriptor: finished.");
  28.           control_event_server_status(
  29.                       LOG_NOTICE, "ACCEPTED_SERVER_DESCRIPTOR DIRAUTH=%s:%d",
  30.                       conn->_base.address, conn->_base.port);
  31.           ds->has_accepted_serverdesc = 1;
  32.           if (directories_have_accepted_server_descriptor())
  33.             control_event_server_status(LOG_NOTICE, "GOOD_SERVER_DESCRIPTOR");
  34.         }
  35.         break;
  36.       case 400:
  37.         log_warn(LD_GENERAL,"http status 400 (%s) response from "
  38.                  "dirserver '%s:%d'. Please correct.",
  39.                  escaped(reason), conn->_base.address, conn->_base.port);
  40.         control_event_server_status(LOG_WARN,
  41.                       "BAD_SERVER_DESCRIPTOR DIRAUTH=%s:%d REASON="%s"",
  42.                       conn->_base.address, conn->_base.port, escaped(reason));
  43.         break;
  44.       default:
  45.         log_warn(LD_GENERAL,
  46.              "http status %d (%s) reason unexpected while uploading "
  47.              "descriptor to server '%s:%d').",
  48.              status_code, escaped(reason), conn->_base.address,
  49.              conn->_base.port);
  50.         break;
  51.     }
  52.     /* return 0 in all cases, since we don't want to mark any
  53.      * dirservers down just because they don't like us. */
  54.   }
  55.   if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_VOTE) {
  56.     switch (status_code) {
  57.       case 200: {
  58.         log_notice(LD_DIR,"Uploaded a vote to dirserver %s:%d",
  59.                    conn->_base.address, conn->_base.port);
  60.         }
  61.         break;
  62.       case 400:
  63.         log_warn(LD_DIR,"http status 400 (%s) response after uploading "
  64.                  "vote to dirserver '%s:%d'. Please correct.",
  65.                  escaped(reason), conn->_base.address, conn->_base.port);
  66.         break;
  67.       default:
  68.         log_warn(LD_GENERAL,
  69.              "http status %d (%s) reason unexpected while uploading "
  70.              "vote to server '%s:%d').",
  71.              status_code, escaped(reason), conn->_base.address,
  72.              conn->_base.port);
  73.         break;
  74.     }
  75.     /* return 0 in all cases, since we don't want to mark any
  76.      * dirservers down just because they don't like us. */
  77.   }
  78.   if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_SIGNATURES) {
  79.     switch (status_code) {
  80.       case 200: {
  81.         log_notice(LD_DIR,"Uploaded signature(s) to dirserver %s:%d",
  82.                    conn->_base.address, conn->_base.port);
  83.         }
  84.         break;
  85.       case 400:
  86.         log_warn(LD_DIR,"http status 400 (%s) response after uploading "
  87.                  "signatures to dirserver '%s:%d'. Please correct.",
  88.                  escaped(reason), conn->_base.address, conn->_base.port);
  89.         break;
  90.       default:
  91.         log_warn(LD_GENERAL,
  92.              "http status %d (%s) reason unexpected while uploading "
  93.              "signatures to server '%s:%d').",
  94.              status_code, escaped(reason), conn->_base.address,
  95.              conn->_base.port);
  96.         break;
  97.     }
  98.     /* return 0 in all cases, since we don't want to mark any
  99.      * dirservers down just because they don't like us. */
  100.   }
  101.   if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC) {
  102.     tor_assert(conn->rend_data);
  103.     log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d "
  104.              "(%s))",
  105.              (int)body_len, status_code, escaped(reason));
  106.     switch (status_code) {
  107.       case 200:
  108.         if (rend_cache_store(body, body_len, 0) < -1) {
  109.           log_warn(LD_REND,"Failed to parse rendezvous descriptor.");
  110.           /* Any pending rendezvous attempts will notice when
  111.            * connection_about_to_close_connection()
  112.            * cleans this dir conn up. */
  113.           /* We could retry. But since v0 descriptors are going out of
  114.            * style, it isn't worth the hassle. We'll do better in v2. */
  115.         } else {
  116.           /* Success, or at least there's a v2 descriptor already
  117.            * present. Notify pending connections about this. */
  118.           conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
  119.           rend_client_desc_trynow(conn->rend_data->onion_address, -1);
  120.         }
  121.         break;
  122.       case 404:
  123.         /* Not there. Pending connections will be notified when
  124.          * connection_about_to_close_connection() cleans this conn up. */
  125.         break;
  126.       case 400:
  127.         log_warn(LD_REND,
  128.                  "http status 400 (%s). Dirserver didn't like our "
  129.                  "rendezvous query?", escaped(reason));
  130.         break;
  131.       default:
  132.         log_warn(LD_REND,"http status %d (%s) response unexpected while "
  133.                  "fetching hidden service descriptor (server '%s:%d').",
  134.                  status_code, escaped(reason), conn->_base.address,
  135.                  conn->_base.port);
  136.         break;
  137.     }
  138.   }
  139.   if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) {
  140.     tor_assert(conn->rend_data);
  141.     log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d "
  142.              "(%s))",
  143.              (int)body_len, status_code, escaped(reason));
  144.     switch (status_code) {
  145.       case 200:
  146.         switch (rend_cache_store_v2_desc_as_client(body, conn->rend_data)) {
  147.           case -2:
  148.             log_warn(LD_REND,"Fetching v2 rendezvous descriptor failed. "
  149.                      "Retrying at another directory.");
  150.             /* We'll retry when connection_about_to_close_connection()
  151.              * cleans this dir conn up. */
  152.             break;
  153.           case -1:
  154.             /* We already have a v0 descriptor here. Ignoring this one
  155.              * and _not_ performing another request. */
  156.             log_info(LD_REND, "Successfully fetched v2 rendezvous "
  157.                      "descriptor, but we already have a v0 descriptor.");
  158.             conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
  159.             break;
  160.           default:
  161.             /* success. notify pending connections about this. */
  162.             log_info(LD_REND, "Successfully fetched v2 rendezvous "
  163.                      "descriptor.");
  164.             conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
  165.             rend_client_desc_trynow(conn->rend_data->onion_address, -1);
  166.             break;
  167.         }
  168.         break;
  169.       case 404:
  170.         /* Not there. We'll retry when
  171.          * connection_about_to_close_connection() cleans this conn up. */
  172.         log_info(LD_REND,"Fetching v2 rendezvous descriptor failed: "
  173.                          "Retrying at another directory.");
  174.         break;
  175.       case 400:
  176.         log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: "
  177.                  "http status 400 (%s). Dirserver didn't like our "
  178.                  "v2 rendezvous query? Retrying at another directory.",
  179.                  escaped(reason));
  180.         break;
  181.       default:
  182.         log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: "
  183.                  "http status %d (%s) response unexpected while "
  184.                  "fetching v2 hidden service descriptor (server '%s:%d'). "
  185.                  "Retrying at another directory.",
  186.                  status_code, escaped(reason), conn->_base.address,
  187.                  conn->_base.port);
  188.         break;
  189.     }
  190.   }
  191.   if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC ||
  192.       conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) {
  193.     log_info(LD_REND,"Uploaded rendezvous descriptor (status %d "
  194.              "(%s))",
  195.              status_code, escaped(reason));
  196.     switch (status_code) {
  197.       case 200:
  198.         log_info(LD_REND,
  199.                  "Uploading rendezvous descriptor: finished with status "
  200.                  "200 (%s)", escaped(reason));
  201.         break;
  202.       case 400:
  203.         log_warn(LD_REND,"http status 400 (%s) response from dirserver "
  204.                  "'%s:%d'. Malformed rendezvous descriptor?",
  205.                  escaped(reason), conn->_base.address, conn->_base.port);
  206.         break;
  207.       case 503:
  208.         log_info(LD_REND,"http status 503 (%s) response from dirserver "
  209.                  "'%s:%d'. Node is (currently) not acting as v2 hidden "
  210.                  "service directory.",
  211.                  escaped(reason), conn->_base.address, conn->_base.port);
  212.         break;
  213.       default:
  214.         log_warn(LD_REND,"http status %d (%s) response unexpected (server "
  215.                  "'%s:%d').",
  216.                  status_code, escaped(reason), conn->_base.address,
  217.                  conn->_base.port);
  218.         break;
  219.     }
  220.   }
  221.   note_client_request(conn->_base.purpose, was_compressed, orig_len);
  222.   tor_free(body); tor_free(headers); tor_free(reason);
  223.   return 0;
  224. }
  225. /** Called when a directory connection reaches EOF. */
  226. int
  227. connection_dir_reached_eof(dir_connection_t *conn)
  228. {
  229.   int retval;
  230.   if (conn->_base.state != DIR_CONN_STATE_CLIENT_READING) {
  231.     log_info(LD_HTTP,"conn reached eof, not reading. [state=%d] Closing.",
  232.              conn->_base.state);
  233.     connection_close_immediate(TO_CONN(conn)); /* error: give up on flushing */
  234.     connection_mark_for_close(TO_CONN(conn));
  235.     return -1;
  236.   }
  237.   retval = connection_dir_client_reached_eof(conn);
  238.   if (retval == 0) /* success */
  239.     conn->_base.state = DIR_CONN_STATE_CLIENT_FINISHED;
  240.   connection_mark_for_close(TO_CONN(conn));
  241.   return retval;
  242. }
  243. /** If any directory object is arriving, and it's over 10MB large, we're
  244.  * getting DoS'd.  (As of 0.1.2.x, raw directories are about 1MB, and we never
  245.  * ask for more than 96 router descriptors at a time.)
  246.  */
  247. #define MAX_DIRECTORY_OBJECT_SIZE (10*(1<<20))
  248. /** Read handler for directory connections.  (That's connections <em>to</em>
  249.  * directory servers and connections <em>at</em> directory servers.)
  250.  */
  251. int
  252. connection_dir_process_inbuf(dir_connection_t *conn)
  253. {
  254.   tor_assert(conn);
  255.   tor_assert(conn->_base.type == CONN_TYPE_DIR);
  256.   /* Directory clients write, then read data until they receive EOF;
  257.    * directory servers read data until they get an HTTP command, then
  258.    * write their response (when it's finished flushing, they mark for
  259.    * close).
  260.    */
  261.   /* If we're on the dirserver side, look for a command. */
  262.   if (conn->_base.state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
  263.     if (directory_handle_command(conn) < 0) {
  264.       connection_mark_for_close(TO_CONN(conn));
  265.       return -1;
  266.     }
  267.     return 0;
  268.   }
  269.   if (buf_datalen(conn->_base.inbuf) > MAX_DIRECTORY_OBJECT_SIZE) {
  270.     log_warn(LD_HTTP, "Too much data received from directory connection: "
  271.              "denial of service attempt, or you need to upgrade?");
  272.     connection_mark_for_close(TO_CONN(conn));
  273.     return -1;
  274.   }
  275.   if (!conn->_base.inbuf_reached_eof)
  276.     log_debug(LD_HTTP,"Got data, not eof. Leaving on inbuf.");
  277.   return 0;
  278. }
  279. /** Create an http response for the client <b>conn</b> out of
  280.  * <b>status</b> and <b>reason_phrase</b>. Write it to <b>conn</b>.
  281.  */
  282. static void
  283. write_http_status_line(dir_connection_t *conn, int status,
  284.                        const char *reason_phrase)
  285. {
  286.   char buf[256];
  287.   if (tor_snprintf(buf, sizeof(buf), "HTTP/1.0 %d %srnrn",
  288.       status, reason_phrase ? reason_phrase : "OK") < 0) {
  289.     log_warn(LD_BUG,"status line too long.");
  290.     return;
  291.   }
  292.   connection_write_to_buf(buf, strlen(buf), TO_CONN(conn));
  293. }
  294. /** Write the header for an HTTP/1.0 response onto <b>conn</b>->outbuf,
  295.  * with <b>type</b> as the Content-Type.
  296.  *
  297.  * If <b>length</b> is nonnegative, it is the Content-Length.
  298.  * If <b>encoding</b> is provided, it is the Content-Encoding.
  299.  * If <b>cache_lifetime</b> is greater than 0, the content may be cached for
  300.  * up to cache_lifetime seconds.  Otherwise, the content may not be cached. */
  301. static void
  302. write_http_response_header_impl(dir_connection_t *conn, ssize_t length,
  303.                            const char *type, const char *encoding,
  304.                            const char *extra_headers,
  305.                            long cache_lifetime)
  306. {
  307.   char date[RFC1123_TIME_LEN+1];
  308.   char tmp[1024];
  309.   char *cp;
  310.   time_t now = time(NULL);
  311.   tor_assert(conn);
  312.   format_rfc1123_time(date, now);
  313.   cp = tmp;
  314.   tor_snprintf(cp, sizeof(tmp),
  315.                "HTTP/1.0 200 OKrnDate: %srn",
  316.                date);
  317.   cp += strlen(tmp);
  318.   if (type) {
  319.     tor_snprintf(cp, sizeof(tmp)-(cp-tmp), "Content-Type: %srn", type);
  320.     cp += strlen(cp);
  321.   }
  322.   if (!is_local_addr(&conn->_base.addr)) {
  323.     /* Don't report the source address for a nearby/private connection.
  324.      * Otherwise we tend to mis-report in cases where incoming ports are
  325.      * being forwarded to a Tor server running behind the firewall. */
  326.     tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
  327.                  X_ADDRESS_HEADER "%srn", conn->_base.address);
  328.     cp += strlen(cp);
  329.   }
  330.   if (encoding) {
  331.     tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
  332.                  "Content-Encoding: %srn", encoding);
  333.     cp += strlen(cp);
  334.   }
  335.   if (length >= 0) {
  336.     tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
  337.                  "Content-Length: %ldrn", (long)length);
  338.     cp += strlen(cp);
  339.   }
  340.   if (cache_lifetime > 0) {
  341.     char expbuf[RFC1123_TIME_LEN+1];
  342.     format_rfc1123_time(expbuf, now + cache_lifetime);
  343.     /* We could say 'Cache-control: max-age=%d' here if we start doing
  344.      * http/1.1 */
  345.     tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
  346.                  "Expires: %srn", expbuf);
  347.     cp += strlen(cp);
  348.   } else if (cache_lifetime == 0) {
  349.     /* We could say 'Cache-control: no-cache' here if we start doing
  350.      * http/1.1 */
  351.     strlcpy(cp, "Pragma: no-cachern", sizeof(tmp)-(cp-tmp));
  352.     cp += strlen(cp);
  353.   }
  354.   if (extra_headers) {
  355.     strlcpy(cp, extra_headers, sizeof(tmp)-(cp-tmp));
  356.     cp += strlen(cp);
  357.   }
  358.   if (sizeof(tmp)-(cp-tmp) > 3)
  359.     memcpy(cp, "rn", 3);
  360.   else
  361.     tor_assert(0);
  362.   connection_write_to_buf(tmp, strlen(tmp), TO_CONN(conn));
  363. }
  364. /** As write_http_response_header_impl, but sets encoding and content-typed
  365.  * based on whether the response will be <b>compressed</b> or not. */
  366. static void
  367. write_http_response_header(dir_connection_t *conn, ssize_t length,
  368.                            int compressed, long cache_lifetime)
  369. {
  370.   write_http_response_header_impl(conn, length,
  371.                           compressed?"application/octet-stream":"text/plain",
  372.                           compressed?"deflate":"identity",
  373.                              NULL,
  374.                              cache_lifetime);
  375. }
  376. #ifdef INSTRUMENT_DOWNLOADS
  377. typedef struct request_t {
  378.   uint64_t bytes; /**< How many bytes have we transferred? */
  379.   uint64_t count; /**< How many requests have we made? */
  380. } request_t;
  381. /** Map used to keep track of how much data we've up/downloaded in what kind
  382.  * of request.  Maps from request type to pointer to request_t. */
  383. static strmap_t *request_map = NULL;
  384. /** Record that a client request of <b>purpose</b> was made, and that
  385.  * <b>bytes</b> bytes of possibly <b>compressed</b> data were sent/received.
  386.  * Used to keep track of how much we've up/downloaded in what kind of
  387.  * request. */
  388. static void
  389. note_client_request(int purpose, int compressed, size_t bytes)
  390. {
  391.   char *key;
  392.   const char *kind = NULL;
  393.   switch (purpose) {
  394.     case DIR_PURPOSE_FETCH_V2_NETWORKSTATUS: kind = "dl/status"; break;
  395.     case DIR_PURPOSE_FETCH_CONSENSUS:     kind = "dl/consensus"; break;
  396.     case DIR_PURPOSE_FETCH_CERTIFICATE:   kind = "dl/cert"; break;
  397.     case DIR_PURPOSE_FETCH_STATUS_VOTE:   kind = "dl/vote"; break;
  398.     case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: kind = "dl/detached_sig";
  399.          break;
  400.     case DIR_PURPOSE_FETCH_SERVERDESC:    kind = "dl/server"; break;
  401.     case DIR_PURPOSE_FETCH_EXTRAINFO:     kind = "dl/extra"; break;
  402.     case DIR_PURPOSE_UPLOAD_DIR:          kind = "dl/ul-dir"; break;
  403.     case DIR_PURPOSE_UPLOAD_VOTE:         kind = "dl/ul-vote"; break;
  404.     case DIR_PURPOSE_UPLOAD_SIGNATURES:   kind = "dl/ul-sig"; break;
  405.     case DIR_PURPOSE_FETCH_RENDDESC:      kind = "dl/rend"; break;
  406.     case DIR_PURPOSE_FETCH_RENDDESC_V2:   kind = "dl/rend2"; break;
  407.     case DIR_PURPOSE_UPLOAD_RENDDESC:     kind = "dl/ul-rend"; break;
  408.     case DIR_PURPOSE_UPLOAD_RENDDESC_V2:  kind = "dl/ul-rend2"; break;
  409.   }
  410.   if (kind) {
  411.     key = tor_malloc(256);
  412.     tor_snprintf(key, 256, "%s%s", kind, compressed?".z":"");
  413.   } else {
  414.     key = tor_malloc(256);
  415.     tor_snprintf(key, 256, "unknown purpose (%d)%s",
  416.                  purpose, compressed?".z":"");
  417.   }
  418.   note_request(key, bytes);
  419.   tor_free(key);
  420. }
  421. /** Helper: initialize the request map to instrument downloads. */
  422. static void
  423. ensure_request_map_initialized(void)
  424. {
  425.   if (!request_map)
  426.     request_map = strmap_new();
  427. }
  428. /** Called when we just transmitted or received <b>bytes</b> worth of data
  429.  * because of a request of type <b>key</b> (an arbitrary identifier): adds
  430.  * <b>bytes</b> to the total associated with key. */
  431. void
  432. note_request(const char *key, size_t bytes)
  433. {
  434.   request_t *r;
  435.   ensure_request_map_initialized();
  436.   r = strmap_get(request_map, key);
  437.   if (!r) {
  438.     r = tor_malloc_zero(sizeof(request_t));
  439.     strmap_set(request_map, key, r);
  440.   }
  441.   r->bytes += bytes;
  442.   r->count++;
  443. }
  444. /** Return a newly allocated string holding a summary of bytes used per
  445.  * request type. */
  446. char *
  447. directory_dump_request_log(void)
  448. {
  449.   smartlist_t *lines;
  450.   char tmp[256];
  451.   char *result;
  452.   strmap_iter_t *iter;
  453.   ensure_request_map_initialized();
  454.   lines = smartlist_create();
  455.   for (iter = strmap_iter_init(request_map);
  456.        !strmap_iter_done(iter);
  457.        iter = strmap_iter_next(request_map, iter)) {
  458.     const char *key;
  459.     void *val;
  460.     request_t *r;
  461.     strmap_iter_get(iter, &key, &val);
  462.     r = val;
  463.     tor_snprintf(tmp, sizeof(tmp), "%s  "U64_FORMAT"  "U64_FORMAT"n",
  464.                  key, U64_PRINTF_ARG(r->bytes), U64_PRINTF_ARG(r->count));
  465.     smartlist_add(lines, tor_strdup(tmp));
  466.   }
  467.   smartlist_sort_strings(lines);
  468.   result = smartlist_join_strings(lines, "", 0, NULL);
  469.   SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
  470.   smartlist_free(lines);
  471.   return result;
  472. }
  473. #else
  474. static void
  475. note_client_request(int purpose, int compressed, size_t bytes)
  476. {
  477.   (void)purpose;
  478.   (void)compressed;
  479.   (void)bytes;
  480. }
  481. void
  482. note_request(const char *key, size_t bytes)
  483. {
  484.   (void)key;
  485.   (void)bytes;
  486. }
  487. char *
  488. directory_dump_request_log(void)
  489. {
  490.   return tor_strdup("Not supported.");
  491. }
  492. #endif
  493. /** Decide whether a client would accept the consensus we have
  494.  *
  495.  * Clients can say they only want a consensus if it's signed by more
  496.  * than half the authorities in a list.  They pass this list in
  497.  * the url as "...consensus/<b>fpr</b>+<b>fpr</b>+<b>fpr</b>".
  498.  *
  499.  * <b>fpr</b> may be an abbreviated fingerprint, i.e. only a left substring
  500.  * of the full authority identity digest. (Only strings of even length,
  501.  * i.e. encodings of full bytes, are handled correctly.  In the case
  502.  * of an odd number of hex digits the last one is silently ignored.)
  503.  *
  504.  * Returns 1 if more than half of the requested authorities signed the
  505.  * consensus, 0 otherwise.
  506.  */
  507. int
  508. client_likes_consensus(networkstatus_t *v, const char *want_url)
  509. {
  510.   smartlist_t *want_authorities = smartlist_create();
  511.   int need_at_least;
  512.   int have = 0;
  513.   dir_split_resource_into_fingerprints(want_url, want_authorities, NULL, 0, 0);
  514.   need_at_least = smartlist_len(want_authorities)/2+1;
  515.   SMARTLIST_FOREACH(want_authorities, const char *, d, {
  516.     char want_digest[DIGEST_LEN];
  517.     size_t want_len = strlen(d)/2;
  518.     if (want_len > DIGEST_LEN)
  519.       want_len = DIGEST_LEN;
  520.     if (base16_decode(want_digest, DIGEST_LEN, d, want_len*2) < 0) {
  521.       log_warn(LD_DIR,"Failed to decode requested authority digest %s.", d);
  522.       continue;
  523.     };
  524.     SMARTLIST_FOREACH(v->voters, networkstatus_voter_info_t *, vi, {
  525.       if (vi->signature &&
  526.           !memcmp(vi->identity_digest, want_digest, want_len)) {
  527.         have++;
  528.         break;
  529.       };
  530.     });
  531.     /* early exit, if we already have enough */
  532.     if (have >= need_at_least)
  533.       break;
  534.   });
  535.   SMARTLIST_FOREACH(want_authorities, char *, d, tor_free(d));
  536.   smartlist_free(want_authorities);
  537.   return (have >= need_at_least);
  538. }
  539. /** Helper function: called when a dirserver gets a complete HTTP GET
  540.  * request.  Look for a request for a directory or for a rendezvous
  541.  * service descriptor.  On finding one, write a response into
  542.  * conn->outbuf.  If the request is unrecognized, send a 400.
  543.  * Always return 0. */
  544. static int
  545. directory_handle_command_get(dir_connection_t *conn, const char *headers,
  546.                              const char *body, size_t body_len)
  547. {
  548.   size_t dlen;
  549.   char *url, *url_mem, *header;
  550.   or_options_t *options = get_options();
  551.   time_t if_modified_since = 0;
  552.   int compressed;
  553.   size_t url_len;
  554.   /* We ignore the body of a GET request. */
  555.   (void)body;
  556.   (void)body_len;
  557.   log_debug(LD_DIRSERV,"Received GET command.");
  558.   conn->_base.state = DIR_CONN_STATE_SERVER_WRITING;
  559.   if (parse_http_url(headers, &url) < 0) {
  560.     write_http_status_line(conn, 400, "Bad request");
  561.     return 0;
  562.   }
  563.   if ((header = http_get_header(headers, "If-Modified-Since: "))) {
  564.     struct tm tm;
  565.     if (parse_http_time(header, &tm) == 0) {
  566.       if_modified_since = tor_timegm(&tm);
  567.     }
  568.     /* The correct behavior on a malformed If-Modified-Since header is to
  569.      * act as if no If-Modified-Since header had been given. */
  570.     tor_free(header);
  571.   }
  572.   log_debug(LD_DIRSERV,"rewritten url as '%s'.", url);
  573.   url_mem = url;
  574.   url_len = strlen(url);
  575.   compressed = url_len > 2 && !strcmp(url+url_len-2, ".z");
  576.   if (compressed) {
  577.     url[url_len-2] = '';
  578.     url_len -= 2;
  579.   }
  580.   if (!strcmp(url,"/tor/")) {
  581.     const char *frontpage = get_dirportfrontpage();
  582.     if (frontpage) {
  583.       dlen = strlen(frontpage);
  584.       /* Let's return a disclaimer page (users shouldn't use V1 anymore,
  585.          and caches don't fetch '/', so this is safe). */
  586.       /* [We don't check for write_bucket_low here, since we want to serve
  587.        *  this page no matter what.] */
  588.       note_request(url, dlen);
  589.       write_http_response_header_impl(conn, dlen, "text/html", "identity",
  590.                                       NULL, DIRPORTFRONTPAGE_CACHE_LIFETIME);
  591.       connection_write_to_buf(frontpage, dlen, TO_CONN(conn));
  592.       goto done;
  593.     }
  594.     /* if no disclaimer file, fall through and continue */
  595.   }
  596.   if (!strcmp(url,"/tor/") || !strcmp(url,"/tor/dir")) { /* v1 dir fetch */
  597.     cached_dir_t *d = dirserv_get_directory();
  598.     if (!d) {
  599.       log_info(LD_DIRSERV,"Client asked for the mirrored directory, but we "
  600.                "don't have a good one yet. Sending 503 Dir not available.");
  601.       write_http_status_line(conn, 503, "Directory unavailable");
  602.       goto done;
  603.     }
  604.     if (d->published < if_modified_since) {
  605.       write_http_status_line(conn, 304, "Not modified");
  606.       goto done;
  607.     }
  608.     dlen = compressed ? d->dir_z_len : d->dir_len;
  609.     if (global_write_bucket_low(TO_CONN(conn), dlen, 1)) {
  610.       log_debug(LD_DIRSERV,
  611.                "Client asked for the mirrored directory, but we've been "
  612.                "writing too many bytes lately. Sending 503 Dir busy.");
  613.       write_http_status_line(conn, 503, "Directory busy, try again later");
  614.       goto done;
  615.     }
  616.     note_request(url, dlen);
  617.     log_debug(LD_DIRSERV,"Dumping %sdirectory to client.",
  618.               compressed?"compressed ":"");
  619.     write_http_response_header(conn, dlen, compressed,
  620.                           FULL_DIR_CACHE_LIFETIME);
  621.     conn->cached_dir = d;
  622.     conn->cached_dir_offset = 0;
  623.     if (!compressed)
  624.       conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD);
  625.     ++d->refcnt;
  626.     /* Prime the connection with some data. */
  627.     conn->dir_spool_src = DIR_SPOOL_CACHED_DIR;
  628.     connection_dirserv_flushed_some(conn);
  629.     goto done;
  630.   }
  631.   if (!strcmp(url,"/tor/running-routers")) { /* running-routers fetch */
  632.     cached_dir_t *d = dirserv_get_runningrouters();
  633.     if (!d) {
  634.       write_http_status_line(conn, 503, "Directory unavailable");
  635.       goto done;
  636.     }
  637.     if (d->published < if_modified_since) {
  638.       write_http_status_line(conn, 304, "Not modified");
  639.       goto done;
  640.     }
  641.     dlen = compressed ? d->dir_z_len : d->dir_len;
  642.     if (global_write_bucket_low(TO_CONN(conn), dlen, 1)) {
  643.       log_info(LD_DIRSERV,
  644.                "Client asked for running-routers, but we've been "
  645.                "writing too many bytes lately. Sending 503 Dir busy.");
  646.       write_http_status_line(conn, 503, "Directory busy, try again later");
  647.       goto done;
  648.     }
  649.     note_request(url, dlen);
  650.     write_http_response_header(conn, dlen, compressed,
  651.                  RUNNINGROUTERS_CACHE_LIFETIME);
  652.     connection_write_to_buf(compressed ? d->dir_z : d->dir, dlen,
  653.                             TO_CONN(conn));
  654.     goto done;
  655.   }
  656.   if (!strcmpstart(url,"/tor/status/")
  657.       || !strcmpstart(url, "/tor/status-vote/current/consensus")) {
  658.     /* v2 or v3 network status fetch. */
  659.     smartlist_t *dir_fps = smartlist_create();
  660.     int is_v3 = !strcmpstart(url, "/tor/status-vote");
  661.     const char *request_type = NULL;
  662.     const char *key = url + strlen("/tor/status/");
  663.     long lifetime = NETWORKSTATUS_CACHE_LIFETIME;
  664.     if (!is_v3) {
  665.       dirserv_get_networkstatus_v2_fingerprints(dir_fps, key);
  666.       if (!strcmpstart(key, "fp/"))
  667.         request_type = compressed?"/tor/status/fp.z":"/tor/status/fp";
  668.       else if (!strcmpstart(key, "authority"))
  669.         request_type = compressed?"/tor/status/authority.z":
  670.           "/tor/status/authority";
  671.       else if (!strcmpstart(key, "all"))
  672.         request_type = compressed?"/tor/status/all.z":"/tor/status/all";
  673.       else
  674.         request_type = "/tor/status/?";
  675.     } else {
  676.       networkstatus_t *v = networkstatus_get_latest_consensus();
  677.       time_t now = time(NULL);
  678.       #define CONSENSUS_URL_PREFIX "/tor/status-vote/current/consensus/"
  679.       if (v &&
  680.           !strcmpstart(url, CONSENSUS_URL_PREFIX) &&
  681.           !client_likes_consensus(v, url + strlen(CONSENSUS_URL_PREFIX))) {
  682.         write_http_status_line(conn, 404, "Consensus not signed by sufficient "
  683.                                           "number of requested authorities");
  684.         smartlist_free(dir_fps);
  685.         goto done;
  686.       }
  687.       smartlist_add(dir_fps, tor_memdup(""
  688.                                         "", 20));
  689.       request_type = compressed?"v3.z":"v3";
  690.       lifetime = (v && v->fresh_until > now) ? v->fresh_until - now : 0;
  691.     }
  692.     if (!smartlist_len(dir_fps)) { /* we failed to create/cache cp */
  693.       write_http_status_line(conn, 503, "Network status object unavailable");
  694.       smartlist_free(dir_fps);
  695.       goto done;
  696.     }
  697.     if (!dirserv_remove_old_statuses(dir_fps, if_modified_since)) {
  698.       write_http_status_line(conn, 404, "Not found");
  699.       SMARTLIST_FOREACH(dir_fps, char *, cp, tor_free(cp));
  700.       smartlist_free(dir_fps);
  701.       goto done;
  702.     } else if (!smartlist_len(dir_fps)) {
  703.       write_http_status_line(conn, 304, "Not modified");
  704.       SMARTLIST_FOREACH(dir_fps, char *, cp, tor_free(cp));
  705.       smartlist_free(dir_fps);
  706.       goto done;
  707.     }
  708.     dlen = dirserv_estimate_data_size(dir_fps, 0, compressed);
  709.     if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) {
  710.       log_debug(LD_DIRSERV,
  711.                "Client asked for network status lists, but we've been "
  712.                "writing too many bytes lately. Sending 503 Dir busy.");
  713.       write_http_status_line(conn, 503, "Directory busy, try again later");
  714.       SMARTLIST_FOREACH(dir_fps, char *, fp, tor_free(fp));
  715.       smartlist_free(dir_fps);
  716.       goto done;
  717.     }
  718. #ifdef ENABLE_GEOIP_STATS
  719.     {
  720.       geoip_client_action_t act =
  721.         is_v3 ? GEOIP_CLIENT_NETWORKSTATUS : GEOIP_CLIENT_NETWORKSTATUS_V2;
  722.       struct in_addr in;
  723.       if (tor_inet_aton((TO_CONN(conn))->address, &in))
  724.         geoip_note_client_seen(act, ntohl(in.s_addr), time(NULL));
  725.     }
  726. #endif
  727.     // note_request(request_type,dlen);
  728.     (void) request_type;
  729.     write_http_response_header(conn, -1, compressed,
  730.                                smartlist_len(dir_fps) == 1 ? lifetime : 0);
  731.     conn->fingerprint_stack = dir_fps;
  732.     if (! compressed)
  733.       conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD);
  734.     /* Prime the connection with some data. */
  735.     conn->dir_spool_src = DIR_SPOOL_NETWORKSTATUS;
  736.     connection_dirserv_flushed_some(conn);
  737.     goto done;
  738.   }
  739.   if (!strcmpstart(url,"/tor/status-vote/current/") ||
  740.       !strcmpstart(url,"/tor/status-vote/next/")) {
  741.     /* XXXX If-modified-since is only implemented for the current
  742.      * consensus: that's probably fine, since it's the only vote document
  743.      * people fetch much. */
  744.     int current;
  745.     ssize_t body_len = 0;
  746.     ssize_t estimated_len = 0;
  747.     smartlist_t *items = smartlist_create();
  748.     smartlist_t *dir_items = smartlist_create();
  749.     int lifetime = 60; /* XXXX022 should actually use vote intervals. */
  750.     url += strlen("/tor/status-vote/");
  751.     current = !strcmpstart(url, "current/");
  752.     url = strchr(url, '/');
  753.     tor_assert(url);
  754.     ++url;
  755.     if (!strcmp(url, "consensus")) {
  756.       const char *item;
  757.       tor_assert(!current); /* we handle current consensus specially above,
  758.                              * since it wants to be spooled. */
  759.       if ((item = dirvote_get_pending_consensus()))
  760.         smartlist_add(items, (char*)item);
  761.     } else if (!current && !strcmp(url, "consensus-signatures")) {
  762.       /* XXXX the spec says that we should implement
  763.        * current/consensus-signatures too.  It doesn't seem to be needed,
  764.        * though. */
  765.       const char *item;
  766.       if ((item=dirvote_get_pending_detached_signatures()))
  767.         smartlist_add(items, (char*)item);
  768.     } else if (!strcmp(url, "authority")) {
  769.       const cached_dir_t *d;
  770.       int flags = DGV_BY_ID |
  771.         (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING);
  772.       if ((d=dirvote_get_vote(NULL, flags)))
  773.         smartlist_add(dir_items, (cached_dir_t*)d);
  774.     } else {
  775.       const cached_dir_t *d;
  776.       smartlist_t *fps = smartlist_create();
  777.       int flags;
  778.       if (!strcmpstart(url, "d/")) {
  779.         url += 2;
  780.         flags = DGV_INCLUDE_PENDING | DGV_INCLUDE_PREVIOUS;
  781.       } else {
  782.         flags = DGV_BY_ID |
  783.           (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING);
  784.       }
  785.       dir_split_resource_into_fingerprints(url, fps, NULL, 1, 1);
  786.       SMARTLIST_FOREACH(fps, char *, fp, {
  787.           if ((d = dirvote_get_vote(fp, flags)))
  788.             smartlist_add(dir_items, (cached_dir_t*)d);
  789.           tor_free(fp);
  790.         });
  791.       smartlist_free(fps);
  792.     }
  793.     if (!smartlist_len(dir_items) && !smartlist_len(items)) {
  794.       write_http_status_line(conn, 404, "Not found");
  795.       goto vote_done;
  796.     }
  797.     SMARTLIST_FOREACH(dir_items, cached_dir_t *, d,
  798.                       body_len += compressed ? d->dir_z_len : d->dir_len);
  799.     estimated_len += body_len;
  800.     SMARTLIST_FOREACH(items, const char *, item, {
  801.         size_t ln = strlen(item);
  802.         if (compressed) {
  803.           estimated_len += ln/2;
  804.         } else {
  805.           body_len += ln; estimated_len += ln;
  806.         }
  807.       });
  808.     if (global_write_bucket_low(TO_CONN(conn), estimated_len, 2)) {
  809.       write_http_status_line(conn, 503, "Directory busy, try again later.");
  810.       goto vote_done;
  811.     }
  812.     write_http_response_header(conn, body_len ? body_len : -1, compressed,
  813.                  lifetime);
  814.     if (smartlist_len(items)) {
  815.       if (compressed) {
  816.         conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD);
  817.         SMARTLIST_FOREACH(items, const char *, c,
  818.                  connection_write_to_buf_zlib(c, strlen(c), conn, 0));
  819.         connection_write_to_buf_zlib("", 0, conn, 1);
  820.       } else {
  821.         SMARTLIST_FOREACH(items, const char *, c,
  822.                          connection_write_to_buf(c, strlen(c), TO_CONN(conn)));
  823.       }
  824.     } else {
  825.       SMARTLIST_FOREACH(dir_items, cached_dir_t *, d,
  826.           connection_write_to_buf(compressed ? d->dir_z : d->dir,
  827.                                   compressed ? d->dir_z_len : d->dir_len,
  828.                                   TO_CONN(conn)));
  829.     }
  830.   vote_done:
  831.     smartlist_free(items);
  832.     smartlist_free(dir_items);
  833.     goto done;
  834.   }
  835.   if (!strcmpstart(url,"/tor/server/") ||
  836.       (!options->BridgeAuthoritativeDir &&
  837.        !options->BridgeRelay && !strcmpstart(url,"/tor/extra/"))) {
  838.     int res;
  839.     const char *msg;
  840.     const char *request_type = NULL;
  841.     int cache_lifetime = 0;
  842.     int is_extra = !strcmpstart(url,"/tor/extra/");
  843.     url += is_extra ? strlen("/tor/extra/") : strlen("/tor/server/");
  844.     conn->fingerprint_stack = smartlist_create();
  845.     res = dirserv_get_routerdesc_fingerprints(conn->fingerprint_stack, url,
  846.                                           &msg,
  847.                                           !connection_dir_is_encrypted(conn),
  848.                                           is_extra);
  849.     if (!strcmpstart(url, "fp/")) {
  850.       request_type = compressed?"/tor/server/fp.z":"/tor/server/fp";
  851.       if (smartlist_len(conn->fingerprint_stack) == 1)
  852.         cache_lifetime = ROUTERDESC_CACHE_LIFETIME;
  853.     } else if (!strcmpstart(url, "authority")) {
  854.       request_type = compressed?"/tor/server/authority.z":
  855.         "/tor/server/authority";
  856.       cache_lifetime = ROUTERDESC_CACHE_LIFETIME;
  857.     } else if (!strcmpstart(url, "all")) {
  858.       request_type = compressed?"/tor/server/all.z":"/tor/server/all";
  859.       cache_lifetime = FULL_DIR_CACHE_LIFETIME;
  860.     } else if (!strcmpstart(url, "d/")) {
  861.       request_type = compressed?"/tor/server/d.z":"/tor/server/d";
  862.       if (smartlist_len(conn->fingerprint_stack) == 1)
  863.         cache_lifetime = ROUTERDESC_BY_DIGEST_CACHE_LIFETIME;
  864.     } else {
  865.       request_type = "/tor/server/?";
  866.     }
  867.     (void) request_type; /* usable for note_request. */
  868.     if (!strcmpstart(url, "d/"))
  869.       conn->dir_spool_src =
  870.         is_extra ? DIR_SPOOL_EXTRA_BY_DIGEST : DIR_SPOOL_SERVER_BY_DIGEST;
  871.     else
  872.       conn->dir_spool_src =
  873.         is_extra ? DIR_SPOOL_EXTRA_BY_FP : DIR_SPOOL_SERVER_BY_FP;
  874.     if (!dirserv_have_any_serverdesc(conn->fingerprint_stack,
  875.                                      conn->dir_spool_src)) {
  876.       res = -1;
  877.       msg = "Not found";
  878.     }
  879.     if (res < 0)
  880.       write_http_status_line(conn, 404, msg);
  881.     else {
  882.       dlen = dirserv_estimate_data_size(conn->fingerprint_stack,
  883.                                         1, compressed);
  884.       if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) {
  885.         log_info(LD_DIRSERV,
  886.                  "Client asked for server descriptors, but we've been "
  887.                  "writing too many bytes lately. Sending 503 Dir busy.");
  888.         write_http_status_line(conn, 503, "Directory busy, try again later");
  889.         conn->dir_spool_src = DIR_SPOOL_NONE;
  890.         goto done;
  891.       }
  892.       write_http_response_header(conn, -1, compressed, cache_lifetime);
  893.       if (compressed)
  894.         conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD);
  895.       /* Prime the connection with some data. */
  896.       connection_dirserv_flushed_some(conn);
  897.     }
  898.     goto done;
  899.   }
  900.   if (!strcmpstart(url,"/tor/keys/")) {
  901.     smartlist_t *certs = smartlist_create();
  902.     ssize_t len = -1;
  903.     if (!strcmp(url, "/tor/keys/all")) {
  904.       authority_cert_get_all(certs);
  905.     } else if (!strcmp(url, "/tor/keys/authority")) {
  906.       authority_cert_t *cert = get_my_v3_authority_cert();
  907.       if (cert)
  908.         smartlist_add(certs, cert);
  909.     } else if (!strcmpstart(url, "/tor/keys/fp/")) {
  910.       smartlist_t *fps = smartlist_create();
  911.       dir_split_resource_into_fingerprints(url+strlen("/tor/keys/fp/"),
  912.                                            fps, NULL, 1, 1);
  913.       SMARTLIST_FOREACH(fps, char *, d, {
  914.           authority_cert_t *c = authority_cert_get_newest_by_id(d);
  915.           if (c) smartlist_add(certs, c);
  916.           tor_free(d);
  917.       });
  918.       smartlist_free(fps);
  919.     } else if (!strcmpstart(url, "/tor/keys/sk/")) {
  920.       smartlist_t *fps = smartlist_create();
  921.       dir_split_resource_into_fingerprints(url+strlen("/tor/keys/sk/"),
  922.                                            fps, NULL, 1, 1);
  923.       SMARTLIST_FOREACH(fps, char *, d, {
  924.           authority_cert_t *c = authority_cert_get_by_sk_digest(d);
  925.           if (c) smartlist_add(certs, c);
  926.           tor_free(d);
  927.       });
  928.       smartlist_free(fps);
  929.     } else if (!strcmpstart(url, "/tor/keys/fp-sk/")) {
  930.       smartlist_t *fp_sks = smartlist_create();
  931.       dir_split_resource_into_fingerprint_pairs(url+strlen("/tor/keys/fp-sk/"),
  932.                                                 fp_sks);
  933.       SMARTLIST_FOREACH(fp_sks, fp_pair_t *, pair, {
  934.           authority_cert_t *c = authority_cert_get_by_digests(pair->first,
  935.                                                               pair->second);
  936.           if (c) smartlist_add(certs, c);
  937.           tor_free(pair);
  938.       });
  939.       smartlist_free(fp_sks);
  940.     } else {
  941.       write_http_status_line(conn, 400, "Bad request");
  942.       goto keys_done;
  943.     }
  944.     if (!smartlist_len(certs)) {
  945.       write_http_status_line(conn, 404, "Not found");
  946.       goto keys_done;
  947.     }
  948.     SMARTLIST_FOREACH(certs, authority_cert_t *, c,
  949.       if (c->cache_info.published_on < if_modified_since)
  950.         SMARTLIST_DEL_CURRENT(certs, c));
  951.     if (!smartlist_len(certs)) {
  952.       write_http_status_line(conn, 304, "Not modified");
  953.       goto keys_done;
  954.     }
  955.     len = 0;
  956.     SMARTLIST_FOREACH(certs, authority_cert_t *, c,
  957.                       len += c->cache_info.signed_descriptor_len);
  958.     if (global_write_bucket_low(TO_CONN(conn), compressed?len/2:len, 2)) {
  959.       write_http_status_line(conn, 503, "Directory busy, try again later.");
  960.       goto keys_done;
  961.     }
  962.     write_http_response_header(conn, compressed?-1:len, compressed, 60*60);
  963.     if (compressed) {
  964.       conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD);
  965.       SMARTLIST_FOREACH(certs, authority_cert_t *, c,
  966.             connection_write_to_buf_zlib(c->cache_info.signed_descriptor_body,
  967.                                          c->cache_info.signed_descriptor_len,
  968.                                          conn, 0));
  969.       connection_write_to_buf_zlib("", 0, conn, 1);
  970.     } else {
  971.       SMARTLIST_FOREACH(certs, authority_cert_t *, c,
  972.             connection_write_to_buf(c->cache_info.signed_descriptor_body,
  973.                                     c->cache_info.signed_descriptor_len,
  974.                                     TO_CONN(conn)));
  975.     }
  976.   keys_done:
  977.     smartlist_free(certs);
  978.     goto done;
  979.   }
  980.   if (options->HidServDirectoryV2 &&
  981.        !strcmpstart(url,"/tor/rendezvous2/")) {
  982.     /* Handle v2 rendezvous descriptor fetch request. */
  983.     const char *descp;
  984.     const char *query = url + strlen("/tor/rendezvous2/");
  985.     if (strlen(query) == REND_DESC_ID_V2_LEN_BASE32) {
  986.       log_info(LD_REND, "Got a v2 rendezvous descriptor request for ID '%s'",
  987.                safe_str(query));
  988.       switch (rend_cache_lookup_v2_desc_as_dir(query, &descp)) {
  989.         case 1: /* valid */
  990.           write_http_response_header(conn, strlen(descp), 0, 0);
  991.           connection_write_to_buf(descp, strlen(descp), TO_CONN(conn));
  992.           break;
  993.         case 0: /* well-formed but not present */
  994.           write_http_status_line(conn, 404, "Not found");
  995.           break;
  996.         case -1: /* not well-formed */
  997.           write_http_status_line(conn, 400, "Bad request");
  998.           break;
  999.       }
  1000.     } else { /* not well-formed */
  1001.       write_http_status_line(conn, 400, "Bad request");
  1002.     }
  1003.     goto done;
  1004.   }
  1005.   if (options->HSAuthoritativeDir && !strcmpstart(url,"/tor/rendezvous/")) {
  1006.     /* rendezvous descriptor fetch */
  1007.     const char *descp;
  1008.     size_t desc_len;
  1009.     const char *query = url+strlen("/tor/rendezvous/");
  1010.     log_info(LD_REND, "Handling rendezvous descriptor get");
  1011.     switch (rend_cache_lookup_desc(query, 0, &descp, &desc_len)) {
  1012.       case 1: /* valid */
  1013.         write_http_response_header_impl(conn, desc_len,
  1014.                                         "application/octet-stream",
  1015.                                         NULL, NULL, 0);
  1016.         note_request("/tor/rendezvous?/", desc_len);
  1017.         /* need to send descp separately, because it may include NULs */
  1018.         connection_write_to_buf(descp, desc_len, TO_CONN(conn));
  1019.         /* report successful fetch to statistic */
  1020.         if (options->HSAuthorityRecordStats) {
  1021.           hs_usage_note_fetch_total(query, time(NULL));
  1022.           hs_usage_note_fetch_successful(query, time(NULL));
  1023.         }
  1024.         break;
  1025.       case 0: /* well-formed but not present */
  1026.         write_http_status_line(conn, 404, "Not found");
  1027.         /* report (unsuccessful) fetch to statistic */
  1028.         if (options->HSAuthorityRecordStats) {
  1029.           hs_usage_note_fetch_total(query, time(NULL));
  1030.         }
  1031.         break;
  1032.       case -1: /* not well-formed */
  1033.         write_http_status_line(conn, 400, "Bad request");
  1034.         break;
  1035.     }
  1036.     goto done;
  1037.   }
  1038.   if (options->BridgeAuthoritativeDir &&
  1039.       options->BridgePassword &&
  1040.       connection_dir_is_encrypted(conn) &&
  1041.       !strcmp(url,"/tor/networkstatus-bridges")) {
  1042.     char *status;
  1043.     char *secret = alloc_http_authenticator(options->BridgePassword);
  1044.     header = http_get_header(headers, "Authorization: Basic ");
  1045.     /* now make sure the password is there and right */
  1046.     if (!header || strcmp(header, secret)) {
  1047.       write_http_status_line(conn, 404, "Not found");
  1048.       tor_free(secret);
  1049.       tor_free(header);
  1050.       goto done;
  1051.     }
  1052.     tor_free(secret);
  1053.     tor_free(header);
  1054.     /* all happy now. send an answer. */
  1055.     status = networkstatus_getinfo_by_purpose("bridge", time(NULL));
  1056.     dlen = strlen(status);
  1057.     write_http_response_header(conn, dlen, 0, 0);
  1058.     connection_write_to_buf(status, dlen, TO_CONN(conn));
  1059.     tor_free(status);
  1060.     goto done;
  1061.   }
  1062.   if (!strcmpstart(url,"/tor/bytes.txt")) {
  1063.     char *bytes = directory_dump_request_log();
  1064.     size_t len = strlen(bytes);
  1065.     write_http_response_header(conn, len, 0, 0);
  1066.     connection_write_to_buf(bytes, len, TO_CONN(conn));
  1067.     tor_free(bytes);
  1068.     goto done;
  1069.   }
  1070.   if (!strcmp(url,"/tor/robots.txt")) { /* /robots.txt will have been
  1071.                                            rewritten to /tor/robots.txt */
  1072.     char robots[] = "User-agent: *rnDisallow: /rn";
  1073.     size_t len = strlen(robots);
  1074.     write_http_response_header(conn, len, 0, ROBOTS_CACHE_LIFETIME);
  1075.     connection_write_to_buf(robots, len, TO_CONN(conn));
  1076.     goto done;
  1077.   }
  1078.   if (!strcmp(url,"/tor/dbg-stability.txt")) {
  1079.     const char *stability;
  1080.     size_t len;
  1081.     if (! authdir_mode_tests_reachability(options) ||
  1082.         ! (stability = rep_hist_get_router_stability_doc(time(NULL)))) {
  1083.       write_http_status_line(conn, 404, "Not found.");
  1084.       goto done;
  1085.     }
  1086.     len = strlen(stability);
  1087.     write_http_response_header(conn, len, 0, 0);
  1088.     connection_write_to_buf(stability, len, TO_CONN(conn));
  1089.     goto done;
  1090.   }
  1091. #if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
  1092. #define ADD_MALLINFO_LINE(x) do {                               
  1093.     tor_snprintf(tmp, sizeof(tmp), "%s %dn", #x, mi.x);        
  1094.     smartlist_add(lines, tor_strdup(tmp));                      
  1095.   }while(0);
  1096.   if (!strcmp(url,"/tor/mallinfo.txt") &&
  1097.       (tor_addr_eq_ipv4h(&conn->_base.addr, 0x7f000001ul))) {
  1098.     char *result;
  1099.     size_t len;
  1100.     struct mallinfo mi;
  1101.     smartlist_t *lines;
  1102.     char tmp[256];
  1103.     memset(&mi, 0, sizeof(mi));
  1104.     mi = mallinfo();
  1105.     lines = smartlist_create();
  1106.     ADD_MALLINFO_LINE(arena)
  1107.     ADD_MALLINFO_LINE(ordblks)
  1108.     ADD_MALLINFO_LINE(smblks)
  1109.     ADD_MALLINFO_LINE(hblks)
  1110.     ADD_MALLINFO_LINE(hblkhd)
  1111.     ADD_MALLINFO_LINE(usmblks)
  1112.     ADD_MALLINFO_LINE(fsmblks)
  1113.     ADD_MALLINFO_LINE(uordblks)
  1114.     ADD_MALLINFO_LINE(fordblks)
  1115.     ADD_MALLINFO_LINE(keepcost)
  1116.     result = smartlist_join_strings(lines, "", 0, NULL);
  1117.     SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
  1118.     smartlist_free(lines);
  1119.     len = strlen(result);
  1120.     write_http_response_header(conn, len, 0, 0);
  1121.     connection_write_to_buf(result, len, TO_CONN(conn));
  1122.     tor_free(result);
  1123.     goto done;
  1124.   }
  1125. #endif
  1126.   /* we didn't recognize the url */
  1127.   write_http_status_line(conn, 404, "Not found");
  1128.  done:
  1129.   tor_free(url_mem);
  1130.   return 0;
  1131. }
  1132. /** Helper function: called when a dirserver gets a complete HTTP POST
  1133.  * request.  Look for an uploaded server descriptor or rendezvous
  1134.  * service descriptor.  On finding one, process it and write a
  1135.  * response into conn->outbuf.  If the request is unrecognized, send a
  1136.  * 400.  Always return 0. */
  1137. static int
  1138. directory_handle_command_post(dir_connection_t *conn, const char *headers,
  1139.                               const char *body, size_t body_len)
  1140. {
  1141.   char *url = NULL;
  1142.   or_options_t *options = get_options();
  1143.   log_debug(LD_DIRSERV,"Received POST command.");
  1144.   conn->_base.state = DIR_CONN_STATE_SERVER_WRITING;
  1145.   if (parse_http_url(headers, &url) < 0) {
  1146.     write_http_status_line(conn, 400, "Bad request");
  1147.     return 0;
  1148.   }
  1149.   log_debug(LD_DIRSERV,"rewritten url as '%s'.", url);
  1150.   /* Handle v2 rendezvous service publish request. */
  1151.   if (options->HidServDirectoryV2 &&
  1152.       !strcmpstart(url,"/tor/rendezvous2/publish")) {
  1153.     switch (rend_cache_store_v2_desc_as_dir(body)) {
  1154.       case -2:
  1155.         log_info(LD_REND, "Rejected v2 rend descriptor (length %d) from %s "
  1156.                  "since we're not currently a hidden service directory.",
  1157.                  (int)body_len, conn->_base.address);
  1158.         write_http_status_line(conn, 503, "Currently not acting as v2 "
  1159.                                "hidden service directory");
  1160.         break;
  1161.       case -1:
  1162.         log_warn(LD_REND, "Rejected v2 rend descriptor (length %d) from %s.",
  1163.                  (int)body_len, conn->_base.address);
  1164.         write_http_status_line(conn, 400,
  1165.                                "Invalid v2 service descriptor rejected");
  1166.         break;
  1167.       default:
  1168.         write_http_status_line(conn, 200, "Service descriptor (v2) stored");
  1169.         log_info(LD_REND, "Handled v2 rendezvous descriptor post: accepted");
  1170.     }
  1171.     goto done;
  1172.   }
  1173.   if (!authdir_mode(options)) {
  1174.     /* we just provide cached directories; we don't want to
  1175.      * receive anything. */
  1176.     write_http_status_line(conn, 400, "Nonauthoritative directory does not "
  1177.                            "accept posted server descriptors");
  1178.     goto done;
  1179.   }
  1180.   if (authdir_mode_handles_descs(options, -1) &&
  1181.       !strcmp(url,"/tor/")) { /* server descriptor post */
  1182.     const char *msg = "[None]";
  1183.     uint8_t purpose = authdir_mode_bridge(options) ?
  1184.                       ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL;
  1185.     was_router_added_t r = dirserv_add_multiple_descriptors(body, purpose,
  1186.                                              conn->_base.address, &msg);
  1187.     tor_assert(msg);
  1188.     if (WRA_WAS_ADDED(r))
  1189.       dirserv_get_directory(); /* rebuild and write to disk */
  1190.     if (r == ROUTER_ADDED_NOTIFY_GENERATOR) {
  1191.       /* Accepted with a message. */
  1192.       log_info(LD_DIRSERV,
  1193.                "Problematic router descriptor or extra-info from %s "
  1194.                "("%s").",
  1195.                conn->_base.address, msg);
  1196.       write_http_status_line(conn, 400, msg);
  1197.     } else if (r == ROUTER_ADDED_SUCCESSFULLY) {
  1198.       write_http_status_line(conn, 200, msg);
  1199.     } else if (WRA_WAS_OUTDATED(r)) {
  1200.       write_http_response_header_impl(conn, -1, NULL, NULL,
  1201.                                       "X-Descriptor-Not-New: Yesrn", -1);
  1202.     } else {
  1203.       log_info(LD_DIRSERV,
  1204.                "Rejected router descriptor or extra-info from %s "
  1205.                "("%s").",
  1206.                conn->_base.address, msg);
  1207.       write_http_status_line(conn, 400, msg);
  1208.     }
  1209.     goto done;
  1210.   }
  1211.   if (options->HSAuthoritativeDir &&
  1212.       !strcmpstart(url,"/tor/rendezvous/publish")) {
  1213.     /* rendezvous descriptor post */
  1214.     log_info(LD_REND, "Handling rendezvous descriptor post.");
  1215.     if (rend_cache_store(body, body_len, 1) < 0) {
  1216.       log_fn(LOG_PROTOCOL_WARN, LD_DIRSERV,
  1217.              "Rejected rend descriptor (length %d) from %s.",
  1218.              (int)body_len, conn->_base.address);
  1219.       write_http_status_line(conn, 400,
  1220.                              "Invalid v0 service descriptor rejected");
  1221.     } else {
  1222.       write_http_status_line(conn, 200, "Service descriptor (v0) stored");
  1223.     }
  1224.     goto done;
  1225.   }
  1226.   if (authdir_mode_v3(options) &&
  1227.       !strcmp(url,"/tor/post/vote")) { /* v3 networkstatus vote */
  1228.     const char *msg = "OK";
  1229.     int status;
  1230.     if (dirvote_add_vote(body, &msg, &status)) {
  1231.       write_http_status_line(conn, status, "Vote stored");
  1232.     } else {
  1233.       tor_assert(msg);
  1234.       write_http_status_line(conn, status, msg);
  1235.     }
  1236.     goto done;
  1237.   }
  1238.   if (authdir_mode_v3(options) &&
  1239.       !strcmp(url,"/tor/post/consensus-signature")) { /* sigs on consensus. */
  1240.     const char *msg = NULL;
  1241.     if (dirvote_add_signatures(body, conn->_base.address, &msg)>=0) {
  1242.       write_http_status_line(conn, 200, msg?msg:"Signatures stored");
  1243.     } else {
  1244.       log_warn(LD_DIR, "Unable to store signatures posted by %s: %s",
  1245.                conn->_base.address, msg?msg:"???");
  1246.       write_http_status_line(conn, 400, msg?msg:"Unable to store signatures");
  1247.     }
  1248.     goto done;
  1249.   }
  1250.   /* we didn't recognize the url */
  1251.   write_http_status_line(conn, 404, "Not found");
  1252.  done:
  1253.   tor_free(url);
  1254.   return 0;
  1255. }
  1256. /** Called when a dirserver receives data on a directory connection;
  1257.  * looks for an HTTP request.  If the request is complete, remove it
  1258.  * from the inbuf, try to process it; otherwise, leave it on the
  1259.  * buffer.  Return a 0 on success, or -1 on error.
  1260.  */
  1261. static int
  1262. directory_handle_command(dir_connection_t *conn)
  1263. {
  1264.   char *headers=NULL, *body=NULL;
  1265.   size_t body_len=0;
  1266.   int r;
  1267.   tor_assert(conn);
  1268.   tor_assert(conn->_base.type == CONN_TYPE_DIR);
  1269.   switch (fetch_from_buf_http(conn->_base.inbuf,
  1270.                               &headers, MAX_HEADERS_SIZE,
  1271.                               &body, &body_len, MAX_DIR_UL_SIZE, 0)) {
  1272.     case -1: /* overflow */
  1273.       log_warn(LD_DIRSERV,
  1274.                "Invalid input from address '%s'. Closing.",
  1275.                conn->_base.address);
  1276.       return -1;
  1277.     case 0:
  1278.       log_debug(LD_DIRSERV,"command not all here yet.");
  1279.       return 0;
  1280.     /* case 1, fall through */
  1281.   }
  1282.   http_set_address_origin(headers, TO_CONN(conn));
  1283.   //log_debug(LD_DIRSERV,"headers %s, body %s.", headers, body);
  1284.   if (!strncasecmp(headers,"GET",3))
  1285.     r = directory_handle_command_get(conn, headers, body, body_len);
  1286.   else if (!strncasecmp(headers,"POST",4))
  1287.     r = directory_handle_command_post(conn, headers, body, body_len);
  1288.   else {
  1289.     log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
  1290.            "Got headers %s with unknown command. Closing.",
  1291.            escaped(headers));
  1292.     r = -1;
  1293.   }
  1294.   tor_free(headers); tor_free(body);
  1295.   return r;
  1296. }
  1297. /** Write handler for directory connections; called when all data has
  1298.  * been flushed.  Close the connection or wait for a response as
  1299.  * appropriate.
  1300.  */
  1301. int
  1302. connection_dir_finished_flushing(dir_connection_t *conn)
  1303. {
  1304.   tor_assert(conn);
  1305.   tor_assert(conn->_base.type == CONN_TYPE_DIR);
  1306.   switch (conn->_base.state) {
  1307.     case DIR_CONN_STATE_CLIENT_SENDING:
  1308.       log_debug(LD_DIR,"client finished sending command.");
  1309.       conn->_base.state = DIR_CONN_STATE_CLIENT_READING;
  1310.       connection_stop_writing(TO_CONN(conn));
  1311.       return 0;
  1312.     case DIR_CONN_STATE_SERVER_WRITING:
  1313.       log_debug(LD_DIRSERV,"Finished writing server response. Closing.");
  1314.       connection_mark_for_close(TO_CONN(conn));
  1315.       return 0;
  1316.     default:
  1317.       log_warn(LD_BUG,"called in unexpected state %d.",
  1318.                conn->_base.state);
  1319.       tor_fragile_assert();
  1320.       return -1;
  1321.   }
  1322.   return 0;
  1323. }
  1324. /** Connected handler for directory connections: begin sending data to the
  1325.  * server */
  1326. int
  1327. connection_dir_finished_connecting(dir_connection_t *conn)
  1328. {
  1329.   tor_assert(conn);
  1330.   tor_assert(conn->_base.type == CONN_TYPE_DIR);
  1331.   tor_assert(conn->_base.state == DIR_CONN_STATE_CONNECTING);
  1332.   log_debug(LD_HTTP,"Dir connection to router %s:%u established.",
  1333.             conn->_base.address,conn->_base.port);
  1334.   conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
  1335.   return 0;
  1336. }
  1337. /** Called when one or more networkstatus fetches have failed (with uppercase
  1338.  * fingerprints listed in <b>failed</b>).  Mark those fingerprints as having
  1339.  * failed once, unless they failed with status code 503. */
  1340. static void
  1341. dir_networkstatus_download_failed(smartlist_t *failed, int status_code)
  1342. {
  1343.   if (status_code == 503)
  1344.     return;
  1345.   SMARTLIST_FOREACH(failed, const char *, fp,
  1346.   {
  1347.     char digest[DIGEST_LEN];
  1348.     trusted_dir_server_t *dir;
  1349.     if (base16_decode(digest, DIGEST_LEN, fp, strlen(fp))<0) {
  1350.       log_warn(LD_BUG, "Called with bad fingerprint in list: %s",
  1351.                escaped(fp));
  1352.       continue;
  1353.     }
  1354.     dir = router_get_trusteddirserver_by_digest(digest);
  1355.     if (dir)
  1356.       download_status_failed(&dir->v2_ns_dl_status, status_code);
  1357.   });
  1358. }
  1359. /** Schedule for when servers should download things in general. */
  1360. static const int server_dl_schedule[] = {
  1361.   0, 0, 0, 60, 60, 60*2, 60*5, 60*15, INT_MAX
  1362. };
  1363. /** Schedule for when clients should download things in general. */
  1364. static const int client_dl_schedule[] = {
  1365.   0, 0, 60, 60*5, 60*10, INT_MAX
  1366. };
  1367. /** Schedule for when servers should download consensuses. */
  1368. static const int server_consensus_dl_schedule[] = {
  1369.   0, 0, 60, 60*5, 60*10, 60*30, 60*30, 60*30, 60*30, 60*30, 60*60, 60*60*2
  1370. };
  1371. /** Schedule for when clients should download consensuses. */
  1372. static const int client_consensus_dl_schedule[] = {
  1373.   0, 0, 60, 60*5, 60*10, 60*30, 60*60, 60*60, 60*60, 60*60*3, 60*60*6, 60*60*12
  1374. };
  1375. /** Schedule for when clients should download bridge descriptors. */
  1376. static const int bridge_dl_schedule[] = {
  1377.   60*60, 15*60, 15*60, 60*60
  1378. };
  1379. /** Decide which download schedule we want to use, and then return a
  1380.  * pointer to it along with a pointer to its length. Helper function for
  1381.  * download_status_increment_failure() and download_status_reset(). */
  1382. static void
  1383. find_dl_schedule_and_len(download_status_t *dls, int server,
  1384.                          const int **schedule, size_t *schedule_len)
  1385. {
  1386.   switch (dls->schedule) {
  1387.     case DL_SCHED_GENERIC:
  1388.       if (server) {
  1389.         *schedule = server_dl_schedule;
  1390.         *schedule_len = sizeof(server_dl_schedule)/sizeof(int);
  1391.       } else {
  1392.         *schedule = client_dl_schedule;
  1393.         *schedule_len = sizeof(client_dl_schedule)/sizeof(int);
  1394.       }
  1395.       break;
  1396.     case DL_SCHED_CONSENSUS:
  1397.       if (server) {
  1398.         *schedule = server_consensus_dl_schedule;
  1399.         *schedule_len = sizeof(server_consensus_dl_schedule)/sizeof(int);
  1400.       } else {
  1401.         *schedule = client_consensus_dl_schedule;
  1402.         *schedule_len = sizeof(client_consensus_dl_schedule)/sizeof(int);
  1403.       }
  1404.       break;
  1405.     case DL_SCHED_BRIDGE:
  1406.       *schedule = bridge_dl_schedule;
  1407.       *schedule_len = sizeof(bridge_dl_schedule)/sizeof(int);
  1408.       break;
  1409.     default:
  1410.       tor_assert(0);
  1411.   }
  1412. }
  1413. /** Called when an attempt to download <b>dls</b> has failed with HTTP status
  1414.  * <b>status_code</b>.  Increment the failure count (if the code indicates a
  1415.  * real failure) and set <b>dls</b>->next_attempt_at to an appropriate time
  1416.  * in the future. */
  1417. time_t
  1418. download_status_increment_failure(download_status_t *dls, int status_code,
  1419.                                   const char *item, int server, time_t now)
  1420. {
  1421.   const int *schedule;
  1422.   size_t schedule_len;
  1423.   int increment;
  1424.   tor_assert(dls);
  1425.   if (status_code != 503 || server) {
  1426.     if (dls->n_download_failures < IMPOSSIBLE_TO_DOWNLOAD-1)
  1427.       ++dls->n_download_failures;
  1428.   }
  1429.   find_dl_schedule_and_len(dls, server, &schedule, &schedule_len);
  1430.   if (dls->n_download_failures < schedule_len)
  1431.     increment = schedule[dls->n_download_failures];
  1432.   else if (dls->n_download_failures == IMPOSSIBLE_TO_DOWNLOAD)
  1433.     increment = INT_MAX;
  1434.   else
  1435.     increment = schedule[schedule_len-1];
  1436.   if (increment < INT_MAX)
  1437.     dls->next_attempt_at = now+increment;
  1438.   else
  1439.     dls->next_attempt_at = TIME_MAX;
  1440.   if (item) {
  1441.     if (increment == 0)
  1442.       log_debug(LD_DIR, "%s failed %d time(s); I'll try again immediately.",
  1443.                 item, (int)dls->n_download_failures);
  1444.     else if (dls->next_attempt_at < TIME_MAX)
  1445.       log_debug(LD_DIR, "%s failed %d time(s); I'll try again in %d seconds.",
  1446.                 item, (int)dls->n_download_failures,
  1447.                 (int)(dls->next_attempt_at-now));
  1448.     else
  1449.       log_debug(LD_DIR, "%s failed %d time(s); Giving up for a while.",
  1450.                 item, (int)dls->n_download_failures);
  1451.   }
  1452.   return dls->next_attempt_at;
  1453. }
  1454. /** Reset <b>dls</b> so that it will be considered downloadable
  1455.  * immediately, and/or to show that we don't need it anymore.
  1456.  *
  1457.  * (We find the zeroth element of the download schedule, and set
  1458.  * next_attempt_at to be the appropriate offset from 'now'. In most
  1459.  * cases this means setting it to 'now', so the item will be immediately
  1460.  * downloadable; in the case of bridge descriptors, the zeroth element
  1461.  * is an hour from now.) */
  1462. void
  1463. download_status_reset(download_status_t *dls)
  1464. {
  1465.   const int *schedule;
  1466.   size_t schedule_len;
  1467.   find_dl_schedule_and_len(dls, get_options()->DirPort,
  1468.                            &schedule, &schedule_len);
  1469.   dls->n_download_failures = 0;
  1470.   dls->next_attempt_at = time(NULL) + schedule[0];
  1471. }
  1472. /** Called when one or more routerdesc (or extrainfo, if <b>was_extrainfo</b>)
  1473.  * fetches have failed (with uppercase fingerprints listed in <b>failed</b>,
  1474.  * either as descriptor digests or as identity digests based on
  1475.  * <b>was_descriptor_digests</b>).
  1476.  */
  1477. static void
  1478. dir_routerdesc_download_failed(smartlist_t *failed, int status_code,
  1479.                                int router_purpose,
  1480.                                int was_extrainfo, int was_descriptor_digests)
  1481. {
  1482.   char digest[DIGEST_LEN];
  1483.   time_t now = time(NULL);
  1484.   int server = directory_fetches_from_authorities(get_options());
  1485.   if (!was_descriptor_digests) {
  1486.     if (router_purpose == ROUTER_PURPOSE_BRIDGE) {
  1487.       tor_assert(!was_extrainfo); /* not supported yet */
  1488.       SMARTLIST_FOREACH(failed, const char *, cp,
  1489.       {
  1490.         if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp))<0) {
  1491.           log_warn(LD_BUG, "Malformed fingerprint in list: %s",
  1492.                    escaped(cp));
  1493.           continue;
  1494.         }
  1495.         retry_bridge_descriptor_fetch_directly(digest);
  1496.       });
  1497.     }
  1498.     return; /* FFFF should implement for other-than-router-purpose someday */
  1499.   }
  1500.   SMARTLIST_FOREACH(failed, const char *, cp,
  1501.   {
  1502.     download_status_t *dls = NULL;
  1503.     if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp)) < 0) {
  1504.       log_warn(LD_BUG, "Malformed fingerprint in list: %s", escaped(cp));
  1505.       continue;
  1506.     }
  1507.     if (was_extrainfo) {
  1508.       signed_descriptor_t *sd =
  1509.         router_get_by_extrainfo_digest(digest);
  1510.       if (sd)
  1511.         dls = &sd->ei_dl_status;
  1512.     } else {
  1513.       dls = router_get_dl_status_by_descriptor_digest(digest);
  1514.     }
  1515.     if (!dls || dls->n_download_failures >= MAX_ROUTERDESC_DOWNLOAD_FAILURES)
  1516.       continue;
  1517.     download_status_increment_failure(dls, status_code, cp, server, now);
  1518.   });
  1519.   /* No need to relaunch descriptor downloads here: we already do it
  1520.    * every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */
  1521. }
  1522. /** Helper.  Compare two fp_pair_t objects, and return -1, 0, or 1 as
  1523.  * appropriate. */
  1524. static int
  1525. _compare_pairs(const void **a, const void **b)
  1526. {
  1527.   const fp_pair_t *fp1 = *a, *fp2 = *b;
  1528.   int r;
  1529.   if ((r = memcmp(fp1->first, fp2->first, DIGEST_LEN)))
  1530.     return r;
  1531.   else
  1532.     return memcmp(fp1->second, fp2->second, DIGEST_LEN);
  1533. }
  1534. /** Divide a string <b>res</b> of the form FP1-FP2+FP3-FP4...[.z], where each
  1535.  * FP is a hex-encoded fingerprint, into a sequence of distinct sorted
  1536.  * fp_pair_t. Skip malformed pairs. On success, return 0 and add those
  1537.  * fp_pair_t into <b>pairs_out</b>.  On failure, return -1. */
  1538. int
  1539. dir_split_resource_into_fingerprint_pairs(const char *res,
  1540.                                           smartlist_t *pairs_out)
  1541. {
  1542.   smartlist_t *pairs_tmp = smartlist_create();
  1543.   smartlist_t *pairs_result = smartlist_create();
  1544.   smartlist_split_string(pairs_tmp, res, "+", 0, 0);
  1545.   if (smartlist_len(pairs_tmp)) {
  1546.     char *last = smartlist_get(pairs_tmp,smartlist_len(pairs_tmp)-1);
  1547.     size_t last_len = strlen(last);
  1548.     if (last_len > 2 && !strcmp(last+last_len-2, ".z")) {
  1549.       last[last_len-2] = '';
  1550.     }
  1551.   }
  1552.   SMARTLIST_FOREACH_BEGIN(pairs_tmp, char *, cp) {
  1553.     if (strlen(cp) != HEX_DIGEST_LEN*2+1) {
  1554.       log_info(LD_DIR,
  1555.              "Skipping digest pair %s with non-standard length.", escaped(cp));
  1556.     } else if (cp[HEX_DIGEST_LEN] != '-') {
  1557.       log_info(LD_DIR,
  1558.              "Skipping digest pair %s with missing dash.", escaped(cp));
  1559.     } else {
  1560.       fp_pair_t pair;
  1561.       if (base16_decode(pair.first, DIGEST_LEN, cp, HEX_DIGEST_LEN)<0 ||
  1562.           base16_decode(pair.second,
  1563.                         DIGEST_LEN, cp+HEX_DIGEST_LEN+1, HEX_DIGEST_LEN)<0) {
  1564.         log_info(LD_DIR, "Skipping non-decodable digest pair %s", escaped(cp));
  1565.       } else {
  1566.         smartlist_add(pairs_result, tor_memdup(&pair, sizeof(pair)));
  1567.       }
  1568.     }
  1569.     tor_free(cp);
  1570.   } SMARTLIST_FOREACH_END(cp);
  1571.   smartlist_free(pairs_tmp);
  1572.   /* Uniq-and-sort */
  1573.   smartlist_sort(pairs_result, _compare_pairs);
  1574.   smartlist_uniq(pairs_result, _compare_pairs, _tor_free);
  1575.   smartlist_add_all(pairs_out, pairs_result);
  1576.   smartlist_free(pairs_result);
  1577.   return 0;
  1578. }
  1579. /** Given a directory <b>resource</b> request, containing zero
  1580.  * or more strings separated by plus signs, followed optionally by ".z", store
  1581.  * the strings, in order, into <b>fp_out</b>.  If <b>compressed_out</b> is
  1582.  * non-NULL, set it to 1 if the resource ends in ".z", else set it to 0.  If
  1583.  * decode_hex is true, then delete all elements that aren't hex digests, and
  1584.  * decode the rest.  If sort_uniq is true, then sort the list and remove
  1585.  * all duplicates.
  1586.  */
  1587. int
  1588. dir_split_resource_into_fingerprints(const char *resource,
  1589.                                      smartlist_t *fp_out, int *compressed_out,
  1590.                                      int decode_hex, int sort_uniq)
  1591. {
  1592.   smartlist_t *fp_tmp = smartlist_create();
  1593.   tor_assert(fp_out);
  1594.   smartlist_split_string(fp_tmp, resource, "+", 0, 0);
  1595.   if (compressed_out)
  1596.     *compressed_out = 0;
  1597.   if (smartlist_len(fp_tmp)) {
  1598.     char *last = smartlist_get(fp_tmp,smartlist_len(fp_tmp)-1);
  1599.     size_t last_len = strlen(last);
  1600.     if (last_len > 2 && !strcmp(last+last_len-2, ".z")) {
  1601.       last[last_len-2] = '';
  1602.       if (compressed_out)
  1603.         *compressed_out = 1;
  1604.     }
  1605.   }
  1606.   if (decode_hex) {
  1607.     int i;
  1608.     char *cp, *d = NULL;
  1609.     for (i = 0; i < smartlist_len(fp_tmp); ++i) {
  1610.       cp = smartlist_get(fp_tmp, i);
  1611.       if (strlen(cp) != HEX_DIGEST_LEN) {
  1612.         log_info(LD_DIR,
  1613.                  "Skipping digest %s with non-standard length.", escaped(cp));
  1614.         smartlist_del_keeporder(fp_tmp, i--);
  1615.         goto again;
  1616.       }
  1617.       d = tor_malloc_zero(DIGEST_LEN);
  1618.       if (base16_decode(d, DIGEST_LEN, cp, HEX_DIGEST_LEN)<0) {
  1619.         log_info(LD_DIR, "Skipping non-decodable digest %s", escaped(cp));
  1620.         smartlist_del_keeporder(fp_tmp, i--);
  1621.         goto again;
  1622.       }
  1623.       smartlist_set(fp_tmp, i, d);
  1624.       d = NULL;
  1625.     again:
  1626.       tor_free(cp);
  1627.       tor_free(d);
  1628.     }
  1629.   }
  1630.   if (sort_uniq) {
  1631.     smartlist_t *fp_tmp2 = smartlist_create();
  1632.     int i;
  1633.     if (decode_hex)
  1634.       smartlist_sort_digests(fp_tmp);
  1635.     else
  1636.       smartlist_sort_strings(fp_tmp);
  1637.     if (smartlist_len(fp_tmp))
  1638.       smartlist_add(fp_tmp2, smartlist_get(fp_tmp, 0));
  1639.     for (i = 1; i < smartlist_len(fp_tmp); ++i) {
  1640.       char *cp = smartlist_get(fp_tmp, i);
  1641.       char *last = smartlist_get(fp_tmp2, smartlist_len(fp_tmp2)-1);
  1642.       if ((decode_hex && memcmp(cp, last, DIGEST_LEN))
  1643.           || (!decode_hex && strcasecmp(cp, last)))
  1644.         smartlist_add(fp_tmp2, cp);
  1645.       else
  1646.         tor_free(cp);
  1647.     }
  1648.     smartlist_free(fp_tmp);
  1649.     fp_tmp = fp_tmp2;
  1650.   }
  1651.   smartlist_add_all(fp_out, fp_tmp);
  1652.   smartlist_free(fp_tmp);
  1653.   return 0;
  1654. }