Back to index

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

Header file for dirserv.c. More...

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

Go to the source code of this file.

Defines

#define REACHABILITY_MODULO_PER_TEST   128
 What fraction (1 over this number) of the relay ID space do we (as a directory authority) launch connections to at each reachability test?
#define REACHABILITY_TEST_INTERVAL   10
 How often (in seconds) do we launch reachability tests?
#define REACHABILITY_TEST_CYCLE_PERIOD   (REACHABILITY_TEST_INTERVAL*REACHABILITY_MODULO_PER_TEST)
 How many seconds apart are the reachability tests for a given relay?
#define MAX_EXITPOLICY_SUMMARY_LEN   1000
 Maximum length of an exit policy summary.
#define MAX_V_LINE_LEN   128
 Maximum allowable length of a version line in a networkstatus.
#define MAX_FLAG_LINE_LEN   96
 Length of "r Authority BadDirectory BadExit Exit Fast Guard HSDir Named Running Stable Unnamed V2Dir Valid\n".
#define MAX_WEIGHT_LINE_LEN   (12+10+10+10+1)
 Length of "w" line for weighting.
#define MAX_POLICY_LINE_LEN   (3+MAX_EXITPOLICY_SUMMARY_LEN)
 Maximum length of an exit policy summary line.
#define RS_ENTRY_LEN
 Amount of space to allocate for each entry: r, s, and v lines.
#define directory_caches_v1_dir_info(o)   directory_caches_v2_dir_info(o)

Functions

int connection_dirserv_flushed_some (dir_connection_t *conn)
 Called whenever we have flushed some directory data in state SERVER_WRITING.
int dirserv_add_own_fingerprint (const char *nickname, crypto_pk_t *pk)
 Add the nickname and fingerprint for this OR to the global list of recognized identity key fingerprints.
int dirserv_load_fingerprint_file (void)
 Load the nickname->fingerprint mappings stored in the approved-routers file.
void dirserv_free_fingerprint_list (void)
 Clear the current fingerprint list.
const char * dirserv_get_nickname_by_digest (const char *digest)
 If we are an authoritative dirserver, and the list of approved servers contains one whose identity key digest is digest, return that router's nickname.
enum was_router_added_t dirserv_add_multiple_descriptors (const char *desc, uint8_t purpose, const char *source, const char **msg)
 As for dirserv_add_descriptor(), but accepts multiple documents, and returns the most severe error that occurred for any one of them.
enum was_router_added_t dirserv_add_descriptor (routerinfo_t *ri, const char **msg, const char *source)
 Examine the parsed server descriptor in ri and maybe insert it into the list of server descriptors.
void dirserv_set_router_is_running (routerinfo_t *router, time_t now)
 Treat a router as alive if.
int list_server_status_v1 (smartlist_t *routers, char **router_status_out, int for_controller)
 Based on the routerinfo_ts in routers, allocate the contents of a v1-style router-status line, and store it in *router_status_out.
int dirserv_dump_directory_to_string (char **dir_out, crypto_pk_t *private_key)
 Generate a new v1 directory and write it into a newly allocated string.
int directory_fetches_from_authorities (const or_options_t *options)
 Return 1 if we fetch our directory material directly from the authorities, rather than from a mirror.
int directory_fetches_dir_info_early (const or_options_t *options)
 Return 1 if we should fetch new networkstatuses, descriptors, etc on the "mirror" schedule rather than the "client" schedule.
int directory_fetches_dir_info_later (const or_options_t *options)
 Return 1 if we should fetch new networkstatuses, descriptors, etc on a very passive schedule -- waiting long enough for ordinary clients to probably have the info we want.
int directory_caches_v2_dir_info (const or_options_t *options)
 Return 1 if we want to cache v2 dir info (each status file).
int directory_caches_unknown_auth_certs (const or_options_t *options)
 Return true iff we want to fetch and keep certificates for authorities that we don't acknowledge as aurthorities ourself.
int directory_caches_dir_info (const or_options_t *options)
 Return 1 if we want to keep descriptors, networkstatuses, etc around and we're willing to serve them to others.
int directory_permits_begindir_requests (const or_options_t *options)
 Return 1 if we want to allow remote people to ask us directory requests via the "begin_dir" interface, which doesn't require having any separate port open.
int directory_permits_controller_requests (const or_options_t *options)
 Return 1 if we want to allow controllers to ask us directory requests via the controller interface, which doesn't require having any separate port open.
int directory_too_idle_to_fetch_descriptors (const or_options_t *options, time_t now)
 Return 1 if we have no need to fetch new descriptors.
void directory_set_dirty (void)
 Mark the directory as dirty -- when we're next asked for a directory, we will rebuild it instead of reusing the most recently generated one.
cached_dir_tdirserv_get_directory (void)
 Return the most recently generated encoded signed v1 directory, generating a new one as necessary.
cached_dir_tdirserv_get_runningrouters (void)
 Set *rr to the most recently generated encoded signed running-routers list, generating a new one as necessary.
cached_dir_tdirserv_get_consensus (const char *flavor_name)
 Return the latest downloaded consensus networkstatus in encoded, signed, optionally compressed format, suitable for sending to clients.
void dirserv_set_cached_directory (const char *directory, time_t when, int is_running_routers)
 If we have no cached v1 directory, or it is older than published, then replace it with directory, published at published.
void dirserv_set_cached_networkstatus_v2 (const char *directory, const char *identity, time_t published)
 If networkstatus is non-NULL, we've just received a v2 network-status for an authoritative directory with identity digest identity published at published -- store it so we can serve it to others.
void dirserv_set_cached_consensus_networkstatus (const char *consensus, const char *flavor_name, const digests_t *digests, time_t published)
 Replace the v3 consensus networkstatus of type flavor_name that we're serving with networkstatus, published at published.
void dirserv_clear_old_networkstatuses (time_t cutoff)
 Remove any v2 networkstatus from the directory cache that was published before cutoff.
void dirserv_clear_old_v1_info (time_t now)
 Remove any v1 info from the directory cache that was published too long ago.
void dirserv_get_networkstatus_v2 (smartlist_t *result, const char *key)
 Look for a network status object as specified by key, which should be either "authority" (to find a network status generated by us), a hex identity digest (to find a network status generated by given directory), or "all" (to return all the v2 network status objects we have).
void dirserv_get_networkstatus_v2_fingerprints (smartlist_t *result, const char *key)
 Given the portion of a networkstatus request URL after "tor/status/" in key, append to result the digests of the identity keys of the networkstatus objects that the client has requested.
int dirserv_get_routerdesc_fingerprints (smartlist_t *fps_out, const char *key, const char **msg, int for_unencrypted_conn, int is_extrainfo)
 As dirserv_get_routerdescs(), but instead of getting signed_descriptor_t pointers, adds copies of digests to fps_out, and doesn't use the /tor/server/ prefix.
int dirserv_get_routerdescs (smartlist_t *descs_out, const char *key, const char **msg)
 Add a signed_descriptor_t to descs_out for each router matching key.
void dirserv_orconn_tls_done (const char *address, uint16_t or_port, const char *digest_rcvd)
 Called when a TLS handshake has completed successfully with a router listening at address:or_port, and has yielded a certificate with digest digest_rcvd.
int dirserv_should_launch_reachability_test (const routerinfo_t *ri, const routerinfo_t *ri_old)
 Called when we, as an authority, receive a new router descriptor either as an upload or a download.
void dirserv_single_reachability_test (time_t now, routerinfo_t *router)
 Helper function for dirserv_test_reachability().
void dirserv_test_reachability (time_t now)
 Auth dir server only: load balance such that we only try a few connections per call.
int authdir_wants_to_reject_router (routerinfo_t *ri, const char **msg, int complain, int *valid_out)
 Check whether we, as a directory server, want to accept ri.
uint32_t dirserv_router_get_status (const routerinfo_t *router, const char **msg)
 Check whether router has a nickname/identity key combination that we recognize from the fingerprint list, or an IP we automatically act on according to our configuration.
void dirserv_set_node_flags_from_authoritative_status (node_t *node, uint32_t authstatus)
 Update the relevant flags of node based on our opinion as a directory authority in authstatus, as returned by dirserv_router_get_status or equivalent.
int dirserv_would_reject_router (const routerstatus_t *rs)
 Return true if there is no point in downloading the router described by rs because this directory would reject it.
int dirserv_remove_old_statuses (smartlist_t *fps, time_t cutoff)
 Remove from fps every networkstatus key where both a) we have a networkstatus document and b) it is not newer than cutoff.
int dirserv_have_any_serverdesc (smartlist_t *fps, int spool_src)
 Return true iff we have any of the documents (extrainfo or routerdesc) specified by the fingerprints in fps and spool_src.
int dirserv_have_any_microdesc (const smartlist_t *fps)
 Return true iff any of the 256-bit elements in fps is the digest of a microdescriptor we have.
size_t dirserv_estimate_data_size (smartlist_t *fps, int is_serverdescs, int compressed)
 Return an approximate estimate of the number of bytes that will be needed to transmit the server descriptors (if is_serverdescs -- they can be either d/ or fp/ queries) or networkstatus objects (if !is_serverdescs) listed in fps.
size_t dirserv_estimate_microdesc_size (const smartlist_t *fps, int compressed)
 Given a list of microdescriptor hashes, guess how many bytes will be needed to transmit them, and return the guess.
int routerstatus_format_entry (char *buf, size_t buf_len, const routerstatus_t *rs, const char *platform, routerstatus_format_type_t format)
 Helper: write the router-status information in rs into buf, which has at least buf_len free characters.
void dirserv_free_all (void)
 Release all storage used by the directory server.
void cached_dir_decref (cached_dir_t *d)
 Decrement the reference count on d, and free it if it no longer has any references.
cached_dir_tnew_cached_dir (char *s, time_t published)
 Allocate and return a new cached_dir_t containing the string s, published at published.
int dirserv_read_measured_bandwidths (const char *from_file, smartlist_t *routerstatuses)
 Read the measured bandwidth file and apply it to the list of routerstatuses.

Detailed Description

Header file for dirserv.c.

Definition in file dirserv.h.


Define Documentation

Definition at line 78 of file dirserv.h.

#define MAX_EXITPOLICY_SUMMARY_LEN   1000

Maximum length of an exit policy summary.

Definition at line 28 of file dirserv.h.

#define MAX_FLAG_LINE_LEN   96

Length of "r Authority BadDirectory BadExit Exit Fast Guard HSDir Named Running Stable Unnamed V2Dir Valid\n".

Definition at line 34 of file dirserv.h.

Maximum length of an exit policy summary line.

Definition at line 39 of file dirserv.h.

#define MAX_V_LINE_LEN   128

Maximum allowable length of a version line in a networkstatus.

Definition at line 31 of file dirserv.h.

#define MAX_WEIGHT_LINE_LEN   (12+10+10+10+1)

Length of "w" line for weighting.

Currently at most "w Bandwidth=<uint32t> Measured=<uint32t>\n"

Definition at line 37 of file dirserv.h.

#define REACHABILITY_MODULO_PER_TEST   128

What fraction (1 over this number) of the relay ID space do we (as a directory authority) launch connections to at each reachability test?

Definition at line 18 of file dirserv.h.

How many seconds apart are the reachability tests for a given relay?

Definition at line 24 of file dirserv.h.

#define REACHABILITY_TEST_INTERVAL   10

How often (in seconds) do we launch reachability tests?

Definition at line 21 of file dirserv.h.

#define RS_ENTRY_LEN
Value:
( /* first line */                                                    \
   MAX_NICKNAME_LEN+BASE64_DIGEST_LEN*2+ISO_TIME_LEN+INET_NTOA_BUF_LEN+ \
   5*2 /* ports */ + 10 /* punctuation */ +                             \
   /* second line */                                                    \
   MAX_FLAG_LINE_LEN +                                                  \
   /* weight line */                                                    \
   MAX_WEIGHT_LINE_LEN +                                                \
   /* p line. */                                                        \
   MAX_POLICY_LINE_LEN +                                                \
   /* v line. */                                                        \
   MAX_V_LINE_LEN                                                       \
   )

Amount of space to allocate for each entry: r, s, and v lines.

Definition at line 41 of file dirserv.h.


Function Documentation

int authdir_wants_to_reject_router ( routerinfo_t ri,
const char **  msg,
int  complain,
int *  valid_out 
)

Check whether we, as a directory server, want to accept ri.

If so, set its is_valid,named,running fields and return 0. Otherwise, return -1.

If the router is rejected, set *msg to an explanation of why.

If complain then explain at log-level 'notice' why we refused a descriptor; else explain at log-level 'info'.

Definition at line 545 of file dirserv.c.

{
  /* Okay.  Now check whether the fingerprint is recognized. */
  uint32_t status = dirserv_router_get_status(ri, msg);
  time_t now;
  int severity = (complain && ri->contact_info) ? LOG_NOTICE : LOG_INFO;
  tor_assert(msg);
  if (status & FP_REJECT)
    return -1; /* msg is already set. */

  /* Is there too much clock skew? */
  now = time(NULL);
  if (ri->cache_info.published_on > now+ROUTER_ALLOW_SKEW) {
    log_fn(severity, LD_DIRSERV, "Publication time for %s is too "
           "far (%d minutes) in the future; possible clock skew. Not adding "
           "(%s)",
           router_describe(ri),
           (int)((ri->cache_info.published_on-now)/60),
           esc_router_info(ri));
    *msg = "Rejected: Your clock is set too far in the future, or your "
      "timezone is not correct.";
    return -1;
  }
  if (ri->cache_info.published_on < now-ROUTER_MAX_AGE_TO_PUBLISH) {
    log_fn(severity, LD_DIRSERV,
           "Publication time for %s is too far "
           "(%d minutes) in the past. Not adding (%s)",
           router_describe(ri),
           (int)((now-ri->cache_info.published_on)/60),
           esc_router_info(ri));
    *msg = "Rejected: Server is expired, or your clock is too far in the past,"
      " or your timezone is not correct.";
    return -1;
  }
  if (dirserv_router_has_valid_address(ri) < 0) {
    log_fn(severity, LD_DIRSERV,
           "Router %s has invalid address '%s'. "
           "Not adding (%s).",
           router_describe(ri),
           ri->address,
           esc_router_info(ri));
    *msg = "Rejected: Address is not an IP, or IP is a private address.";
    return -1;
  }

  *valid_out = ! (status & FP_INVALID);

  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Decrement the reference count on d, and free it if it no longer has any references.

Definition at line 1366 of file dirserv.c.

{
  if (!d || --d->refcnt > 0)
    return;
  clear_cached_dir(d);
  tor_free(d);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Called whenever we have flushed some directory data in state SERVER_WRITING.

Definition at line 3772 of file dirserv.c.

{
  tor_assert(conn->_base.state == DIR_CONN_STATE_SERVER_WRITING);

  if (connection_get_outbuf_len(TO_CONN(conn)) >= DIRSERV_BUFFER_MIN)
    return 0;

  switch (conn->dir_spool_src) {
    case DIR_SPOOL_EXTRA_BY_DIGEST:
    case DIR_SPOOL_EXTRA_BY_FP:
    case DIR_SPOOL_SERVER_BY_DIGEST:
    case DIR_SPOOL_SERVER_BY_FP:
      return connection_dirserv_add_servers_to_outbuf(conn);
    case DIR_SPOOL_MICRODESC:
      return connection_dirserv_add_microdescs_to_outbuf(conn);
    case DIR_SPOOL_CACHED_DIR:
      return connection_dirserv_add_dir_bytes_to_outbuf(conn);
    case DIR_SPOOL_NETWORKSTATUS:
      return connection_dirserv_add_networkstatus_bytes_to_outbuf(conn);
    case DIR_SPOOL_NONE:
    default:
      return 0;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

int directory_caches_dir_info ( const or_options_t options)

Return 1 if we want to keep descriptors, networkstatuses, etc around and we're willing to serve them to others.

Else return 0.

Definition at line 1269 of file dirserv.c.

{
  if (options->BridgeRelay || options->DirPort)
    return 1;
  if (!server_mode(options) || !advertised_server_mode())
    return 0;
  /* We need an up-to-date view of network info if we're going to try to
   * block exit attempts from unknown relays. */
  return ! router_my_exit_policy_is_reject_star() &&
    should_refuse_unknown_exits(options);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return true iff we want to fetch and keep certificates for authorities that we don't acknowledge as aurthorities ourself.

Definition at line 1260 of file dirserv.c.

{
  return options->DirPort || options->BridgeRelay;
}

Here is the caller graph for this function:

int directory_caches_v2_dir_info ( const or_options_t options)

Return 1 if we want to cache v2 dir info (each status file).

Definition at line 1251 of file dirserv.c.

{
  return options->DirPort != NULL;
}

Here is the caller graph for this function:

Return 1 if we should fetch new networkstatuses, descriptors, etc on the "mirror" schedule rather than the "client" schedule.

Definition at line 1231 of file dirserv.c.

Here is the call graph for this function:

Here is the caller graph for this function:

Return 1 if we should fetch new networkstatuses, descriptors, etc on a very passive schedule -- waiting long enough for ordinary clients to probably have the info we want.

These would include bridge users, and maybe others in the future e.g. if a Tor client uses another Tor client as a directory guard.

Definition at line 1243 of file dirserv.c.

{
  return options->UseBridges != 0;
}

Here is the caller graph for this function:

Return 1 if we fetch our directory material directly from the authorities, rather than from a mirror.

Definition at line 1204 of file dirserv.c.

{
  const routerinfo_t *me;
  uint32_t addr;
  int refuseunknown;
  if (options->FetchDirInfoEarly)
    return 1;
  if (options->BridgeRelay == 1)
    return 0;
  if (server_mode(options) && router_pick_published_address(options, &addr)<0)
    return 1; /* we don't know our IP address; ask an authority. */
  refuseunknown = ! router_my_exit_policy_is_reject_star() &&
    should_refuse_unknown_exits(options);
  if (options->DirPort == NULL && !refuseunknown)
    return 0;
  if (!server_mode(options) || !advertised_server_mode())
    return 0;
  me = router_get_my_routerinfo();
  if (!me || (!me->dir_port && !refuseunknown))
    return 0; /* if dirport not advertised, return 0 too */
  return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return 1 if we want to allow remote people to ask us directory requests via the "begin_dir" interface, which doesn't require having any separate port open.

Definition at line 1285 of file dirserv.c.

{
  return options->BridgeRelay != 0 || options->DirPort != NULL;
}

Here is the caller graph for this function:

Return 1 if we want to allow controllers to ask us directory requests via the controller interface, which doesn't require having any separate port open.

Definition at line 1294 of file dirserv.c.

{
  return options->DirPort != NULL;
}
void directory_set_dirty ( void  )

Mark the directory as dirty -- when we're next asked for a directory, we will rebuild it instead of reusing the most recently generated one.

Definition at line 899 of file dirserv.c.

{
  time_t now = time(NULL);
  int set_v1_dirty=0;

  /* Regenerate stubs only every 8 hours.
   * XXXX It would be nice to generate less often, but these are just
   * stubs: it doesn't matter. */
#define STUB_REGENERATE_INTERVAL (8*60*60)
  if (!the_directory || !the_runningrouters.dir)
    set_v1_dirty = 1;
  else if (the_directory->published < now - STUB_REGENERATE_INTERVAL ||
           the_runningrouters.published < now - STUB_REGENERATE_INTERVAL)
    set_v1_dirty = 1;

  if (set_v1_dirty) {
    if (!the_directory_is_dirty)
      the_directory_is_dirty = now;
    if (!runningrouters_is_dirty)
      runningrouters_is_dirty = now;
  }
  if (!the_v2_networkstatus_is_dirty)
    the_v2_networkstatus_is_dirty = now;
}

Here is the caller graph for this function:

int directory_too_idle_to_fetch_descriptors ( const or_options_t options,
time_t  now 
)

Return 1 if we have no need to fetch new descriptors.

This generally happens when we're not a dir cache and we haven't built any circuits lately.

Definition at line 1304 of file dirserv.c.

Here is the call graph for this function:

Here is the caller graph for this function:

enum was_router_added_t dirserv_add_descriptor ( routerinfo_t ri,
const char **  msg,
const char *  source 
)

Examine the parsed server descriptor in ri and maybe insert it into the list of server descriptors.

Set *msg to a message that should be passed back to the origin of this descriptor, or NULL if there is no such message. Use source to produce better log messages.

Return the status of the operation

This function is only called when fresh descriptors are posted, not when we re-load the cache.

Definition at line 704 of file dirserv.c.

{
  was_router_added_t r;
  routerinfo_t *ri_old;
  char *desc, *nickname;
  size_t desclen = 0;
  *msg = NULL;

  /* If it's too big, refuse it now. Otherwise we'll cache it all over the
   * network and it'll clog everything up. */
  if (ri->cache_info.signed_descriptor_len > MAX_DESCRIPTOR_UPLOAD_SIZE) {
    log_notice(LD_DIR, "Somebody attempted to publish a router descriptor '%s'"
               " (source: %s) with size %d. Either this is an attack, or the "
               "MAX_DESCRIPTOR_UPLOAD_SIZE (%d) constant is too low.",
               ri->nickname, source, (int)ri->cache_info.signed_descriptor_len,
               MAX_DESCRIPTOR_UPLOAD_SIZE);
    *msg = "Router descriptor was too large";
    control_event_or_authdir_new_descriptor("REJECTED",
               ri->cache_info.signed_descriptor_body,
               ri->cache_info.signed_descriptor_len, *msg);
    routerinfo_free(ri);
    return ROUTER_AUTHDIR_REJECTS;
  }

  /* Check whether this descriptor is semantically identical to the last one
   * from this server.  (We do this here and not in router_add_to_routerlist
   * because we want to be able to accept the newest router descriptor that
   * another authority has, so we all converge on the same one.) */
  ri_old = router_get_mutable_by_digest(ri->cache_info.identity_digest);
  if (ri_old && ri_old->cache_info.published_on < ri->cache_info.published_on
      && router_differences_are_cosmetic(ri_old, ri)
      && !router_is_me(ri)) {
    log_info(LD_DIRSERV,
             "Not replacing descriptor from %s (source: %s); "
             "differences are cosmetic.",
             router_describe(ri), source);
    *msg = "Not replacing router descriptor; no information has changed since "
      "the last one with this identity.";
    control_event_or_authdir_new_descriptor("DROPPED",
                         ri->cache_info.signed_descriptor_body,
                         ri->cache_info.signed_descriptor_len, *msg);
    routerinfo_free(ri);
    return ROUTER_WAS_NOT_NEW;
  }

  /* Make a copy of desc, since router_add_to_routerlist might free
   * ri and its associated signed_descriptor_t. */
  desclen = ri->cache_info.signed_descriptor_len;
  desc = tor_strndup(ri->cache_info.signed_descriptor_body, desclen);
  nickname = tor_strdup(ri->nickname);

  /* Tell if we're about to need to launch a test if we add this. */
  ri->needs_retest_if_added =
    dirserv_should_launch_reachability_test(ri, ri_old);

  r = router_add_to_routerlist(ri, msg, 0, 0);
  if (!WRA_WAS_ADDED(r)) {
    /* unless the routerinfo was fine, just out-of-date */
    if (WRA_WAS_REJECTED(r))
      control_event_or_authdir_new_descriptor("REJECTED", desc, desclen, *msg);
    log_info(LD_DIRSERV,
             "Did not add descriptor from '%s' (source: %s): %s.",
             nickname, source, *msg ? *msg : "(no message)");
  } else {
    smartlist_t *changed;
    control_event_or_authdir_new_descriptor("ACCEPTED", desc, desclen, *msg);

    changed = smartlist_new();
    smartlist_add(changed, ri);
    routerlist_descriptors_added(changed, 0);
    smartlist_free(changed);
    if (!*msg) {
      *msg =  "Descriptor accepted";
    }
    log_info(LD_DIRSERV,
             "Added descriptor from '%s' (source: %s): %s.",
             nickname, source, *msg);
  }
  tor_free(desc);
  tor_free(nickname);
  return r;
}

Here is the call graph for this function:

Here is the caller graph for this function:

enum was_router_added_t dirserv_add_multiple_descriptors ( const char *  desc,
uint8_t  purpose,
const char *  source,
const char **  msg 
)

As for dirserv_add_descriptor(), but accepts multiple documents, and returns the most severe error that occurred for any one of them.

Definition at line 618 of file dirserv.c.

{
  was_router_added_t r, r_tmp;
  const char *msg_out;
  smartlist_t *list;
  const char *s;
  int n_parsed = 0;
  time_t now = time(NULL);
  char annotation_buf[ROUTER_ANNOTATION_BUF_LEN];
  char time_buf[ISO_TIME_LEN+1];
  int general = purpose == ROUTER_PURPOSE_GENERAL;
  tor_assert(msg);

  r=ROUTER_ADDED_SUCCESSFULLY; /*Least severe return value. */

  format_iso_time(time_buf, now);
  if (tor_snprintf(annotation_buf, sizeof(annotation_buf),
                   "@uploaded-at %s\n"
                   "@source %s\n"
                   "%s%s%s", time_buf, escaped(source),
                   !general ? "@purpose " : "",
                   !general ? router_purpose_to_string(purpose) : "",
                   !general ? "\n" : "")<0) {
    *msg = "Couldn't format annotations";
    return -1;
  }

  s = desc;
  list = smartlist_new();
  if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 0, 0,
                                     annotation_buf)) {
    SMARTLIST_FOREACH(list, routerinfo_t *, ri, {
        msg_out = NULL;
        tor_assert(ri->purpose == purpose);
        r_tmp = dirserv_add_descriptor(ri, &msg_out, source);
        if (WRA_MORE_SEVERE(r_tmp, r)) {
          r = r_tmp;
          *msg = msg_out;
        }
      });
  }
  n_parsed += smartlist_len(list);
  smartlist_clear(list);

  s = desc;
  if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 1, 0,
                                     NULL)) {
    SMARTLIST_FOREACH(list, extrainfo_t *, ei, {
        msg_out = NULL;

        r_tmp = dirserv_add_extrainfo(ei, &msg_out);
        if (WRA_MORE_SEVERE(r_tmp, r)) {
          r = r_tmp;
          *msg = msg_out;
        }
      });
  }
  n_parsed += smartlist_len(list);
  smartlist_free(list);

  if (! *msg) {
    if (!n_parsed) {
      *msg = "No descriptors found in your POST.";
      if (WRA_WAS_ADDED(r))
        r = ROUTER_WAS_NOT_NEW;
    } else {
      *msg = "(no message)";
    }
  }

  return r;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int dirserv_add_own_fingerprint ( const char *  nickname,
crypto_pk_t pk 
)

Add the nickname and fingerprint for this OR to the global list of recognized identity key fingerprints.

Definition at line 188 of file dirserv.c.

{
  char fp[FINGERPRINT_LEN+1];
  if (crypto_pk_get_fingerprint(pk, fp, 0)<0) {
    log_err(LD_BUG, "Error computing fingerprint");
    return -1;
  }
  if (!fingerprint_list)
    fingerprint_list = authdir_config_new();
  add_fingerprint_to_dir(nickname, fp, fingerprint_list);
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dirserv_clear_old_networkstatuses ( time_t  cutoff)

Remove any v2 networkstatus from the directory cache that was published before cutoff.

Definition at line 1527 of file dirserv.c.

{
  if (!cached_v2_networkstatus)
    return;

  DIGESTMAP_FOREACH_MODIFY(cached_v2_networkstatus, id, cached_dir_t *, dir) {
    if (dir->published < cutoff) {
      char *fname;
      fname = networkstatus_get_cache_filename(id);
      if (file_status(fname) == FN_FILE) {
        log_info(LD_DIR, "Removing too-old untrusted networkstatus in %s",
                 fname);
        unlink(fname);
      }
      tor_free(fname);
      cached_dir_decref(dir);
      MAP_DEL_CURRENT(id);
    }
  } DIGESTMAP_FOREACH_END
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dirserv_clear_old_v1_info ( time_t  now)

Remove any v1 info from the directory cache that was published too long ago.

Definition at line 1551 of file dirserv.c.

Here is the call graph for this function:

Here is the caller graph for this function:

int dirserv_dump_directory_to_string ( char **  dir_out,
crypto_pk_t private_key 
)

Generate a new v1 directory and write it into a newly allocated string.

Point *dir_out to the allocated string. Sign the directory with private_key. Return 0 on success, -1 on failure. If complete is set, give us all the descriptors; otherwise leave out non-running and non-valid ones.

Definition at line 1117 of file dirserv.c.

{
  char *cp;
  char *identity_pkey; /* Identity key, DER64-encoded. */
  char *recommended_versions;
  char digest[DIGEST_LEN];
  char published[ISO_TIME_LEN+1];
  char *buf = NULL;
  size_t buf_len;
  size_t identity_pkey_len;
  time_t now = time(NULL);

  tor_assert(dir_out);
  *dir_out = NULL;

  if (crypto_pk_write_public_key_to_string(private_key,&identity_pkey,
                                           &identity_pkey_len)<0) {
    log_warn(LD_BUG,"write identity_pkey to string failed!");
    return -1;
  }

  recommended_versions =
    format_versions_list(get_options()->RecommendedVersions);

  format_iso_time(published, now);

  buf_len = 2048+strlen(recommended_versions);

  buf = tor_malloc(buf_len);
  /* We'll be comparing against buf_len throughout the rest of the
     function, though strictly speaking we shouldn't be able to exceed
     it.  This is C, after all, so we may as well check for buffer
     overruns.*/

  tor_snprintf(buf, buf_len,
               "signed-directory\n"
               "published %s\n"
               "recommended-software %s\n"
               "router-status %s\n"
               "dir-signing-key\n%s\n",
               published, recommended_versions, "",
               identity_pkey);

  tor_free(recommended_versions);
  tor_free(identity_pkey);

  cp = buf + strlen(buf);
  *cp = '\0';

  /* These multiple strlcat calls are inefficient, but dwarfed by the RSA
     signature. */
  if (strlcat(buf, "directory-signature ", buf_len) >= buf_len)
    goto truncated;
  if (strlcat(buf, get_options()->Nickname, buf_len) >= buf_len)
    goto truncated;
  if (strlcat(buf, "\n", buf_len) >= buf_len)
    goto truncated;

  if (router_get_dir_hash(buf,digest)) {
    log_warn(LD_BUG,"couldn't compute digest");
    tor_free(buf);
    return -1;
  }
  note_crypto_pk_op(SIGN_DIR);
  if (router_append_dirobj_signature(buf,buf_len,digest,DIGEST_LEN,
                                     private_key)<0) {
    tor_free(buf);
    return -1;
  }

  *dir_out = buf;
  return 0;
 truncated:
  log_warn(LD_BUG,"tried to exceed string length.");
  tor_free(buf);
  return -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

size_t dirserv_estimate_data_size ( smartlist_t fps,
int  is_serverdescs,
int  compressed 
)

Return an approximate estimate of the number of bytes that will be needed to transmit the server descriptors (if is_serverdescs -- they can be either d/ or fp/ queries) or networkstatus objects (if !is_serverdescs) listed in fps.

If compressed is set, we guess how large the data will be after compression.

The return value is an estimate; it might be larger or smaller.

Definition at line 3513 of file dirserv.c.

{
  size_t result;
  tor_assert(fps);
  if (is_serverdescs) {
    int n = smartlist_len(fps);
    const routerinfo_t *me = router_get_my_routerinfo();
    result = (me?me->cache_info.signed_descriptor_len:2048) * n;
    if (compressed)
      result /= 2; /* observed compressibility is between 35 and 55%. */
  } else {
    result = 0;
    SMARTLIST_FOREACH(fps, const char *, digest, {
        cached_dir_t *dir = lookup_cached_dir_by_fp(digest);
        if (dir)
          result += compressed ? dir->dir_z_len : dir->dir_len;
      });
  }
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

size_t dirserv_estimate_microdesc_size ( const smartlist_t fps,
int  compressed 
)

Given a list of microdescriptor hashes, guess how many bytes will be needed to transmit them, and return the guess.

Definition at line 3538 of file dirserv.c.

{
  size_t result = smartlist_len(fps) * microdesc_average_size(NULL);
  if (compressed)
    result /= 2;
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dirserv_free_all ( void  )

Clear the current fingerprint list.

Definition at line 499 of file dirserv.c.

Here is the call graph for this function:

Here is the caller graph for this function:

cached_dir_t* dirserv_get_consensus ( const char *  flavor_name)

Return the latest downloaded consensus networkstatus in encoded, signed, optionally compressed format, suitable for sending to clients.

Definition at line 1705 of file dirserv.c.

{
  if (!cached_consensuses)
    return NULL;
  return strmap_get(cached_consensuses, flavor_name);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return the most recently generated encoded signed v1 directory, generating a new one as necessary.

If not a v1 authoritative directory may return NULL if no directory is yet cached.

Definition at line 1601 of file dirserv.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void dirserv_get_networkstatus_v2 ( smartlist_t result,
const char *  key 
)

Look for a network status object as specified by key, which should be either "authority" (to find a network status generated by us), a hex identity digest (to find a network status generated by given directory), or "all" (to return all the v2 network status objects we have).

Definition at line 3098 of file dirserv.c.

{
  cached_dir_t *cached;
  smartlist_t *fingerprints = smartlist_new();
  tor_assert(result);

  if (!cached_v2_networkstatus)
    cached_v2_networkstatus = digestmap_new();

  dirserv_get_networkstatus_v2_fingerprints(fingerprints, key);
  SMARTLIST_FOREACH(fingerprints, const char *, fp,
    {
      if (router_digest_is_me(fp) && should_generate_v2_networkstatus())
        generate_v2_networkstatus_opinion();
      cached = digestmap_get(cached_v2_networkstatus, fp);
      if (cached) {
        smartlist_add(result, cached);
      } else {
        char hexbuf[HEX_DIGEST_LEN+1];
        base16_encode(hexbuf, sizeof(hexbuf), fp, DIGEST_LEN);
        log_info(LD_DIRSERV, "Don't know about any network status with "
                 "fingerprint '%s'", hexbuf);
      }
    });
  SMARTLIST_FOREACH(fingerprints, char *, cp, tor_free(cp));
  smartlist_free(fingerprints);
}

Here is the call graph for this function:

void dirserv_get_networkstatus_v2_fingerprints ( smartlist_t result,
const char *  key 
)

Given the portion of a networkstatus request URL after "tor/status/" in key, append to result the digests of the identity keys of the networkstatus objects that the client has requested.

Definition at line 3047 of file dirserv.c.

{
  tor_assert(result);

  if (!cached_v2_networkstatus)
    cached_v2_networkstatus = digestmap_new();

  if (should_generate_v2_networkstatus())
    generate_v2_networkstatus_opinion();

  if (!strcmp(key,"authority")) {
    if (authdir_mode_v2(get_options())) {
      const routerinfo_t *me = router_get_my_routerinfo();
      if (me)
        smartlist_add(result,
                      tor_memdup(me->cache_info.identity_digest, DIGEST_LEN));
    }
  } else if (!strcmp(key, "all")) {
    if (digestmap_size(cached_v2_networkstatus)) {
      digestmap_iter_t *iter;
      iter = digestmap_iter_init(cached_v2_networkstatus);
      while (!digestmap_iter_done(iter)) {
        const char *ident;
        void *val;
        digestmap_iter_get(iter, &ident, &val);
        smartlist_add(result, tor_memdup(ident, DIGEST_LEN));
        iter = digestmap_iter_next(cached_v2_networkstatus, iter);
      }
    } else {
      SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
                  trusted_dir_server_t *, ds,
                  if (ds->type & V2_DIRINFO)
                    smartlist_add(result, tor_memdup(ds->digest, DIGEST_LEN)));
    }
    smartlist_sort_digests(result);
    if (smartlist_len(result) == 0)
      log_info(LD_DIRSERV,
               "Client requested 'all' network status objects; we have none.");
  } else if (!strcmpstart(key, "fp/")) {
    dir_split_resource_into_fingerprints(key+3, result, NULL,
                                         DSR_HEX|DSR_SORT_UNIQ);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

const char* dirserv_get_nickname_by_digest ( const char *  digest)

If we are an authoritative dirserver, and the list of approved servers contains one whose identity key digest is digest, return that router's nickname.

Otherwise return NULL.

Definition at line 486 of file dirserv.c.

{
  router_status_t *status;
  if (!fingerprint_list)
    return NULL;
  tor_assert(digest);

  status = digestmap_get(fingerprint_list->status_by_digest, digest);
  return status ? status->nickname : NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int dirserv_get_routerdesc_fingerprints ( smartlist_t fps_out,
const char *  key,
const char **  msg,
int  for_unencrypted_conn,
int  is_extrainfo 
)

As dirserv_get_routerdescs(), but instead of getting signed_descriptor_t pointers, adds copies of digests to fps_out, and doesn't use the /tor/server/ prefix.

For a /d/ request, adds descriptor digests; for other requests, adds identity digests.

Definition at line 3133 of file dirserv.c.

{
  int by_id = 1;
  *msg = NULL;

  if (!strcmp(key, "all")) {
    routerlist_t *rl = router_get_routerlist();
    SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r,
                      smartlist_add(fps_out,
                      tor_memdup(r->cache_info.identity_digest, DIGEST_LEN)));
    /* Treat "all" requests as if they were unencrypted */
    for_unencrypted_conn = 1;
  } else if (!strcmp(key, "authority")) {
    const routerinfo_t *ri = router_get_my_routerinfo();
    if (ri)
      smartlist_add(fps_out,
                    tor_memdup(ri->cache_info.identity_digest, DIGEST_LEN));
  } else if (!strcmpstart(key, "d/")) {
    by_id = 0;
    key += strlen("d/");
    dir_split_resource_into_fingerprints(key, fps_out, NULL,
                                         DSR_HEX|DSR_SORT_UNIQ);
  } else if (!strcmpstart(key, "fp/")) {
    key += strlen("fp/");
    dir_split_resource_into_fingerprints(key, fps_out, NULL,
                                         DSR_HEX|DSR_SORT_UNIQ);
  } else {
    *msg = "Key not recognized";
    return -1;
  }

  if (for_unencrypted_conn) {
    /* Remove anything that insists it not be sent unencrypted. */
    SMARTLIST_FOREACH_BEGIN(fps_out, char *, cp) {
        const signed_descriptor_t *sd;
        if (by_id)
          sd = get_signed_descriptor_by_fp(cp,is_extrainfo,0);
        else if (is_extrainfo)
          sd = extrainfo_get_by_descriptor_digest(cp);
        else
          sd = router_get_by_descriptor_digest(cp);
        if (sd && !sd->send_unencrypted) {
          tor_free(cp);
          SMARTLIST_DEL_CURRENT(fps_out, cp);
        }
    } SMARTLIST_FOREACH_END(cp);
  }

  if (!smartlist_len(fps_out)) {
    *msg = "Servers unavailable";
    return -1;
  }
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int dirserv_get_routerdescs ( smartlist_t descs_out,
const char *  key,
const char **  msg 
)

Add a signed_descriptor_t to descs_out for each router matching key.

The key should be either

  • "/tor/server/authority" for our own routerinfo;
  • "/tor/server/all" for all the routerinfos we have, concatenated;
  • "/tor/server/fp/FP" where FP is a plus-separated sequence of hex identity digests; or
  • "/tor/server/d/D" where D is a plus-separated sequence of server descriptor digests, in hex.

Return 0 if we found some matching descriptors, or -1 if we do not have any descriptors, no matching descriptors, or if we did not recognize the key (URL). If -1 is returned *msg will be set to an appropriate error message.

XXXX rename this function. It's only called from the controller. XXXX in fact, refactor this function, merging as much as possible.

Definition at line 3209 of file dirserv.c.

{
  *msg = NULL;

  if (!strcmp(key, "/tor/server/all")) {
    routerlist_t *rl = router_get_routerlist();
    SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r,
                      smartlist_add(descs_out, &(r->cache_info)));
  } else if (!strcmp(key, "/tor/server/authority")) {
    const routerinfo_t *ri = router_get_my_routerinfo();
    if (ri)
      smartlist_add(descs_out, (void*) &(ri->cache_info));
  } else if (!strcmpstart(key, "/tor/server/d/")) {
    smartlist_t *digests = smartlist_new();
    key += strlen("/tor/server/d/");
    dir_split_resource_into_fingerprints(key, digests, NULL,
                                         DSR_HEX|DSR_SORT_UNIQ);
    SMARTLIST_FOREACH(digests, const char *, d,
       {
         signed_descriptor_t *sd = router_get_by_descriptor_digest(d);
         if (sd)
           smartlist_add(descs_out,sd);
       });
    SMARTLIST_FOREACH(digests, char *, d, tor_free(d));
    smartlist_free(digests);
  } else if (!strcmpstart(key, "/tor/server/fp/")) {
    smartlist_t *digests = smartlist_new();
    time_t cutoff = time(NULL) - ROUTER_MAX_AGE_TO_PUBLISH;
    key += strlen("/tor/server/fp/");
    dir_split_resource_into_fingerprints(key, digests, NULL,
                                         DSR_HEX|DSR_SORT_UNIQ);
    SMARTLIST_FOREACH(digests, const char *, d,
       {
         if (router_digest_is_me(d)) {
           /* make sure desc_routerinfo exists */
           const routerinfo_t *ri = router_get_my_routerinfo();
           if (ri)
             smartlist_add(descs_out, (void*) &(ri->cache_info));
         } else {
           const routerinfo_t *ri = router_get_by_id_digest(d);
           /* Don't actually serve a descriptor that everyone will think is
            * expired.  This is an (ugly) workaround to keep buggy 0.1.1.10
            * Tors from downloading descriptors that they will throw away.
            */
           if (ri && ri->cache_info.published_on > cutoff)
             smartlist_add(descs_out, (void*) &(ri->cache_info));
         }
       });
    SMARTLIST_FOREACH(digests, char *, d, tor_free(d));
    smartlist_free(digests);
  } else {
    *msg = "Key not recognized";
    return -1;
  }

  if (!smartlist_len(descs_out)) {
    *msg = "Servers unavailable";
    return -1;
  }
  return 0;
}

Here is the call graph for this function:

Set *rr to the most recently generated encoded signed running-routers list, generating a new one as necessary.

Return the size of the directory on success, and 0 on failure.

Definition at line 1693 of file dirserv.c.

Here is the call graph for this function:

Here is the caller graph for this function:

Return true iff any of the 256-bit elements in fps is the digest of a microdescriptor we have.

Definition at line 3495 of file dirserv.c.

{
  microdesc_cache_t *cache = get_microdesc_cache();
  SMARTLIST_FOREACH(fps, const char *, fp,
                    if (microdesc_cache_lookup_by_digest256(cache, fp))
                      return 1);
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int dirserv_have_any_serverdesc ( smartlist_t fps,
int  spool_src 
)

Return true iff we have any of the documents (extrainfo or routerdesc) specified by the fingerprints in fps and spool_src.

Used to decide whether to send a 404.

Definition at line 3469 of file dirserv.c.

{
  time_t publish_cutoff = time(NULL)-ROUTER_MAX_AGE_TO_PUBLISH;
  SMARTLIST_FOREACH(fps, const char *, fp, {
      switch (spool_src)
      {
        case DIR_SPOOL_EXTRA_BY_DIGEST:
          if (extrainfo_get_by_descriptor_digest(fp)) return 1;
          break;
        case DIR_SPOOL_SERVER_BY_DIGEST:
          if (router_get_by_descriptor_digest(fp)) return 1;
          break;
        case DIR_SPOOL_EXTRA_BY_FP:
        case DIR_SPOOL_SERVER_BY_FP:
          if (get_signed_descriptor_by_fp(fp,
                spool_src == DIR_SPOOL_EXTRA_BY_FP, publish_cutoff))
            return 1;
          break;
      }
  });
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Load the nickname->fingerprint mappings stored in the approved-routers file.

The file format is line-based, with each non-blank holding one nickname, some space, and a fingerprint for that nickname. On success, replace the current fingerprint list with the new list and return 0. On failure, leave the current fingerprint list untouched, and return -1.

Definition at line 207 of file dirserv.c.

{
  char *fname;
  char *cf;
  char *nickname, *fingerprint;
  authdir_config_t *fingerprint_list_new;
  int result;
  config_line_t *front=NULL, *list;
  const or_options_t *options = get_options();

  fname = get_datadir_fname("approved-routers");
  log_info(LD_GENERAL,
           "Reloading approved fingerprints from \"%s\"...", fname);

  cf = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL);
  if (!cf) {
    if (options->NamingAuthoritativeDir) {
      log_warn(LD_FS, "Cannot open fingerprint file '%s'. Failing.", fname);
      tor_free(fname);
      return -1;
    } else {
      log_info(LD_FS, "Cannot open fingerprint file '%s'. That's ok.", fname);
      tor_free(fname);
      return 0;
    }
  }
  tor_free(fname);

  result = config_get_lines(cf, &front, 0);
  tor_free(cf);
  if (result < 0) {
    log_warn(LD_CONFIG, "Error reading from fingerprint file");
    return -1;
  }

  fingerprint_list_new = authdir_config_new();

  for (list=front; list; list=list->next) {
    char digest_tmp[DIGEST_LEN];
    nickname = list->key; fingerprint = list->value;
    if (strlen(nickname) > MAX_NICKNAME_LEN) {
      log_notice(LD_CONFIG,
                 "Nickname '%s' too long in fingerprint file. Skipping.",
                 nickname);
      continue;
    }
    if (!is_legal_nickname(nickname) &&
        strcasecmp(nickname, "!reject") &&
        strcasecmp(nickname, "!invalid") &&
        strcasecmp(nickname, "!badexit")) {
      log_notice(LD_CONFIG,
                 "Invalid nickname '%s' in fingerprint file. Skipping.",
                 nickname);
      continue;
    }
    tor_strstrip(fingerprint, " "); /* remove spaces */
    if (strlen(fingerprint) != HEX_DIGEST_LEN ||
        base16_decode(digest_tmp, sizeof(digest_tmp),
                      fingerprint, HEX_DIGEST_LEN) < 0) {
      log_notice(LD_CONFIG,
                 "Invalid fingerprint (nickname '%s', "
                 "fingerprint %s). Skipping.",
                 nickname, fingerprint);
      continue;
    }
    if (0==strcasecmp(nickname, DEFAULT_CLIENT_NICKNAME)) {
      /* If you approved an OR called "client", then clients who use
       * the default nickname could all be rejected.  That's no good. */
      log_notice(LD_CONFIG,
                 "Authorizing nickname '%s' would break "
                 "many clients; skipping.",
                 DEFAULT_CLIENT_NICKNAME);
      continue;
    }
    if (0==strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) {
      /* If you approved an OR called "unnamed", then clients will be
       * confused. */
      log_notice(LD_CONFIG,
                 "Authorizing nickname '%s' is not allowed; skipping.",
                 UNNAMED_ROUTER_NICKNAME);
      continue;
    }
    if (add_fingerprint_to_dir(nickname, fingerprint, fingerprint_list_new)
        != 0)
      log_notice(LD_CONFIG, "Duplicate nickname '%s'.", nickname);
  }

  config_free_lines(front);
  dirserv_free_fingerprint_list();
  fingerprint_list = fingerprint_list_new;
  /* Delete any routers whose fingerprints we no longer recognize */
  directory_remove_invalid();
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dirserv_orconn_tls_done ( const char *  address,
uint16_t  or_port,
const char *  digest_rcvd 
)

Called when a TLS handshake has completed successfully with a router listening at address:or_port, and has yielded a certificate with digest digest_rcvd.

Inform the reachability checker that we could get to this guy.

Definition at line 3279 of file dirserv.c.

{
  routerinfo_t *ri;
  time_t now = time(NULL);
  tor_assert(address);
  tor_assert(digest_rcvd);

  ri = router_get_mutable_by_digest(digest_rcvd);

  if (ri == NULL)
    return;

  if (!strcasecmp(address, ri->address) && or_port == ri->or_port) {
    /* Found the right router.  */
    if (!authdir_mode_bridge(get_options()) ||
        ri->purpose == ROUTER_PURPOSE_BRIDGE) {
      /* This is a bridge or we're not a bridge authorititative --
         mark it as reachable.  */
      tor_addr_t addr, *addrp=NULL;
      log_info(LD_DIRSERV, "Found router %s to be reachable at %s:%d. Yay.",
               router_describe(ri),
               address, ri->or_port);
      if (tor_addr_parse(&addr, ri->address) != -1)
        addrp = &addr;
      else
        log_warn(LD_BUG, "Couldn't parse IP address \"%s\"", ri->address);
      rep_hist_note_router_reachable(digest_rcvd, addrp, or_port, now);
      ri->last_reachable = now;
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

int dirserv_read_measured_bandwidths ( const char *  from_file,
smartlist_t routerstatuses 
)

Read the measured bandwidth file and apply it to the list of routerstatuses.

Returns -1 on error, 0 otherwise.

Definition at line 2588 of file dirserv.c.

{
  char line[256];
  FILE *fp = tor_fopen_cloexec(from_file, "r");
  int applied_lines = 0;
  time_t file_time;
  int ok;
  if (fp == NULL) {
    log_warn(LD_CONFIG, "Can't open bandwidth file at configured location: %s",
             from_file);
    return -1;
  }

  if (!fgets(line, sizeof(line), fp)
          || !strlen(line) || line[strlen(line)-1] != '\n') {
    log_warn(LD_DIRSERV, "Long or truncated time in bandwidth file: %s",
             escaped(line));
    fclose(fp);
    return -1;
  }

  line[strlen(line)-1] = '\0';
  file_time = tor_parse_ulong(line, 10, 0, ULONG_MAX, &ok, NULL);
  if (!ok) {
    log_warn(LD_DIRSERV, "Non-integer time in bandwidth file: %s",
             escaped(line));
    fclose(fp);
    return -1;
  }

  if ((time(NULL) - file_time) > MAX_MEASUREMENT_AGE) {
    log_warn(LD_DIRSERV, "Bandwidth measurement file stale. Age: %u",
             (unsigned)(time(NULL) - file_time));
    fclose(fp);
    return -1;
  }

  if (routerstatuses)
    smartlist_sort(routerstatuses, compare_routerstatus_entries);

  while (!feof(fp)) {
    measured_bw_line_t parsed_line;
    if (fgets(line, sizeof(line), fp) && strlen(line)) {
      if (measured_bw_line_parse(&parsed_line, line) != -1) {
        if (measured_bw_line_apply(&parsed_line, routerstatuses) > 0)
          applied_lines++;
      }
    }
  }

  fclose(fp);
  log_info(LD_DIRSERV,
           "Bandwidth measurement file successfully read. "
           "Applied %d measurements.", applied_lines);
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int dirserv_remove_old_statuses ( smartlist_t fps,
time_t  cutoff 
)

Remove from fps every networkstatus key where both a) we have a networkstatus document and b) it is not newer than cutoff.

Return 1 if any items were present at all; else return 0.

Definition at line 3420 of file dirserv.c.

{
  int found_any = 0;
  SMARTLIST_FOREACH(fps, char *, digest,
  {
    cached_dir_t *d = lookup_cached_dir_by_fp(digest);
    if (!d)
      continue;
    found_any = 1;
    if (d->published <= cutoff) {
      tor_free(digest);
      SMARTLIST_DEL_CURRENT(fps, digest);
    }
  });

  return found_any;
}

Here is the call graph for this function:

Here is the caller graph for this function:

uint32_t dirserv_router_get_status ( const routerinfo_t router,
const char **  msg 
)

Check whether router has a nickname/identity key combination that we recognize from the fingerprint list, or an IP we automatically act on according to our configuration.

Return the appropriate router status.

If the status is 'FP_REJECT' and msg is provided, set *msg to an explanation of why.

Definition at line 309 of file dirserv.c.

{
  char d[DIGEST_LEN];

  if (crypto_pk_get_digest(router->identity_pkey, d)) {
    log_warn(LD_BUG,"Error computing fingerprint");
    if (msg)
      *msg = "Bug: Error computing fingerprint";
    return FP_REJECT;
  }

  return dirserv_get_status_impl(d, router->nickname,
                                 router->address,
                                 router->addr, router->or_port,
                                 router->platform, router->contact_info,
                                 msg, 1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dirserv_set_cached_consensus_networkstatus ( const char *  networkstatus,
const char *  flavor_name,
const digests_t digests,
time_t  published 
)

Replace the v3 consensus networkstatus of type flavor_name that we're serving with networkstatus, published at published.

No validation is performed.

Definition at line 1506 of file dirserv.c.

{
  cached_dir_t *new_networkstatus;
  cached_dir_t *old_networkstatus;
  if (!cached_consensuses)
    cached_consensuses = strmap_new();

  new_networkstatus = new_cached_dir(tor_strdup(networkstatus), published);
  memcpy(&new_networkstatus->digests, digests, sizeof(digests_t));
  old_networkstatus = strmap_set(cached_consensuses, flavor_name,
                                 new_networkstatus);
  if (old_networkstatus)
    cached_dir_decref(old_networkstatus);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dirserv_set_cached_directory ( const char *  directory,
time_t  published,
int  is_running_routers 
)

If we have no cached v1 directory, or it is older than published, then replace it with directory, published at published.

If published is too old, do nothing.

If is_running_routers, this is really a v1 running_routers document rather than a v1 directory.

Definition at line 1421 of file dirserv.c.

{
  time_t now = time(NULL);

  if (is_running_routers) {
    if (published >= now - MAX_V1_RR_AGE)
      set_cached_dir(&cached_runningrouters, tor_strdup(directory), published);
  } else {
    if (published >= now - MAX_V1_DIRECTORY_AGE) {
      cached_dir_decref(cached_directory);
      cached_directory = new_cached_dir(tor_strdup(directory), published);
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dirserv_set_cached_networkstatus_v2 ( const char *  networkstatus,
const char *  identity,
time_t  published 
)

If networkstatus is non-NULL, we've just received a v2 network-status for an authoritative directory with identity digest identity published at published -- store it so we can serve it to others.

If networkstatus is NULL, remove the entry with the given identity fingerprint from the v2 cache.

Definition at line 1446 of file dirserv.c.

{
  cached_dir_t *d, *old_d;
  smartlist_t *trusted_dirs;
  if (!cached_v2_networkstatus)
    cached_v2_networkstatus = digestmap_new();

  old_d = digestmap_get(cached_v2_networkstatus, identity);
  if (!old_d && !networkstatus)
    return;

  if (networkstatus) {
    if (!old_d || published > old_d->published) {
      d = new_cached_dir(tor_strdup(networkstatus), published);
      digestmap_set(cached_v2_networkstatus, identity, d);
      if (old_d)
        cached_dir_decref(old_d);
    }
  } else {
    if (old_d) {
      digestmap_remove(cached_v2_networkstatus, identity);
      cached_dir_decref(old_d);
    }
  }

  /* Now purge old entries. */
  trusted_dirs = router_get_trusted_dir_servers();
  if (digestmap_size(cached_v2_networkstatus) >
      smartlist_len(trusted_dirs) + MAX_UNTRUSTED_NETWORKSTATUSES) {
    /* We need to remove the oldest untrusted networkstatus. */
    const char *oldest = NULL;
    time_t oldest_published = TIME_MAX;
    digestmap_iter_t *iter;

    for (iter = digestmap_iter_init(cached_v2_networkstatus);
         !digestmap_iter_done(iter);
         iter = digestmap_iter_next(cached_v2_networkstatus, iter)) {
      const char *ident;
      void *val;
      digestmap_iter_get(iter, &ident, &val);
      d = val;
      if (d->published < oldest_published &&
          !router_digest_is_trusted_dir(ident)) {
        oldest = ident;
        oldest_published = d->published;
      }
    }
    tor_assert(oldest);
    d = digestmap_remove(cached_v2_networkstatus, oldest);
    if (d)
      cached_dir_decref(d);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dirserv_set_node_flags_from_authoritative_status ( node_t node,
uint32_t  authstatus 
)

Update the relevant flags of node based on our opinion as a directory authority in authstatus, as returned by dirserv_router_get_status or equivalent.

Definition at line 600 of file dirserv.c.

{
  node->is_valid = (authstatus & FP_INVALID) ? 0 : 1;
  node->is_bad_directory = (authstatus & FP_BADDIR) ? 1 : 0;
  node->is_bad_exit = (authstatus & FP_BADEXIT) ? 1 : 0;
}

Here is the caller graph for this function:

void dirserv_set_router_is_running ( routerinfo_t router,
time_t  now 
)

Treat a router as alive if.

  • It's me, and I'm not hibernating. or - We've found it reachable recently.

Definition at line 976 of file dirserv.c.

{
  /*XXXX024 This function is a mess.  Separate out the part that calculates
    whether it's reachable and the part that tells rephist that the router was
    unreachable.
   */
  int answer;
  node_t *node = node_get_mutable_by_id(router->cache_info.identity_digest);
  tor_assert(node);

  if (router_is_me(router)) {
    /* We always know if we are down ourselves. */
    answer = ! we_are_hibernating();
  } else if (router->is_hibernating &&
             (router->cache_info.published_on +
              HIBERNATION_PUBLICATION_SKEW) > router->last_reachable) {
    /* A hibernating router is down unless we (somehow) had contact with it
     * since it declared itself to be hibernating. */
    answer = 0;
  } else if (get_options()->AssumeReachable) {
    /* If AssumeReachable, everybody is up unless they say they are down! */
    answer = 1;
  } else {
    /* Otherwise, a router counts as up if we found it reachable in the last
       REACHABLE_TIMEOUT seconds. */
    answer = (now < router->last_reachable + REACHABLE_TIMEOUT);
  }

  if (!answer && running_long_enough_to_decide_unreachable()) {
    /* Not considered reachable. tell rephist about that.

       Because we launch a reachability test for each router every
       REACHABILITY_TEST_CYCLE_PERIOD seconds, then the router has probably
       been down since at least that time after we last successfully reached
       it.
     */
    time_t when = now;
    if (router->last_reachable &&
        router->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD < now)
      when = router->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD;
    rep_hist_note_router_unreachable(router->cache_info.identity_digest, when);
  }

  node->is_running = answer;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int dirserv_should_launch_reachability_test ( const routerinfo_t ri,
const routerinfo_t ri_old 
)

Called when we, as an authority, receive a new router descriptor either as an upload or a download.

Used to decide whether to relaunch reachability testing for the server.

Definition at line 3317 of file dirserv.c.

{
  if (!authdir_mode_handles_descs(get_options(), ri->purpose))
    return 0;
  if (!ri_old) {
    /* New router: Launch an immediate reachability test, so we will have an
     * opinion soon in case we're generating a consensus soon */
    return 1;
  }
  if (ri_old->is_hibernating && !ri->is_hibernating) {
    /* It just came out of hibernation; launch a reachability test */
    return 1;
  }
  if (! routers_have_same_or_addr(ri, ri_old)) {
    /* Address or port changed; launch a reachability test */
    return 1;
  }
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dirserv_single_reachability_test ( time_t  now,
routerinfo_t router 
)

Helper function for dirserv_test_reachability().

Start a TLS connection to router, and annotate it with when we started the test.

Definition at line 3342 of file dirserv.c.

{
  tor_addr_t router_addr;
  log_debug(LD_OR,"Testing reachability of %s at %s:%u.",
            router->nickname, router->address, router->or_port);
  /* Remember when we started trying to determine reachability */
  if (!router->testing_since)
    router->testing_since = now;
  tor_addr_from_ipv4h(&router_addr, router->addr);
  connection_or_connect(&router_addr, router->or_port,
                        router->cache_info.identity_digest);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dirserv_test_reachability ( time_t  now)

Auth dir server only: load balance such that we only try a few connections per call.

The load balancing is such that if we get called once every ten seconds, we will cycle through all the tests in REACHABILITY_TEST_CYCLE_PERIOD seconds (a bit over 20 minutes).

Definition at line 3363 of file dirserv.c.

{
  /* XXX decide what to do here; see or-talk thread "purging old router
   * information, revocation." -NM
   * We can't afford to mess with this in 0.1.2.x. The reason is that
   * if we stop doing reachability tests on some of routerlist, then
   * we'll for-sure think they're down, which may have unexpected
   * effects in other parts of the code. It doesn't hurt much to do
   * the testing, and directory authorities are easy to upgrade. Let's
   * wait til 0.2.0. -RD */
//  time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH;
  routerlist_t *rl = router_get_routerlist();
  static char ctr = 0;
  int bridge_auth = authdir_mode_bridge(get_options());

  SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, router) {
    const char *id_digest = router->cache_info.identity_digest;
    if (router_is_me(router))
      continue;
    if (bridge_auth && router->purpose != ROUTER_PURPOSE_BRIDGE)
      continue; /* bridge authorities only test reachability on bridges */
//    if (router->cache_info.published_on > cutoff)
//      continue;
    if ((((uint8_t)id_digest[0]) % REACHABILITY_MODULO_PER_TEST) == ctr) {
      dirserv_single_reachability_test(now, router);
    }
  } SMARTLIST_FOREACH_END(router);
  ctr = (ctr + 1) % REACHABILITY_MODULO_PER_TEST; /* increment ctr */
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return true if there is no point in downloading the router described by rs because this directory would reject it.

Definition at line 330 of file dirserv.c.

{
  uint32_t res;

  res = dirserv_get_status_impl(rs->identity_digest, rs->nickname,
                                "", /* address is only used in logs */
                                rs->addr, rs->or_port,
                                NULL, NULL,
                                NULL, 0);

  return (res & FP_REJECT) != 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int list_server_status_v1 ( smartlist_t routers,
char **  router_status_out,
int  for_controller 
)

Based on the routerinfo_ts in routers, allocate the contents of a v1-style router-status line, and store it in *router_status_out.

Return 0 on success, -1 on failure.

If for_controller is true, include the routers with very old descriptors.

Definition at line 1029 of file dirserv.c.

{
  /* List of entries in a router-status style: An optional !, then an optional
   * equals-suffixed nickname, then a dollar-prefixed hexdigest. */
  smartlist_t *rs_entries;
  time_t now = time(NULL);
  time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH;
  const or_options_t *options = get_options();
  /* We include v2 dir auths here too, because they need to answer
   * controllers. Eventually we'll deprecate this whole function;
   * see also networkstatus_getinfo_by_purpose(). */
  int authdir = authdir_mode_publishes_statuses(options);
  tor_assert(router_status_out);

  rs_entries = smartlist_new();

  SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) {
    const node_t *node = node_get_by_id(ri->cache_info.identity_digest);
    tor_assert(node);
    if (authdir) {
      /* Update router status in routerinfo_t. */
      dirserv_set_router_is_running(ri, now);
    }
    if (for_controller) {
      char name_buf[MAX_VERBOSE_NICKNAME_LEN+2];
      char *cp = name_buf;
      if (!node->is_running)
        *cp++ = '!';
      router_get_verbose_nickname(cp, ri);
      smartlist_add(rs_entries, tor_strdup(name_buf));
    } else if (ri->cache_info.published_on >= cutoff) {
      smartlist_add(rs_entries, list_single_server_status(ri,
                                                          node->is_running));
    }
  } SMARTLIST_FOREACH_END(ri);

  *router_status_out = smartlist_join_strings(rs_entries, " ", 0, NULL);

  SMARTLIST_FOREACH(rs_entries, char *, cp, tor_free(cp));
  smartlist_free(rs_entries);

  return 0;
}

Here is the call graph for this function:

cached_dir_t* new_cached_dir ( char *  s,
time_t  published 
)

Allocate and return a new cached_dir_t containing the string s, published at published.

Definition at line 1377 of file dirserv.c.

{
  cached_dir_t *d = tor_malloc_zero(sizeof(cached_dir_t));
  d->refcnt = 1;
  d->dir = s;
  d->dir_len = strlen(s);
  d->published = published;
  if (tor_gzip_compress(&(d->dir_z), &(d->dir_z_len), d->dir, d->dir_len,
                        ZLIB_METHOD)) {
    log_warn(LD_BUG, "Error compressing directory");
  }
  return d;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int routerstatus_format_entry ( char *  buf,
size_t  buf_len,
const routerstatus_t rs,
const char *  version,
routerstatus_format_type_t  format 
)

Helper: write the router-status information in rs into buf, which has at least buf_len free characters.

Do NUL-termination. Use the same format as in network-status documents. If version is non-NULL, add a "v" line for the platform. Return 0 on success, -1 on failure.

The format argument has three possible values: NS_V2 - Output an entry suitable for a V2 NS opinion document NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry NS_V3_CONSENSUS_MICRODESC - Output the first portion of a V3 microdesc consensus entry. NS_V3_VOTE - Output a complete V3 NS vote NS_CONTROL_PORT - Output a NS document for the control port

Definition at line 2052 of file dirserv.c.

{
  int r;
  char *cp;
  char *summary;

  char published[ISO_TIME_LEN+1];
  char identity64[BASE64_DIGEST_LEN+1];
  char digest64[BASE64_DIGEST_LEN+1];

  format_iso_time(published, rs->published_on);
  digest_to_base64(identity64, rs->identity_digest);
  digest_to_base64(digest64, rs->descriptor_digest);

  r = tor_snprintf(buf, buf_len,
                   "r %s %s %s%s%s %s %d %d\n",
                   rs->nickname,
                   identity64,
                   (format==NS_V3_CONSENSUS_MICRODESC)?"":digest64,
                   (format==NS_V3_CONSENSUS_MICRODESC)?"":" ",
                   published,
                   fmt_addr32(rs->addr),
                   (int)rs->or_port,
                   (int)rs->dir_port);
  if (r<0) {
    log_warn(LD_BUG, "Not enough space in buffer.");
    return -1;
  }

  /* TODO: Maybe we want to pass in what we need to build the rest of
   * this here, instead of in the caller. Then we could use the
   * networkstatus_type_t values, with an additional control port value
   * added -MP */
  if (format == NS_V3_CONSENSUS || format == NS_V3_CONSENSUS_MICRODESC)
    return 0;

  cp = buf + strlen(buf);
  /* NOTE: Whenever this list expands, be sure to increase MAX_FLAG_LINE_LEN*/
  r = tor_snprintf(cp, buf_len - (cp-buf),
                   "s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
                  /* These must stay in alphabetical order. */
                   rs->is_authority?" Authority":"",
                   rs->is_bad_directory?" BadDirectory":"",
                   rs->is_bad_exit?" BadExit":"",
                   rs->is_exit?" Exit":"",
                   rs->is_fast?" Fast":"",
                   rs->is_possible_guard?" Guard":"",
                   rs->is_hs_dir?" HSDir":"",
                   rs->is_named?" Named":"",
                   rs->is_flagged_running?" Running":"",
                   rs->is_stable?" Stable":"",
                   rs->is_unnamed?" Unnamed":"",
                   rs->is_v2_dir?" V2Dir":"",
                   rs->is_valid?" Valid":"");
  if (r<0) {
    log_warn(LD_BUG, "Not enough space in buffer.");
    return -1;
  }
  cp += strlen(cp);

  /* length of "opt v \n" */
#define V_LINE_OVERHEAD 7
  if (version && strlen(version) < MAX_V_LINE_LEN - V_LINE_OVERHEAD) {
    if (tor_snprintf(cp, buf_len - (cp-buf), "opt v %s\n", version)<0) {
      log_warn(LD_BUG, "Unable to print router version.");
      return -1;
    }
    cp += strlen(cp);
  }

  if (format != NS_V2) {
    const routerinfo_t* desc = router_get_by_id_digest(rs->identity_digest);
    uint32_t bw;

    if (format != NS_CONTROL_PORT) {
      /* Blow up more or less nicely if we didn't get anything or not the
       * thing we expected.
       */
      if (!desc) {
        char id[HEX_DIGEST_LEN+1];
        char dd[HEX_DIGEST_LEN+1];

        base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
        base16_encode(dd, sizeof(dd), rs->descriptor_digest, DIGEST_LEN);
        log_warn(LD_BUG, "Cannot get any descriptor for %s "
            "(wanted descriptor %s).",
            id, dd);
        return -1;
      };

      /* This assert can fire for the control port, because
       * it can request NS documents before all descriptors
       * have been fetched. */
      if (tor_memneq(desc->cache_info.signed_descriptor_digest,
            rs->descriptor_digest,
            DIGEST_LEN)) {
        char rl_d[HEX_DIGEST_LEN+1];
        char rs_d[HEX_DIGEST_LEN+1];
        char id[HEX_DIGEST_LEN+1];

        base16_encode(rl_d, sizeof(rl_d),
            desc->cache_info.signed_descriptor_digest, DIGEST_LEN);
        base16_encode(rs_d, sizeof(rs_d), rs->descriptor_digest, DIGEST_LEN);
        base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
        log_err(LD_BUG, "descriptor digest in routerlist does not match "
            "the one in routerstatus: %s vs %s "
            "(router %s)\n",
            rl_d, rs_d, id);

        tor_assert(tor_memeq(desc->cache_info.signed_descriptor_digest,
              rs->descriptor_digest,
              DIGEST_LEN));
      };
    }

    if (format == NS_CONTROL_PORT && rs->has_bandwidth) {
      bw = rs->bandwidth;
    } else {
      tor_assert(desc);
      bw = router_get_advertised_bandwidth_capped(desc) / 1000;
    }
    r = tor_snprintf(cp, buf_len - (cp-buf),
                     "w Bandwidth=%d\n", bw);

    if (r<0) {
      log_warn(LD_BUG, "Not enough space in buffer.");
      return -1;
    }
    cp += strlen(cp);
    if (format == NS_V3_VOTE && rs->has_measured_bw) {
      *--cp = '\0'; /* Kill "\n" */
      r = tor_snprintf(cp, buf_len - (cp-buf),
                       " Measured=%d\n", rs->measured_bw);
      if (r<0) {
        log_warn(LD_BUG, "Not enough space in buffer for weight line.");
        return -1;
      }
      cp += strlen(cp);
    }

    if (desc) {
      summary = policy_summarize(desc->exit_policy);
      r = tor_snprintf(cp, buf_len - (cp-buf), "p %s\n", summary);
      if (r<0) {
        log_warn(LD_BUG, "Not enough space in buffer.");
        tor_free(summary);
        return -1;
      }
      cp += strlen(cp);
      tor_free(summary);
    }
  }

  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function: