Back to index

tor  0.2.3.19-rc
Defines | Functions
directory.h File Reference

Header file for directory.c. More...

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Defines

#define DSR_HEX   (1<<0)
#define DSR_BASE64   (1<<1)
#define DSR_DIGEST256   (1<<2)
#define DSR_SORT_UNIQ   (1<<3)
#define download_status_failed(dls, sc)
 Increment the failure count of the download_status_t dls, with the optional status code sc.

Functions

int directories_have_accepted_server_descriptor (void)
 Return true iff any trusted directory authority has accepted our server descriptor.
void directory_post_to_dirservers (uint8_t dir_purpose, uint8_t router_purpose, dirinfo_type_t type, const char *payload, size_t payload_len, size_t extrainfo_len)
 Start a connection to every suitable directory authority, using connection purpose dir_purpose and uploading payload (of length payload_len).
void directory_get_from_dirserver (uint8_t dir_purpose, uint8_t router_purpose, const char *resource, int pds_flags)
 Start a connection to a random running directory server, using connection purpose dir_purpose, intending to fetch descriptors of purpose router_purpose, and requesting resource.
void directory_get_from_all_authorities (uint8_t dir_purpose, uint8_t router_purpose, const char *resource)
 As directory_get_from_dirserver, but initiates a request to every directory authority other than ourself.
void directory_initiate_command_routerstatus (const routerstatus_t *status, uint8_t dir_purpose, uint8_t router_purpose, int anonymized_connection, const char *resource, const char *payload, size_t payload_len, time_t if_modified_since)
 Launch a new connection to the directory server status to upload or download a server or rendezvous descriptor.
void directory_initiate_command_routerstatus_rend (const routerstatus_t *status, uint8_t dir_purpose, uint8_t router_purpose, int anonymized_connection, const char *resource, const char *payload, size_t payload_len, time_t if_modified_since, const rend_data_t *rend_query)
 Same as directory_initiate_command_routerstatus(), but accepts rendezvous data to fetch a hidden service descriptor.
int parse_http_response (const char *headers, int *code, time_t *date, compress_method_t *compression, char **response)
 Parse an HTTP response string headers of the form.
int connection_dir_is_encrypted (dir_connection_t *conn)
 Return true iff anything we say on conn is being encrypted before we send it to the client/server.
int connection_dir_reached_eof (dir_connection_t *conn)
 Called when a directory connection reaches EOF.
int connection_dir_process_inbuf (dir_connection_t *conn)
 Read handler for directory connections.
int connection_dir_finished_flushing (dir_connection_t *conn)
 Write handler for directory connections; called when all data has been flushed.
int connection_dir_finished_connecting (dir_connection_t *conn)
 Connected handler for directory connections: begin sending data to the server.
void connection_dir_about_to_close (dir_connection_t *dir_conn)
 Called when we're about to finally unlink and free a directory connection: perform necessary accounting and cleanup.
void directory_initiate_command (const char *address, const tor_addr_t *addr, uint16_t or_port, uint16_t dir_port, int supports_conditional_consensus, int supports_begindir, const char *digest, uint8_t dir_purpose, uint8_t router_purpose, int anonymized_connection, const char *resource, const char *payload, size_t payload_len, time_t if_modified_since)
 Helper for directory_initiate_command_routerstatus: send the command to a server whose address is address, whose IP is addr, whose directory port is dir_port, whose tor version supports_begindir, and whose identity key digest is digest.
int dir_split_resource_into_fingerprints (const char *resource, smartlist_t *fp_out, int *compressed_out, int flags)
 Given a directory resource request, containing zero or more strings separated by plus signs, followed optionally by ".z", store the strings, in order, into fp_out.
int dir_split_resource_into_fingerprint_pairs (const char *res, smartlist_t *pairs_out)
 Divide a string res of the form FP1-FP2+FP3-FP4...[.z], where each FP is a hex-encoded fingerprint, into a sequence of distinct sorted fp_pair_t.
char * directory_dump_request_log (void)
void note_request (const char *key, size_t bytes)
int router_supports_extrainfo (const char *identity_digest, int is_authority)
 Return true iff identity_digest is the digest of a router we believe to support extrainfo downloads.
time_t download_status_increment_failure (download_status_t *dls, int status_code, const char *item, int server, time_t now)
 Called when an attempt to download dls has failed with HTTP status status_code.
void download_status_reset (download_status_t *dls)
 Reset dls so that it will be considered downloadable immediately, and/or to show that we don't need it anymore.
static int download_status_is_ready (download_status_t *dls, time_t now, int max_failures)
 Return true iff, as of now, the resource tracked by dls is ready to get its download reattempted.
static void download_status_mark_impossible (download_status_t *dl)
 Mark dl as never downloadable.
int download_status_get_n_failures (const download_status_t *dls)
 Return the number of failures on dls since the last success (if any).

Detailed Description

Header file for directory.c.

Definition in file directory.h.


Define Documentation

#define download_status_failed (   dls,
  sc 
)
Value:
download_status_increment_failure((dls), (sc), NULL,                  \
                                    get_options()->DirPort!=NULL, time(NULL))

Increment the failure count of the download_status_t dls, with the optional status code sc.

Definition at line 81 of file directory.h.

#define DSR_BASE64   (1<<1)

Definition at line 63 of file directory.h.

#define DSR_DIGEST256   (1<<2)

Definition at line 64 of file directory.h.

#define DSR_HEX   (1<<0)

Definition at line 62 of file directory.h.

#define DSR_SORT_UNIQ   (1<<3)

Definition at line 65 of file directory.h.


Function Documentation

Called when we're about to finally unlink and free a directory connection: perform necessary accounting and cleanup.

Definition at line 2320 of file directory.c.

{
  connection_t *conn = TO_CONN(dir_conn);

  if (conn->state < DIR_CONN_STATE_CLIENT_FINISHED) {
    /* It's a directory connection and connecting or fetching
     * failed: forget about this router, and maybe try again. */
    connection_dir_request_failed(dir_conn);
  }
  /* If we were trying to fetch a v2 rend desc and did not succeed,
   * retry as needed. (If a fetch is successful, the connection state
   * is changed to DIR_PURPOSE_HAS_FETCHED_RENDDESC to mark that
   * refetching is unnecessary.) */
  if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC_V2 &&
      dir_conn->rend_data &&
      strlen(dir_conn->rend_data->onion_address) == REND_SERVICE_ID_LEN_BASE32)
    rend_client_refetch_v2_renddesc(dir_conn->rend_data);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Connected handler for directory connections: begin sending data to the server.

Definition at line 3585 of file directory.c.

{
  tor_assert(conn);
  tor_assert(conn->_base.type == CONN_TYPE_DIR);
  tor_assert(conn->_base.state == DIR_CONN_STATE_CONNECTING);

  log_debug(LD_HTTP,"Dir connection to router %s:%u established.",
            conn->_base.address,conn->_base.port);

  conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
  return 0;
}

Here is the caller graph for this function:

Write handler for directory connections; called when all data has been flushed.

Close the connection or wait for a response as appropriate.

Definition at line 3535 of file directory.c.

{
  tor_assert(conn);
  tor_assert(conn->_base.type == CONN_TYPE_DIR);

  /* Note that we have finished writing the directory response. For direct
   * connections this means we're done, for tunneled connections its only
   * an intermediate step. */
  if (TO_CONN(conn)->dirreq_id)
    geoip_change_dirreq_state(TO_CONN(conn)->dirreq_id, DIRREQ_TUNNELED,
                              DIRREQ_FLUSHING_DIR_CONN_FINISHED);
  else
    geoip_change_dirreq_state(TO_CONN(conn)->global_identifier,
                              DIRREQ_DIRECT,
                              DIRREQ_FLUSHING_DIR_CONN_FINISHED);
  switch (conn->_base.state) {
    case DIR_CONN_STATE_CONNECTING:
    case DIR_CONN_STATE_CLIENT_SENDING:
      log_debug(LD_DIR,"client finished sending command.");
      conn->_base.state = DIR_CONN_STATE_CLIENT_READING;
      return 0;
    case DIR_CONN_STATE_SERVER_WRITING:
      if (conn->dir_spool_src != DIR_SPOOL_NONE) {
#ifdef USE_BUFFEREVENTS
        /* This can happen with paired bufferevents, since a paired connection
         * can flush immediately when you write to it, making the subsequent
         * check in connection_handle_write_cb() decide that the connection
         * is flushed. */
        log_debug(LD_DIRSERV, "Emptied a dirserv buffer, but still spooling.");
#else
        log_warn(LD_BUG, "Emptied a dirserv buffer, but it's still spooling!");
        connection_mark_for_close(TO_CONN(conn));
#endif
      } else {
        log_debug(LD_DIRSERV, "Finished writing server response. Closing.");
        connection_mark_for_close(TO_CONN(conn));
      }
      return 0;
    default:
      log_warn(LD_BUG,"called in unexpected state %d.",
               conn->_base.state);
      tor_fragile_assert();
      return -1;
  }
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return true iff anything we say on conn is being encrypted before we send it to the client/server.

Definition at line 1043 of file directory.c.

{
  /* Right now it's sufficient to see if conn is or has been linked, since
   * the only thing it could be linked to is an edge connection on a
   * circuit, and the only way it could have been unlinked is at the edge
   * connection getting closed.
   */
  return TO_CONN(conn)->linked;
}

Here is the caller graph for this function:

Read handler for directory connections.

(That's connections to directory servers and connections at directory servers.)

Definition at line 2285 of file directory.c.

{
  tor_assert(conn);
  tor_assert(conn->_base.type == CONN_TYPE_DIR);

  /* Directory clients write, then read data until they receive EOF;
   * directory servers read data until they get an HTTP command, then
   * write their response (when it's finished flushing, they mark for
   * close).
   */

  /* If we're on the dirserver side, look for a command. */
  if (conn->_base.state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
    if (directory_handle_command(conn) < 0) {
      connection_mark_for_close(TO_CONN(conn));
      return -1;
    }
    return 0;
  }

  if (connection_get_inbuf_len(TO_CONN(conn)) > MAX_DIRECTORY_OBJECT_SIZE) {
    log_warn(LD_HTTP, "Too much data received from directory connection: "
             "denial of service attempt, or you need to upgrade?");
    connection_mark_for_close(TO_CONN(conn));
    return -1;
  }

  if (!conn->_base.inbuf_reached_eof)
    log_debug(LD_HTTP,"Got data, not eof. Leaving on inbuf.");
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Called when a directory connection reaches EOF.

Definition at line 2257 of file directory.c.

{
  int retval;
  if (conn->_base.state != DIR_CONN_STATE_CLIENT_READING) {
    log_info(LD_HTTP,"conn reached eof, not reading. [state=%d] Closing.",
             conn->_base.state);
    connection_close_immediate(TO_CONN(conn)); /* error: give up on flushing */
    connection_mark_for_close(TO_CONN(conn));
    return -1;
  }

  retval = connection_dir_client_reached_eof(conn);
  if (retval == 0) /* success */
    conn->_base.state = DIR_CONN_STATE_CLIENT_FINISHED;
  connection_mark_for_close(TO_CONN(conn));
  return retval;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int dir_split_resource_into_fingerprint_pairs ( const char *  res,
smartlist_t pairs_out 
)

Divide a string res of the form FP1-FP2+FP3-FP4...[.z], where each FP is a hex-encoded fingerprint, into a sequence of distinct sorted fp_pair_t.

Skip malformed pairs. On success, return 0 and add those fp_pair_t into pairs_out. On failure, return -1.

Definition at line 3848 of file directory.c.

{
  smartlist_t *pairs_tmp = smartlist_new();
  smartlist_t *pairs_result = smartlist_new();

  smartlist_split_string(pairs_tmp, res, "+", 0, 0);
  if (smartlist_len(pairs_tmp)) {
    char *last = smartlist_get(pairs_tmp,smartlist_len(pairs_tmp)-1);
    size_t last_len = strlen(last);
    if (last_len > 2 && !strcmp(last+last_len-2, ".z")) {
      last[last_len-2] = '\0';
    }
  }
  SMARTLIST_FOREACH_BEGIN(pairs_tmp, char *, cp) {
    if (strlen(cp) != HEX_DIGEST_LEN*2+1) {
      log_info(LD_DIR,
             "Skipping digest pair %s with non-standard length.", escaped(cp));
    } else if (cp[HEX_DIGEST_LEN] != '-') {
      log_info(LD_DIR,
             "Skipping digest pair %s with missing dash.", escaped(cp));
    } else {
      fp_pair_t pair;
      if (base16_decode(pair.first, DIGEST_LEN, cp, HEX_DIGEST_LEN)<0 ||
          base16_decode(pair.second,
                        DIGEST_LEN, cp+HEX_DIGEST_LEN+1, HEX_DIGEST_LEN)<0) {
        log_info(LD_DIR, "Skipping non-decodable digest pair %s", escaped(cp));
      } else {
        smartlist_add(pairs_result, tor_memdup(&pair, sizeof(pair)));
      }
    }
    tor_free(cp);
  } SMARTLIST_FOREACH_END(cp);
  smartlist_free(pairs_tmp);

  /* Uniq-and-sort */
  smartlist_sort(pairs_result, _compare_pairs);
  smartlist_uniq(pairs_result, _compare_pairs, _tor_free);

  smartlist_add_all(pairs_out, pairs_result);
  smartlist_free(pairs_result);
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int dir_split_resource_into_fingerprints ( const char *  resource,
smartlist_t fp_out,
int *  compressed_out,
int  flags 
)

Given a directory resource request, containing zero or more strings separated by plus signs, followed optionally by ".z", store the strings, in order, into fp_out.

If compressed_out is non-NULL, set it to 1 if the resource ends in ".z", else set it to 0.

If (flags & DSR_HEX), then delete all elements that aren't hex digests, and decode the rest. If (flags & DSR_BASE64), then use "-" rather than "+" as a separator, delete all the elements that aren't base64-encoded digests, and decode the rest. If (flags & DSR_DIGEST256), these digests should be 256 bits long; else they should be 160.

If (flags & DSR_SORT_UNIQ), then sort the list and remove all duplicates.

Definition at line 3906 of file directory.c.

{
  const int decode_hex = flags & DSR_HEX;
  const int decode_base64 = flags & DSR_BASE64;
  const int digests_are_256 = flags & DSR_DIGEST256;
  const int sort_uniq = flags & DSR_SORT_UNIQ;

  const int digest_len = digests_are_256 ? DIGEST256_LEN : DIGEST_LEN;
  const int hex_digest_len = digests_are_256 ?
    HEX_DIGEST256_LEN : HEX_DIGEST_LEN;
  const int base64_digest_len = digests_are_256 ?
    BASE64_DIGEST256_LEN : BASE64_DIGEST_LEN;
  smartlist_t *fp_tmp = smartlist_new();

  tor_assert(!(decode_hex && decode_base64));
  tor_assert(fp_out);

  smartlist_split_string(fp_tmp, resource, decode_base64?"-":"+", 0, 0);
  if (compressed_out)
    *compressed_out = 0;
  if (smartlist_len(fp_tmp)) {
    char *last = smartlist_get(fp_tmp,smartlist_len(fp_tmp)-1);
    size_t last_len = strlen(last);
    if (last_len > 2 && !strcmp(last+last_len-2, ".z")) {
      last[last_len-2] = '\0';
      if (compressed_out)
        *compressed_out = 1;
    }
  }
  if (decode_hex || decode_base64) {
    const size_t encoded_len = decode_hex ? hex_digest_len : base64_digest_len;
    int i;
    char *cp, *d = NULL;
    for (i = 0; i < smartlist_len(fp_tmp); ++i) {
      cp = smartlist_get(fp_tmp, i);
      if (strlen(cp) != encoded_len) {
        log_info(LD_DIR,
                 "Skipping digest %s with non-standard length.", escaped(cp));
        smartlist_del_keeporder(fp_tmp, i--);
        goto again;
      }
      d = tor_malloc_zero(digest_len);
      if (decode_hex ?
          (base16_decode(d, digest_len, cp, hex_digest_len)<0) :
          (base64_decode(d, digest_len, cp, base64_digest_len)<0)) {
          log_info(LD_DIR, "Skipping non-decodable digest %s", escaped(cp));
          smartlist_del_keeporder(fp_tmp, i--);
          goto again;
      }
      smartlist_set(fp_tmp, i, d);
      d = NULL;
    again:
      tor_free(cp);
      tor_free(d);
    }
  }
  if (sort_uniq) {
    if (decode_hex || decode_base64) {
      if (digests_are_256) {
        smartlist_sort_digests256(fp_tmp);
        smartlist_uniq_digests256(fp_tmp);
      } else {
        smartlist_sort_digests(fp_tmp);
        smartlist_uniq_digests(fp_tmp);
      }
    } else {
      smartlist_sort_strings(fp_tmp);
      smartlist_uniq_strings(fp_tmp);
    }
  }
  smartlist_add_all(fp_out, fp_tmp);
  smartlist_free(fp_tmp);
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return true iff any trusted directory authority has accepted our server descriptor.

We consider any authority sufficient because waiting for all of them means it never happens while any authority is down; we don't go for something more complex in the middle (like >1/3 or >1/2 or >=1/2) because that doesn't seem necessary yet.

Definition at line 253 of file directory.c.

{
  smartlist_t *servers = router_get_trusted_dir_servers();
  const or_options_t *options = get_options();
  SMARTLIST_FOREACH(servers, trusted_dir_server_t *, d, {
    if ((d->type & options->_PublishServerDescriptor) &&
        d->has_accepted_serverdesc) {
      return 1;
    }
  });
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* directory_dump_request_log ( void  )

Definition at line 2561 of file directory.c.

{
  return tor_strdup("Not supported.");
}

Here is the caller graph for this function:

void directory_get_from_all_authorities ( uint8_t  dir_purpose,
uint8_t  router_purpose,
const char *  resource 
)

As directory_get_from_dirserver, but initiates a request to every directory authority other than ourself.

Only for use by authorities when searching for missing information while voting.

Definition at line 531 of file directory.c.

{
  tor_assert(dir_purpose == DIR_PURPOSE_FETCH_STATUS_VOTE ||
             dir_purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES);

  SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
                    trusted_dir_server_t *, ds,
    {
      routerstatus_t *rs;
      if (router_digest_is_me(ds->digest))
        continue;
      if (!(ds->type & V3_DIRINFO))
        continue;
      rs = &ds->fake_status;
      directory_initiate_command_routerstatus(rs, dir_purpose, router_purpose,
                                              0, resource, NULL, 0, 0);
    });
}

Here is the call graph for this function:

Here is the caller graph for this function:

void directory_get_from_dirserver ( uint8_t  dir_purpose,
uint8_t  router_purpose,
const char *  resource,
int  pds_flags 
)

Start a connection to a random running directory server, using connection purpose dir_purpose, intending to fetch descriptors of purpose router_purpose, and requesting resource.

Use pds_flags as arguments to router_pick_directory_server() or router_pick_trusteddirserver().

Definition at line 352 of file directory.c.

{
  const routerstatus_t *rs = NULL;
  const or_options_t *options = get_options();
  int prefer_authority = directory_fetches_from_authorities(options);
  int require_authority = 0;
  int get_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose);
  dirinfo_type_t type;
  time_t if_modified_since = 0;

  /* FFFF we could break this switch into its own function, and call
   * it elsewhere in directory.c. -RD */
  switch (dir_purpose) {
    case DIR_PURPOSE_FETCH_EXTRAINFO:
      type = EXTRAINFO_DIRINFO |
             (router_purpose == ROUTER_PURPOSE_BRIDGE ? BRIDGE_DIRINFO :
                                                        V3_DIRINFO);
      break;
    case DIR_PURPOSE_FETCH_V2_NETWORKSTATUS:
      type = V2_DIRINFO;
      prefer_authority = 1; /* Only v2 authorities have these anyway. */
      require_authority = 1; /* Don't fallback to asking a non-authority */
      break;
    case DIR_PURPOSE_FETCH_SERVERDESC:
      type = (router_purpose == ROUTER_PURPOSE_BRIDGE ? BRIDGE_DIRINFO :
                                                        V3_DIRINFO);
      break;
    case DIR_PURPOSE_FETCH_RENDDESC:
      type = HIDSERV_DIRINFO;
      break;
    case DIR_PURPOSE_FETCH_STATUS_VOTE:
    case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
    case DIR_PURPOSE_FETCH_CERTIFICATE:
      type = V3_DIRINFO;
      break;
    case DIR_PURPOSE_FETCH_CONSENSUS:
      type = V3_DIRINFO;
      if (resource && !strcmp(resource,"microdesc"))
        type |= MICRODESC_DIRINFO;
      break;
    case DIR_PURPOSE_FETCH_MICRODESC:
      type = MICRODESC_DIRINFO;
      break;
    default:
      log_warn(LD_BUG, "Unexpected purpose %d", (int)dir_purpose);
      return;
  }

  if (dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
    int flav = FLAV_NS;
    networkstatus_t *v;
    if (resource)
      flav = networkstatus_parse_flavor_name(resource);

    if (flav != -1) {
      /* IF we have a parsed consensus of this type, we can do an
       * if-modified-time based on it. */
      v = networkstatus_get_latest_consensus_by_flavor(flav);
      if (v)
        if_modified_since = v->valid_after + 180;
    } else {
      /* Otherwise it might be a consensus we don't parse, but which we
       * do cache.  Look at the cached copy, perhaps. */
      cached_dir_t *cd = dirserv_get_consensus(resource);
      if (cd)
        if_modified_since = cd->published + 180;
    }
  }

  if (!options->FetchServerDescriptors && type != HIDSERV_DIRINFO)
    return;

  if (!get_via_tor) {
    if (options->UseBridges && type != BRIDGE_DIRINFO) {
      /* We want to ask a running bridge for which we have a descriptor.
       *
       * Be careful here: we should only ask questions that we know our
       * bridges can answer. So far we're solving that by backing off to
       * the behavior supported by our oldest bridge; see for example
       * any_bridges_dont_support_microdescriptors().
       */
      /* XXX024 Not all bridges handle conditional consensus downloading,
       * so, for now, never assume the server supports that. -PP */
      const node_t *node = choose_random_entry(NULL);
      if (node && node->ri) {
        /* every bridge has a routerinfo. */
        tor_addr_t addr;
        routerinfo_t *ri = node->ri;
        node_get_addr(node, &addr);
        directory_initiate_command(ri->address, &addr,
                                   ri->or_port, 0,
                                   0, /* don't use conditional consensus url */
                                   1, ri->cache_info.identity_digest,
                                   dir_purpose,
                                   router_purpose,
                                   0, resource, NULL, 0, if_modified_since);
      } else
        log_notice(LD_DIR, "Ignoring directory request, since no bridge "
                           "nodes are available yet.");
      return;
    } else {
      if (prefer_authority || type == BRIDGE_DIRINFO) {
        /* only ask authdirservers, and don't ask myself */
        rs = router_pick_trusteddirserver(type, pds_flags);
        if (rs == NULL && (pds_flags & (PDS_NO_EXISTING_SERVERDESC_FETCH|
                                        PDS_NO_EXISTING_MICRODESC_FETCH))) {
          /* We don't want to fetch from any authorities that we're currently
           * fetching server descriptors from, and we got no match.  Did we
           * get no match because all the authorities have connections
           * fetching server descriptors (in which case we should just
           * return,) or because all the authorities are down or on fire or
           * unreachable or something (in which case we should go on with
           * our fallback code)? */
          pds_flags &= ~(PDS_NO_EXISTING_SERVERDESC_FETCH|
                         PDS_NO_EXISTING_MICRODESC_FETCH);
          rs = router_pick_trusteddirserver(type, pds_flags);
          if (rs) {
            log_debug(LD_DIR, "Deferring serverdesc fetch: all authorities "
                      "are in use.");
            return;
          }
        }
        if (rs == NULL && require_authority) {
          log_info(LD_DIR, "No authorities were available for %s: will try "
                   "later.", dir_conn_purpose_to_string(dir_purpose));
          return;
        }
      }
      if (!rs && type != BRIDGE_DIRINFO) {
        /* anybody with a non-zero dirport will do */
        rs = router_pick_directory_server(type, pds_flags);
        if (!rs) {
          log_info(LD_DIR, "No router found for %s; falling back to "
                   "dirserver list.", dir_conn_purpose_to_string(dir_purpose));
          rs = router_pick_trusteddirserver(type, pds_flags);
          if (!rs)
            get_via_tor = 1; /* last resort: try routing it via Tor */
        }
      }
    }
  } else { /* get_via_tor */
    /* Never use fascistfirewall; we're going via Tor. */
    if (dir_purpose == DIR_PURPOSE_FETCH_RENDDESC) {
      /* only ask hidserv authorities, any of them will do */
      pds_flags |= PDS_IGNORE_FASCISTFIREWALL|PDS_ALLOW_SELF;
      rs = router_pick_trusteddirserver(HIDSERV_DIRINFO, pds_flags);
    } else {
      /* anybody with a non-zero dirport will do. Disregard firewalls. */
      pds_flags |= PDS_IGNORE_FASCISTFIREWALL;
      rs = router_pick_directory_server(type, pds_flags);
      /* If we have any hope of building an indirect conn, we know some router
       * descriptors.  If (rs==NULL), we can't build circuits anyway, so
       * there's no point in falling back to the authorities in this case. */
    }
  }

  if (rs)
    directory_initiate_command_routerstatus(rs, dir_purpose,
                                            router_purpose,
                                            get_via_tor,
                                            resource, NULL, 0,
                                            if_modified_since);
  else {
    log_notice(LD_DIR,
               "While fetching directory info, "
               "no running dirservers known. Will try again later. "
               "(purpose %d)", dir_purpose);
    if (!purpose_needs_anonymity(dir_purpose, router_purpose)) {
      /* remember we tried them all and failed. */
      directory_all_unreachable(time(NULL));
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void directory_initiate_command ( const char *  address,
const tor_addr_t _addr,
uint16_t  or_port,
uint16_t  dir_port,
int  supports_conditional_consensus,
int  supports_begindir,
const char *  digest,
uint8_t  dir_purpose,
uint8_t  router_purpose,
int  anonymized_connection,
const char *  resource,
const char *  payload,
size_t  payload_len,
time_t  if_modified_since 
)

Helper for directory_initiate_command_routerstatus: send the command to a server whose address is address, whose IP is addr, whose directory port is dir_port, whose tor version supports_begindir, and whose identity key digest is digest.

Definition at line 857 of file directory.c.

{
  directory_initiate_command_rend(address, _addr, or_port, dir_port,
                             supports_conditional_consensus,
                             supports_begindir, digest, dir_purpose,
                             router_purpose, anonymized_connection,
                             resource, payload, payload_len,
                             if_modified_since, NULL);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void directory_initiate_command_routerstatus ( const routerstatus_t status,
uint8_t  dir_purpose,
uint8_t  router_purpose,
int  anonymized_connection,
const char *  resource,
const char *  payload,
size_t  payload_len,
time_t  if_modified_since 
)

Launch a new connection to the directory server status to upload or download a server or rendezvous descriptor.

dir_purpose determines what kind of directory connection we're launching, and must be one of DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC|RENDDESC_V2}. router_purpose specifies the descriptor purposes we have in mind (currently only used for FETCH_DIR).

When uploading, payload and payload_len determine the content of the HTTP post. Otherwise, payload should be NULL.

When fetching a rendezvous descriptor, resource is the service ID we want to fetch.

Definition at line 624 of file directory.c.

{
  directory_initiate_command_routerstatus_rend(status, dir_purpose,
                                          router_purpose,
                                          anonymized_connection, resource,
                                          payload, payload_len,
                                          if_modified_since, NULL);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void directory_initiate_command_routerstatus_rend ( const routerstatus_t status,
uint8_t  dir_purpose,
uint8_t  router_purpose,
int  anonymized_connection,
const char *  resource,
const char *  payload,
size_t  payload_len,
time_t  if_modified_since,
const rend_data_t rend_query 
)

Same as directory_initiate_command_routerstatus(), but accepts rendezvous data to fetch a hidden service descriptor.

Definition at line 555 of file directory.c.

{
  const or_options_t *options = get_options();
  const node_t *node;
  char address_buf[INET_NTOA_BUF_LEN+1];
  struct in_addr in;
  const char *address;
  tor_addr_t addr;
  node = node_get_by_id(status->identity_digest);

  if (!node && anonymized_connection) {
    log_info(LD_DIR, "Not sending anonymized request to directory '%s'; we "
             "don't have its router descriptor.",
             routerstatus_describe(status));
    return;
  } else if (node) {
    node_get_address_string(node, address_buf, sizeof(address_buf));
    address = address_buf;
  } else {
    in.s_addr = htonl(status->addr);
    tor_inet_ntoa(&in, address_buf, sizeof(address_buf));
    address = address_buf;
  }
  tor_addr_from_ipv4h(&addr, status->addr);

  if (options->ExcludeNodes && options->StrictNodes &&
      routerset_contains_routerstatus(options->ExcludeNodes, status, -1)) {
    log_warn(LD_DIR, "Wanted to contact directory mirror %s for %s, but "
             "it's in our ExcludedNodes list and StrictNodes is set. "
             "Skipping. This choice might make your Tor not work.",
             routerstatus_describe(status),
             dir_conn_purpose_to_string(dir_purpose));
    return;
  }

  directory_initiate_command_rend(address, &addr,
                             status->or_port, status->dir_port,
                             status->version_supports_conditional_consensus,
                             status->version_supports_begindir,
                             status->identity_digest,
                             dir_purpose, router_purpose,
                             anonymized_connection, resource,
                             payload, payload_len, if_modified_since,
                             rend_query);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void directory_post_to_dirservers ( uint8_t  dir_purpose,
uint8_t  router_purpose,
dirinfo_type_t  type,
const char *  payload,
size_t  payload_len,
size_t  extrainfo_len 
)

Start a connection to every suitable directory authority, using connection purpose dir_purpose and uploading payload (of length payload_len).

The dir_purpose should be one of 'DIR_PURPOSE_UPLOAD_DIR' or 'DIR_PURPOSE_UPLOAD_RENDDESC'.

router_purpose describes the type of descriptor we're publishing, if we're publishing a descriptor -- e.g. general or bridge.

type specifies what sort of dir authorities (V1, V2, HIDSERV, BRIDGE) we should upload to.

If extrainfo_len is nonzero, the first payload_len bytes of payload hold a router descriptor, and the next extrainfo_len bytes of payload hold an extra-info document. Upload the descriptor to all authorities, and the extra-info document to all authorities that support it.

Definition at line 284 of file directory.c.

{
  const or_options_t *options = get_options();
  int post_via_tor;
  smartlist_t *dirservers = router_get_trusted_dir_servers();
  int found = 0;
  const int exclude_self = (dir_purpose == DIR_PURPOSE_UPLOAD_VOTE ||
                            dir_purpose == DIR_PURPOSE_UPLOAD_SIGNATURES);
  tor_assert(dirservers);
  /* This tries dirservers which we believe to be down, but ultimately, that's
   * harmless, and we may as well err on the side of getting things uploaded.
   */
  SMARTLIST_FOREACH_BEGIN(dirservers, trusted_dir_server_t *, ds) {
      routerstatus_t *rs = &(ds->fake_status);
      size_t upload_len = payload_len;
      tor_addr_t ds_addr;

      if ((type & ds->type) == 0)
        continue;

      if (exclude_self && router_digest_is_me(ds->digest))
        continue;

      if (options->StrictNodes &&
          routerset_contains_routerstatus(options->ExcludeNodes, rs, -1)) {
        log_warn(LD_DIR, "Wanted to contact authority '%s' for %s, but "
                 "it's in our ExcludedNodes list and StrictNodes is set. "
                 "Skipping.",
                 ds->nickname,
                 dir_conn_purpose_to_string(dir_purpose));
        continue;
      }

      found = 1; /* at least one authority of this type was listed */
      if (dir_purpose == DIR_PURPOSE_UPLOAD_DIR)
        ds->has_accepted_serverdesc = 0;

      if (extrainfo_len && router_supports_extrainfo(ds->digest, 1)) {
        upload_len += extrainfo_len;
        log_info(LD_DIR, "Uploading an extrainfo too (length %d)",
                 (int) extrainfo_len);
      }
      tor_addr_from_ipv4h(&ds_addr, ds->addr);
      post_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose) ||
        !fascist_firewall_allows_address_dir(&ds_addr, ds->dir_port);
      directory_initiate_command_routerstatus(rs, dir_purpose,
                                              router_purpose,
                                              post_via_tor,
                                              NULL, payload, upload_len, 0);
  } SMARTLIST_FOREACH_END(ds);
  if (!found) {
    char *s = authdir_type_to_string(type);
    log_warn(LD_DIR, "Publishing server descriptor to directory authorities "
             "of type '%s', but no authorities of that type listed!", s);
    tor_free(s);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return the number of failures on dls since the last success (if any).

Definition at line 3748 of file directory.c.

{
  return dls->n_download_failures;
}

Here is the caller graph for this function:

time_t download_status_increment_failure ( download_status_t dls,
int  status_code,
const char *  item,
int  server,
time_t  now 
)

Called when an attempt to download dls has failed with HTTP status status_code.

Increment the failure count (if the code indicates a real failure) and set dls->next_attempt_at to an appropriate time in the future.

Definition at line 3683 of file directory.c.

{
  const int *schedule;
  size_t schedule_len;
  int increment;
  tor_assert(dls);
  if (status_code != 503 || server) {
    if (dls->n_download_failures < IMPOSSIBLE_TO_DOWNLOAD-1)
      ++dls->n_download_failures;
  }

  find_dl_schedule_and_len(dls, server, &schedule, &schedule_len);

  if (dls->n_download_failures < schedule_len)
    increment = schedule[dls->n_download_failures];
  else if (dls->n_download_failures == IMPOSSIBLE_TO_DOWNLOAD)
    increment = INT_MAX;
  else
    increment = schedule[schedule_len-1];

  if (increment < INT_MAX)
    dls->next_attempt_at = now+increment;
  else
    dls->next_attempt_at = TIME_MAX;

  if (item) {
    if (increment == 0)
      log_debug(LD_DIR, "%s failed %d time(s); I'll try again immediately.",
                item, (int)dls->n_download_failures);
    else if (dls->next_attempt_at < TIME_MAX)
      log_debug(LD_DIR, "%s failed %d time(s); I'll try again in %d seconds.",
                item, (int)dls->n_download_failures,
                (int)(dls->next_attempt_at-now));
    else
      log_debug(LD_DIR, "%s failed %d time(s); Giving up for a while.",
                item, (int)dls->n_download_failures);
  }
  return dls->next_attempt_at;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static INLINE int download_status_is_ready ( download_status_t dls,
time_t  now,
int  max_failures 
) [static]

Return true iff, as of now, the resource tracked by dls is ready to get its download reattempted.

Definition at line 91 of file directory.h.

{
  return (dls->n_download_failures <= max_failures
          && dls->next_attempt_at <= now);
}

Here is the caller graph for this function:

Mark dl as never downloadable.

Definition at line 101 of file directory.h.

Here is the caller graph for this function:

Reset dls so that it will be considered downloadable immediately, and/or to show that we don't need it anymore.

(We find the zeroth element of the download schedule, and set next_attempt_at to be the appropriate offset from 'now'. In most cases this means setting it to 'now', so the item will be immediately downloadable; in the case of bridge descriptors, the zeroth element is an hour from now.)

Definition at line 3733 of file directory.c.

{
  const int *schedule;
  size_t schedule_len;

  find_dl_schedule_and_len(dls, get_options()->DirPort != NULL,
                           &schedule, &schedule_len);

  dls->n_download_failures = 0;
  dls->next_attempt_at = time(NULL) + schedule[0];
}

Here is the call graph for this function:

Here is the caller graph for this function:

void note_request ( const char *  key,
size_t  bytes 
)

Definition at line 2554 of file directory.c.

{
  (void)key;
  (void)bytes;
}

Here is the caller graph for this function:

int parse_http_response ( const char *  headers,
int *  code,
time_t *  date,
compress_method_t compression,
char **  reason 
)

Parse an HTTP response string headers of the form.

 * "HTTP/1.\%d \%d\%s\r\n...".
 * 

If it's well-formed, assign the status code to *code and return 0. Otherwise, return -1.

On success: If date is provided, set *date to the Date header in the http headers, or 0 if no such header is found. If compression is provided, set *compression to the compression method given in the Content-Encoding header, or 0 if no such header is found, or -1 if the value of the header is not recognized. If reason is provided, strdup the reason string into it.

Definition at line 1428 of file directory.c.

{
  unsigned n1, n2;
  char datestr[RFC1123_TIME_LEN+1];
  smartlist_t *parsed_headers;
  tor_assert(headers);
  tor_assert(code);

  while (TOR_ISSPACE(*headers)) headers++; /* tolerate leading whitespace */

  if (tor_sscanf(headers, "HTTP/1.%u %u", &n1, &n2) < 2 ||
      (n1 != 0 && n1 != 1) ||
      (n2 < 100 || n2 >= 600)) {
    log_warn(LD_HTTP,"Failed to parse header %s",escaped(headers));
    return -1;
  }
  *code = n2;

  parsed_headers = smartlist_new();
  smartlist_split_string(parsed_headers, headers, "\n",
                         SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
  if (reason) {
    smartlist_t *status_line_elements = smartlist_new();
    tor_assert(smartlist_len(parsed_headers));
    smartlist_split_string(status_line_elements,
                           smartlist_get(parsed_headers, 0),
                           " ", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 3);
    tor_assert(smartlist_len(status_line_elements) <= 3);
    if (smartlist_len(status_line_elements) == 3) {
      *reason = smartlist_get(status_line_elements, 2);
      smartlist_set(status_line_elements, 2, NULL); /* Prevent free */
    }
    SMARTLIST_FOREACH(status_line_elements, char *, cp, tor_free(cp));
    smartlist_free(status_line_elements);
  }
  if (date) {
    *date = 0;
    SMARTLIST_FOREACH(parsed_headers, const char *, s,
      if (!strcmpstart(s, "Date: ")) {
        strlcpy(datestr, s+6, sizeof(datestr));
        /* This will do nothing on failure, so we don't need to check
           the result.   We shouldn't warn, since there are many other valid
           date formats besides the one we use. */
        parse_rfc1123_time(datestr, date);
        break;
      });
  }
  if (compression) {
    const char *enc = NULL;
    SMARTLIST_FOREACH(parsed_headers, const char *, s,
      if (!strcmpstart(s, "Content-Encoding: ")) {
        enc = s+18; break;
      });
    if (!enc || !strcmp(enc, "identity")) {
      *compression = NO_METHOD;
    } else if (!strcmp(enc, "deflate") || !strcmp(enc, "x-deflate")) {
      *compression = ZLIB_METHOD;
    } else if (!strcmp(enc, "gzip") || !strcmp(enc, "x-gzip")) {
      *compression = GZIP_METHOD;
    } else {
      log_info(LD_HTTP, "Unrecognized content encoding: %s. Trying to deal.",
               escaped(enc));
      *compression = UNKNOWN_METHOD;
    }
  }
  SMARTLIST_FOREACH(parsed_headers, char *, s, tor_free(s));
  smartlist_free(parsed_headers);

  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int router_supports_extrainfo ( const char *  identity_digest,
int  is_authority 
)

Return true iff identity_digest is the digest of a router we believe to support extrainfo downloads.

(If is_authority we do additional checking that's only valid for authorities.)

Definition at line 223 of file directory.c.

{
  const node_t *node = node_get_by_id(identity_digest);

  if (node && node->ri) {
    if (node->ri->caches_extra_info)
      return 1;
    if (is_authority && node->ri->platform &&
        tor_version_as_new_as(node->ri->platform,
                              "Tor 0.2.0.0-alpha-dev (r10070)"))
      return 1;
  }
  if (is_authority) {
    const routerstatus_t *rs =
      router_get_consensus_status_by_id(identity_digest);
    if (rs && rs->version_supports_extrainfo_upload)
      return 1;
  }
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function: