[tor-commits] [tor/release-0.2.2] Merge remote branch 'origin/maint-0.2.1' into maint-0.2.2

arma at torproject.org arma at torproject.org
Mon Mar 14 21:22:02 UTC 2011


commit b97d9abd0940037b249a1ee56724dbfed904263b
Merge: 0588330 1a9d19e
Author: Nick Mathewson <nickm at torproject.org>
Date:   Mon Mar 14 17:04:53 2011 -0400

    Merge remote branch 'origin/maint-0.2.1' into maint-0.2.2

 changes/bug1172 |    9 +++++++++
 src/or/router.c |   20 +++++---------------
 2 files changed, 14 insertions(+), 15 deletions(-)

diff --combined src/or/router.c
index 4c5eb7a,ba7be3d..c15b9b2
--- a/src/or/router.c
+++ b/src/or/router.c
@@@ -7,24 -7,6 +7,24 @@@
  #define ROUTER_PRIVATE
  
  #include "or.h"
 +#include "circuitlist.h"
 +#include "circuituse.h"
 +#include "config.h"
 +#include "connection.h"
 +#include "control.h"
 +#include "directory.h"
 +#include "dirserv.h"
 +#include "dns.h"
 +#include "geoip.h"
 +#include "hibernate.h"
 +#include "main.h"
 +#include "networkstatus.h"
 +#include "policies.h"
 +#include "relay.h"
 +#include "rephist.h"
 +#include "router.h"
 +#include "routerlist.h"
 +#include "routerparse.h"
  
  /**
   * \file router.c
@@@ -49,15 -31,11 +49,15 @@@ static crypto_pk_env_t *onionkey=NULL
  /** Previous private onionskin decryption key: used to decode CREATE cells
   * generated by clients that have an older version of our descriptor. */
  static crypto_pk_env_t *lastonionkey=NULL;
 -/** Private "identity key": used to sign directory info and TLS
 +/** Private server "identity key": used to sign directory info and TLS
   * certificates. Never changes. */
 -static crypto_pk_env_t *identitykey=NULL;
 -/** Digest of identitykey. */
 -static char identitykey_digest[DIGEST_LEN];
 +static crypto_pk_env_t *server_identitykey=NULL;
 +/** Digest of server_identitykey. */
 +static char server_identitykey_digest[DIGEST_LEN];
 +/** Private client "identity key": used to sign bridges' and clients'
 + * outbound TLS certificates. Regenerated on startup and on IP address
 + * change. */
 +static crypto_pk_env_t *client_identitykey=NULL;
  /** Signing key used for v3 directory material; only set for authorities. */
  static crypto_pk_env_t *authority_signing_key = NULL;
  /** Key certificate to authenticate v3 directory material; only set for
@@@ -83,7 -61,8 +83,7 @@@ static voi
  set_onion_key(crypto_pk_env_t *k)
  {
    tor_mutex_acquire(key_lock);
 -  if (onionkey)
 -    crypto_free_pk_env(onionkey);
 +  crypto_free_pk_env(onionkey);
    onionkey = k;
    onionkey_set_at = time(NULL);
    tor_mutex_release(key_lock);
@@@ -127,78 -106,32 +127,78 @@@ get_onion_key_set_at(void
    return onionkey_set_at;
  }
  
 -/** Set the current identity key to k.
 +/** Set the current server identity key to <b>k</b>.
   */
  void
 -set_identity_key(crypto_pk_env_t *k)
 +set_server_identity_key(crypto_pk_env_t *k)
  {
 -  if (identitykey)
 -    crypto_free_pk_env(identitykey);
 -  identitykey = k;
 -  crypto_pk_get_digest(identitykey, identitykey_digest);
 +  crypto_free_pk_env(server_identitykey);
 +  server_identitykey = k;
 +  crypto_pk_get_digest(server_identitykey, server_identitykey_digest);
  }
  
 -/** Returns the current identity key; requires that the identity key has been
 - * set.
 +/** Make sure that we have set up our identity keys to match or not match as
 + * appropriate, and die with an assertion if we have not. */
 +static void
 +assert_identity_keys_ok(void)
 +{
 +  tor_assert(client_identitykey);
 +  if (public_server_mode(get_options())) {
 +    /* assert that we have set the client and server keys to be equal */
 +    tor_assert(server_identitykey);
 +    tor_assert(0==crypto_pk_cmp_keys(client_identitykey, server_identitykey));
 +  } else {
 +    /* assert that we have set the client and server keys to be unequal */
 +    if (server_identitykey)
 +       tor_assert(0!=crypto_pk_cmp_keys(client_identitykey,
 +                                        server_identitykey));
 +  }
 +}
 +
 +/** Returns the current server identity key; requires that the key has
 + * been set, and that we are running as a Tor server.
   */
  crypto_pk_env_t *
 -get_identity_key(void)
 +get_server_identity_key(void)
  {
 -  tor_assert(identitykey);
 -  return identitykey;
 +  tor_assert(server_identitykey);
 +  tor_assert(server_mode(get_options()));
 +  assert_identity_keys_ok();
 +  return server_identitykey;
  }
  
 -/** Return true iff the identity key has been set. */
 +/** Return true iff the server identity key has been set. */
  int
 -identity_key_is_set(void)
 +server_identity_key_is_set(void)
  {
 -  return identitykey != NULL;
 +  return server_identitykey != NULL;
 +}
 +
 +/** Set the current client identity key to <b>k</b>.
 + */
 +void
 +set_client_identity_key(crypto_pk_env_t *k)
 +{
 +  crypto_free_pk_env(client_identitykey);
 +  client_identitykey = k;
 +}
 +
 +/** Returns the current client identity key for use on outgoing TLS
 + * connections; requires that the key has been set.
 + */
 +crypto_pk_env_t *
 +get_tlsclient_identity_key(void)
 +{
 +  tor_assert(client_identitykey);
 +  assert_identity_keys_ok();
 +  return client_identitykey;
 +}
 +
 +/** Return true iff the client identity key has been set. */
 +int
 +client_identity_key_is_set(void)
 +{
 +  return client_identitykey != NULL;
  }
  
  /** Return the key certificate for this v3 (voting) authority, or NULL
@@@ -268,7 -201,8 +268,7 @@@ rotate_onion_key(void
    }
    log_info(LD_GENERAL, "Rotating onion key");
    tor_mutex_acquire(key_lock);
 -  if (lastonionkey)
 -    crypto_free_pk_env(lastonionkey);
 +  crypto_free_pk_env(lastonionkey);
    lastonionkey = onionkey;
    onionkey = prkey;
    now = time(NULL);
@@@ -397,9 -331,10 +397,9 @@@ load_authority_keyset(int legacy, crypt
      goto done;
    }
  
 -  if (*key_out)
 -    crypto_free_pk_env(*key_out);
 -  if (*cert_out)
 -    authority_cert_free(*cert_out);
 +  crypto_free_pk_env(*key_out);
 +  authority_cert_free(*cert_out);
 +
    *key_out = signing_key;
    *cert_out = parsed;
    r = 0;
@@@ -409,8 -344,10 +409,8 @@@
   done:
    tor_free(fname);
    tor_free(cert);
 -  if (signing_key)
 -    crypto_free_pk_env(signing_key);
 -  if (parsed)
 -    authority_cert_free(parsed);
 +  crypto_free_pk_env(signing_key);
 +  authority_cert_free(parsed);
    return r;
  }
  
@@@ -505,9 -442,7 +505,9 @@@ init_keys(void
      key_lock = tor_mutex_new();
  
    /* There are a couple of paths that put us here before */
 -  if (crypto_global_init(get_options()->HardwareAccel)) {
 +  if (crypto_global_init(get_options()->HardwareAccel,
 +                         get_options()->AccelName,
 +                         get_options()->AccelDir)) {
      log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting.");
      return -1;
    }
@@@ -521,12 -456,9 +521,12 @@@
        crypto_free_pk_env(prkey);
        return -1;
      }
 -    set_identity_key(prkey);
 -    /* Create a TLS context; default the client nickname to "client". */
 -    if (tor_tls_context_new(get_identity_key(), MAX_SSL_KEY_LIFETIME) < 0) {
 +    set_client_identity_key(prkey);
 +    /* Create a TLS context. */
 +    if (tor_tls_context_init(0,
 +                             get_tlsclient_identity_key(),
 +                             NULL,
 +                             MAX_SSL_KEY_LIFETIME) < 0) {
        log_err(LD_GENERAL,"Error creating TLS context for Tor client.");
        return -1;
      }
@@@ -561,28 -493,13 +561,28 @@@
      }
    }
  
 -  /* 1. Read identity key. Make it if none is found. */
 +  /* 1b. Read identity key. Make it if none is found. */
    keydir = get_datadir_fname2("keys", "secret_id_key");
    log_info(LD_GENERAL,"Reading/making identity key \"%s\"...",keydir);
    prkey = init_key_from_file(keydir, 1, LOG_ERR);
    tor_free(keydir);
    if (!prkey) return -1;
 -  set_identity_key(prkey);
 +  set_server_identity_key(prkey);
 +
 +  /* 1c. If we are configured as a bridge, generate a client key;
 +   * otherwise, set the server identity key as our client identity
 +   * key. */
 +  if (public_server_mode(options)) {
 +    set_client_identity_key(crypto_pk_dup_key(prkey)); /* set above */
 +  } else {
 +    if (!(prkey = crypto_new_pk_env()))
 +      return -1;
 +    if (crypto_pk_generate_key(prkey)) {
 +      crypto_free_pk_env(prkey);
 +      return -1;
 +    }
 +    set_client_identity_key(prkey);
 +  }
  
    /* 2. Read onion key.  Make it if none is found. */
    keydir = get_datadir_fname2("keys", "secret_onion_key");
@@@ -619,22 -536,18 +619,22 @@@
    tor_free(keydir);
  
    /* 3. Initialize link key and TLS context. */
 -  if (tor_tls_context_new(get_identity_key(), MAX_SSL_KEY_LIFETIME) < 0) {
 +  if (tor_tls_context_init(public_server_mode(options),
 +                           get_tlsclient_identity_key(),
 +                           get_server_identity_key(),
 +                           MAX_SSL_KEY_LIFETIME) < 0) {
      log_err(LD_GENERAL,"Error initializing TLS context");
      return -1;
    }
    /* 4. Build our router descriptor. */
    /* Must be called after keys are initialized. */
    mydesc = router_get_my_descriptor();
 -  if (authdir_mode(options)) {
 +  if (authdir_mode_handles_descs(options, ROUTER_PURPOSE_GENERAL)) {
      const char *m = NULL;
      routerinfo_t *ri;
      /* We need to add our own fingerprint so it gets recognized. */
 -    if (dirserv_add_own_fingerprint(options->Nickname, get_identity_key())) {
 +    if (dirserv_add_own_fingerprint(options->Nickname,
 +                                    get_server_identity_key())) {
        log_err(LD_GENERAL,"Error adding own fingerprint to approved set");
        return -1;
      }
@@@ -655,8 -568,7 +655,8 @@@
    /* 5. Dump fingerprint to 'fingerprint' */
    keydir = get_datadir_fname("fingerprint");
    log_info(LD_GENERAL,"Dumping fingerprint to \"%s\"...",keydir);
 -  if (crypto_pk_get_fingerprint(get_identity_key(), fingerprint, 0)<0) {
 +  if (crypto_pk_get_fingerprint(get_server_identity_key(),
 +                                fingerprint, 0) < 0) {
      log_err(LD_GENERAL,"Error computing fingerprint");
      tor_free(keydir);
      return -1;
@@@ -694,7 -606,7 +694,7 @@@
      return -1;
    }
    /* 6b. [authdirserver only] add own key to approved directories. */
 -  crypto_pk_get_digest(get_identity_key(), digest);
 +  crypto_pk_get_digest(get_server_identity_key(), digest);
    type = ((options->V1AuthoritativeDir ? V1_AUTHORITY : NO_AUTHORITY) |
            (options->V2AuthoritativeDir ? V2_AUTHORITY : NO_AUTHORITY) |
            (options->V3AuthoritativeDir ? V3_AUTHORITY : NO_AUTHORITY) |
@@@ -881,19 -793,14 +881,14 @@@ consider_testing_reachability(int test_
  void
  router_orport_found_reachable(void)
  {
-   if (!can_reach_or_port) {
-     routerinfo_t *me = router_get_my_routerinfo();
+   routerinfo_t *me = router_get_my_routerinfo();
+   if (!can_reach_or_port && me) {
      log_notice(LD_OR,"Self-testing indicates your ORPort is reachable from "
                 "the outside. Excellent.%s",
                 get_options()->_PublishServerDescriptor != NO_AUTHORITY ?
                   " Publishing server descriptor." : "");
      can_reach_or_port = 1;
      mark_my_descriptor_dirty();
-     if (!me) { /* should never happen */
-       log_warn(LD_BUG, "ORPort found reachable, but I have no routerinfo "
-                "yet. Failing to inform controller of success.");
-       return;
-     }
      control_event_server_status(LOG_NOTICE,
                                  "REACHABILITY_SUCCEEDED ORADDRESS=%s:%d",
                                  me->address, me->or_port);
@@@ -904,18 -811,13 +899,13 @@@
  void
  router_dirport_found_reachable(void)
  {
-   if (!can_reach_dir_port) {
-     routerinfo_t *me = router_get_my_routerinfo();
+   routerinfo_t *me = router_get_my_routerinfo();
+   if (!can_reach_dir_port && me) {
      log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable "
                 "from the outside. Excellent.");
      can_reach_dir_port = 1;
-     if (!me || decide_to_advertise_dirport(get_options(), me->dir_port))
+     if (decide_to_advertise_dirport(get_options(), me->dir_port))
        mark_my_descriptor_dirty();
-     if (!me) { /* should never happen */
-       log_warn(LD_BUG, "DirPort found reachable, but I have no routerinfo "
-                "yet. Failing to inform controller of success.");
-       return;
-     }
      control_event_server_status(LOG_NOTICE,
                                  "REACHABILITY_SUCCEEDED DIRADDRESS=%s:%d",
                                  me->address, me->dir_port);
@@@ -1050,28 -952,6 +1040,28 @@@ server_mode(or_options_t *options
    return (options->ORPort != 0 || options->ORListenAddress);
  }
  
 +/** Return true iff we are trying to be a non-bridge server.
 + */
 +int
 +public_server_mode(or_options_t *options)
 +{
 +  if (!server_mode(options)) return 0;
 +  return (!options->BridgeRelay);
 +}
 +
 +/** Return true iff the combination of options in <b>options</b> and parameters
 + * in the consensus mean that we don't want to allow exits from circuits
 + * we got from addresses not known to be servers. */
 +int
 +should_refuse_unknown_exits(or_options_t *options)
 +{
 +  if (options->RefuseUnknownExits_ != -1) {
 +    return options->RefuseUnknownExits_;
 +  } else {
 +    return networkstatus_get_param(NULL, "refuseunknownexits", 1, 0, 1);
 +  }
 +}
 +
  /** Remember if we've advertised ourselves to the dirservers. */
  static int server_is_advertised=0;
  
@@@ -1099,7 -979,7 +1089,7 @@@ proxy_mode(or_options_t *options
  {
    return (options->SocksPort != 0 || options->SocksListenAddress ||
            options->TransPort != 0 || options->TransListenAddress ||
 -          options->NatdPort != 0 || options->NatdListenAddress ||
 +          options->NATDPort != 0 || options->NATDListenAddress ||
            options->DNSPort != 0 || options->DNSListenAddress);
  }
  
@@@ -1234,24 -1114,12 +1224,24 @@@ router_compare_to_my_exit_policy(edge_c
                     desc_routerinfo->exit_policy) != ADDR_POLICY_ACCEPTED;
  }
  
 +/** Return true iff my exit policy is reject *:*.  Return -1 if we don't
 + * have a descriptor */
 +int
 +router_my_exit_policy_is_reject_star(void)
 +{
 +  if (!router_get_my_routerinfo()) /* make sure desc_routerinfo exists */
 +    return -1;
 +
 +  return desc_routerinfo->policy_is_reject_star;
 +}
 +
  /** Return true iff I'm a server and <b>digest</b> is equal to
 - * my identity digest. */
 + * my server identity key digest. */
  int
  router_digest_is_me(const char *digest)
  {
 -  return identitykey && !memcmp(identitykey_digest, digest, DIGEST_LEN);
 +  return (server_identitykey &&
 +          !memcmp(server_identitykey_digest, digest, DIGEST_LEN));
  }
  
  /** Return true iff I'm a server and <b>digest</b> is equal to
@@@ -1341,8 -1209,6 +1331,8 @@@ static int router_guess_address_from_di
  int
  router_pick_published_address(or_options_t *options, uint32_t *addr)
  {
 +  char buf[INET_NTOA_BUF_LEN];
 +  struct in_addr a;
    if (resolve_my_address(LOG_INFO, options, addr, NULL) < 0) {
      log_info(LD_CONFIG, "Could not determine our address locally. "
               "Checking if directory headers provide any hints.");
@@@ -1352,9 -1218,6 +1342,9 @@@
        return -1;
      }
    }
 +  a.s_addr = htonl(*addr);
 +  tor_inet_ntoa(&a, buf, sizeof(buf));
 +  log_info(LD_CONFIG,"Success: chose address '%s'.", buf);
    return 0;
  }
  
@@@ -1377,7 -1240,7 +1367,7 @@@ router_rebuild_descriptor(int force
  
    if (router_pick_published_address(options, &addr) < 0) {
      /* Stop trying to rebuild our descriptor every second. We'll
 -     * learn that it's time to try again when server_has_changed_ip()
 +     * learn that it's time to try again when ip_address_changed()
       * marks it dirty. */
      desc_clean_since = time(NULL);
      return -1;
@@@ -1393,7 -1256,7 +1383,7 @@@
    ri->cache_info.published_on = time(NULL);
    ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); /* must invoke from
                                                          * main thread */
 -  ri->identity_pkey = crypto_pk_dup_key(get_identity_key());
 +  ri->identity_pkey = crypto_pk_dup_key(get_server_identity_key());
    if (crypto_pk_get_digest(ri->identity_pkey,
                             ri->cache_info.identity_digest)<0) {
      routerinfo_free(ri);
@@@ -1410,16 -1273,9 +1400,16 @@@
  
    ri->bandwidthcapacity = hibernating ? 0 : rep_hist_bandwidth_assess();
  
 -  policies_parse_exit_policy(options->ExitPolicy, &ri->exit_policy,
 -                             options->ExitPolicyRejectPrivate,
 -                             ri->address);
 +  if (dns_seems_to_be_broken() || has_dns_init_failed()) {
 +    /* DNS is screwed up; don't claim to be an exit. */
 +    policies_exit_policy_append_reject_star(&ri->exit_policy);
 +  } else {
 +    policies_parse_exit_policy(options->ExitPolicy, &ri->exit_policy,
 +                               options->ExitPolicyRejectPrivate,
 +                               ri->address, !options->BridgeRelay);
 +  }
 +  ri->policy_is_reject_star =
 +    policy_is_reject_star(ri->exit_policy);
  
    if (desc_routerinfo) { /* inherit values */
      ri->is_valid = desc_routerinfo->is_valid;
@@@ -1490,30 -1346,26 +1480,30 @@@
    ei->cache_info.published_on = ri->cache_info.published_on;
    memcpy(ei->cache_info.identity_digest, ri->cache_info.identity_digest,
           DIGEST_LEN);
 -  ei->cache_info.signed_descriptor_body = tor_malloc(8192);
 -  if (extrainfo_dump_to_string(ei->cache_info.signed_descriptor_body, 8192,
 -                               ei, get_identity_key()) < 0) {
 +  if (extrainfo_dump_to_string(&ei->cache_info.signed_descriptor_body,
 +                               ei, get_server_identity_key()) < 0) {
      log_warn(LD_BUG, "Couldn't generate extra-info descriptor.");
 -    routerinfo_free(ri);
      extrainfo_free(ei);
 -    return -1;
 +    ei = NULL;
 +  } else {
 +    ei->cache_info.signed_descriptor_len =
 +      strlen(ei->cache_info.signed_descriptor_body);
 +    router_get_extrainfo_hash(ei->cache_info.signed_descriptor_body,
 +                              ei->cache_info.signed_descriptor_digest);
    }
 -  ei->cache_info.signed_descriptor_len =
 -    strlen(ei->cache_info.signed_descriptor_body);
 -  router_get_extrainfo_hash(ei->cache_info.signed_descriptor_body,
 -                            ei->cache_info.signed_descriptor_digest);
  
    /* Now finish the router descriptor. */
 -  memcpy(ri->cache_info.extra_info_digest,
 -         ei->cache_info.signed_descriptor_digest,
 -         DIGEST_LEN);
 +  if (ei) {
 +    memcpy(ri->cache_info.extra_info_digest,
 +           ei->cache_info.signed_descriptor_digest,
 +           DIGEST_LEN);
 +  } else {
 +    /* ri was allocated with tor_malloc_zero, so there is no need to
 +     * zero ri->cache_info.extra_info_digest here. */
 +  }
    ri->cache_info.signed_descriptor_body = tor_malloc(8192);
    if (router_dump_router_to_string(ri->cache_info.signed_descriptor_body, 8192,
 -                                   ri, get_identity_key())<0) {
 +                                   ri, get_server_identity_key()) < 0) {
      log_warn(LD_BUG, "Couldn't generate router descriptor.");
      routerinfo_free(ri);
      extrainfo_free(ei);
@@@ -1528,7 -1380,7 +1518,7 @@@
    /* Let bridges serve their own descriptors unencrypted, so they can
     * pass reachability testing. (If they want to be harder to notice,
     * they can always leave the DirPort off). */
 -  if (!options->BridgeRelay)
 +  if (ei && !options->BridgeRelay)
      ei->cache_info.send_unencrypted = 1;
  
    router_get_router_hash(ri->cache_info.signed_descriptor_body,
@@@ -1537,13 -1389,13 +1527,13 @@@
  
    routerinfo_set_country(ri);
  
 -  tor_assert(! routerinfo_incompatible_with_extrainfo(ri, ei, NULL, NULL));
 +  if (ei) {
 +    tor_assert(! routerinfo_incompatible_with_extrainfo(ri, ei, NULL, NULL));
 +  }
  
 -  if (desc_routerinfo)
 -    routerinfo_free(desc_routerinfo);
 +  routerinfo_free(desc_routerinfo);
    desc_routerinfo = ri;
 -  if (desc_extrainfo)
 -    extrainfo_free(desc_extrainfo);
 +  extrainfo_free(desc_extrainfo);
    desc_extrainfo = ei;
  
    desc_clean_since = time(NULL);
@@@ -1724,6 -1576,8 +1714,6 @@@ router_guess_address_from_dir_headers(u
    return -1;
  }
  
 -extern const char tor_svn_revision[]; /* from tor_main.c */
 -
  /** Set <b>platform</b> (max length <b>len</b>) to a NUL-terminated short
   * string describing the version of Tor and the operating system we're
   * currently running on.
@@@ -1754,7 -1608,6 +1744,7 @@@ router_dump_router_to_string(char *s, s
    char digest[DIGEST_LEN];
    char published[ISO_TIME_LEN+1];
    char fingerprint[FINGERPRINT_LEN+1];
 +  int has_extra_info_digest;
    char extra_info_digest[HEX_DIGEST_LEN+1];
    size_t onion_pkeylen, identity_pkeylen;
    size_t written;
@@@ -1783,7 -1636,7 +1773,7 @@@
      return -1;
    }
  
 -  /* PEM-encode the identity key key */
 +  /* PEM-encode the identity key */
    if (crypto_pk_write_public_key_to_string(router->identity_pkey,
                                          &identity_pkey,&identity_pkeylen)<0) {
      log_warn(LD_BUG,"write identity_pkey to string failed!");
@@@ -1805,13 -1658,8 +1795,13 @@@
      family_line = tor_strdup("");
    }
  
 -  base16_encode(extra_info_digest, sizeof(extra_info_digest),
 -                router->cache_info.extra_info_digest, DIGEST_LEN);
 +  has_extra_info_digest =
 +    ! tor_digest_is_zero(router->cache_info.extra_info_digest);
 +
 +  if (has_extra_info_digest) {
 +    base16_encode(extra_info_digest, sizeof(extra_info_digest),
 +                  router->cache_info.extra_info_digest, DIGEST_LEN);
 +  }
  
    /* Generate the easy portion of the router descriptor. */
    result = tor_snprintf(s, maxlen,
@@@ -1822,7 -1670,7 +1812,7 @@@
                      "opt fingerprint %s\n"
                      "uptime %ld\n"
                      "bandwidth %d %d %d\n"
 -                    "opt extra-info-digest %s\n%s"
 +                    "%s%s%s%s"
                      "onion-key\n%s"
                      "signing-key\n%s"
                      "%s%s%s%s",
@@@ -1837,9 -1685,7 +1827,9 @@@
      (int) router->bandwidthrate,
      (int) router->bandwidthburst,
      (int) router->bandwidthcapacity,
 -    extra_info_digest,
 +    has_extra_info_digest ? "opt extra-info-digest " : "",
 +    has_extra_info_digest ? extra_info_digest : "",
 +    has_extra_info_digest ? "\n" : "",
      options->DownloadExtraInfo ? "opt caches-extra-info\n" : "",
      onion_pkey, identity_pkey,
      family_line,
@@@ -1871,7 -1717,9 +1861,7 @@@
    }
  
    /* Write the exit policy to the end of 's'. */
 -  if (dns_seems_to_be_broken() || has_dns_init_failed() ||
 -      !router->exit_policy || !smartlist_len(router->exit_policy)) {
 -    /* DNS is screwed up; don't claim to be an exit. */
 +  if (!router->exit_policy || !smartlist_len(router->exit_policy)) {
      strlcat(s+written, "reject *:*\n", maxlen-written);
      written += strlen("reject *:*\n");
      tmpe = NULL;
@@@ -1894,8 -1742,7 +1884,8 @@@
      }
    }
  
 -  if (written+256 > maxlen) { /* Not enough room for signature. */
 +  if (written + DIROBJ_MAX_SIG_LEN > maxlen) {
 +    /* Not enough room for signature. */
      log_warn(LD_BUG,"not enough room left in descriptor for signature!");
      return -1;
    }
@@@ -1910,7 -1757,7 +1900,7 @@@
  
    note_crypto_pk_op(SIGN_RTR);
    if (router_append_dirobj_signature(s+written,maxlen-written,
 -                                     digest,ident_key)<0) {
 +                                     digest,DIGEST_LEN,ident_key)<0) {
      log_warn(LD_BUG, "Couldn't sign router descriptor");
      return -1;
    }
@@@ -1945,62 -1792,11 +1935,62 @@@
    return (int)written+1;
  }
  
 -/** Write the contents of <b>extrainfo</b> to the <b>maxlen</b>-byte string
 - * <b>s</b>, signing them with <b>ident_key</b>.  Return 0 on success,
 - * negative on failure. */
 +/** Load the contents of <b>filename</b>, find the last line starting with
 + * <b>end_line</b>, ensure that its timestamp is not more than 25 hours in
 + * the past or more than 1 hour in the future with respect to <b>now</b>,
 + * and write the file contents starting with that line to *<b>out</b>.
 + * Return 1 for success, 0 if the file does not exist, or -1 if the file
 + * does not contain a line matching these criteria or other failure. */
 +static int
 +load_stats_file(const char *filename, const char *end_line, time_t now,
 +                char **out)
 +{
 +  int r = -1;
 +  char *fname = get_datadir_fname(filename);
 +  char *contents, *start = NULL, *tmp, timestr[ISO_TIME_LEN+1];
 +  time_t written;
 +  switch (file_status(fname)) {
 +    case FN_FILE:
 +      /* X022 Find an alternative to reading the whole file to memory. */
 +      if ((contents = read_file_to_str(fname, 0, NULL))) {
 +        tmp = strstr(contents, end_line);
 +        /* Find last block starting with end_line */
 +        while (tmp) {
 +          start = tmp;
 +          tmp = strstr(tmp + 1, end_line);
 +        }
 +        if (!start)
 +          goto notfound;
 +        if (strlen(start) < strlen(end_line) + 1 + sizeof(timestr))
 +          goto notfound;
 +        strlcpy(timestr, start + 1 + strlen(end_line), sizeof(timestr));
 +        if (parse_iso_time(timestr, &written) < 0)
 +          goto notfound;
 +        if (written < now - (25*60*60) || written > now + (1*60*60))
 +          goto notfound;
 +        *out = tor_strdup(start);
 +        r = 1;
 +      }
 +     notfound:
 +      tor_free(contents);
 +      break;
 +    case FN_NOENT:
 +      r = 0;
 +      break;
 +    case FN_ERROR:
 +    case FN_DIR:
 +    default:
 +      break;
 +  }
 +  tor_free(fname);
 +  return r;
 +}
 +
 +/** Write the contents of <b>extrainfo</b> and aggregated statistics to
 + * *<b>s_out</b>, signing them with <b>ident_key</b>. Return 0 on
 + * success, negative on failure. */
  int
 -extrainfo_dump_to_string(char *s, size_t maxlen, extrainfo_t *extrainfo,
 +extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
                           crypto_pk_env_t *ident_key)
  {
    or_options_t *options = get_options();
@@@ -2009,128 -1805,87 +1999,128 @@@
    char digest[DIGEST_LEN];
    char *bandwidth_usage;
    int result;
 -  size_t len;
 +  static int write_stats_to_extrainfo = 1;
 +  char sig[DIROBJ_MAX_SIG_LEN+1];
 +  char *s, *pre, *contents, *cp, *s_dup = NULL;
 +  time_t now = time(NULL);
 +  smartlist_t *chunks = smartlist_create();
 +  extrainfo_t *ei_tmp = NULL;
  
    base16_encode(identity, sizeof(identity),
                  extrainfo->cache_info.identity_digest, DIGEST_LEN);
    format_iso_time(published, extrainfo->cache_info.published_on);
 -  bandwidth_usage = rep_hist_get_bandwidth_lines(1);
 +  bandwidth_usage = rep_hist_get_bandwidth_lines();
  
 -  result = tor_snprintf(s, maxlen,
 -                        "extra-info %s %s\n"
 -                        "published %s\n%s",
 -                        extrainfo->nickname, identity,
 -                        published, bandwidth_usage);
 +  tor_asprintf(&pre, "extra-info %s %s\npublished %s\n%s",
 +               extrainfo->nickname, identity,
 +               published, bandwidth_usage);
    tor_free(bandwidth_usage);
 -  if (result<0)
 -    return -1;
 +  smartlist_add(chunks, pre);
 +
 +  if (options->ExtraInfoStatistics && write_stats_to_extrainfo) {
 +    log_info(LD_GENERAL, "Adding stats to extra-info descriptor.");
 +    if (options->DirReqStatistics &&
 +        load_stats_file("stats"PATH_SEPARATOR"dirreq-stats",
 +                        "dirreq-stats-end", now, &contents) > 0) {
 +      smartlist_add(chunks, contents);
 +    }
 +    if (options->EntryStatistics &&
 +        load_stats_file("stats"PATH_SEPARATOR"entry-stats",
 +                        "entry-stats-end", now, &contents) > 0) {
 +      smartlist_add(chunks, contents);
 +    }
 +    if (options->CellStatistics &&
 +        load_stats_file("stats"PATH_SEPARATOR"buffer-stats",
 +                        "cell-stats-end", now, &contents) > 0) {
 +      smartlist_add(chunks, contents);
 +    }
 +    if (options->ExitPortStatistics &&
 +        load_stats_file("stats"PATH_SEPARATOR"exit-stats",
 +                        "exit-stats-end", now, &contents) > 0) {
 +      smartlist_add(chunks, contents);
 +    }
 +  }
  
 -  if (should_record_bridge_info(options)) {
 -    char *geoip_summary = extrainfo_get_client_geoip_summary(time(NULL));
 -    if (geoip_summary) {
 -      char geoip_start[ISO_TIME_LEN+1];
 -      format_iso_time(geoip_start, geoip_get_history_start());
 -      result = tor_snprintf(s+strlen(s), maxlen-strlen(s),
 -                            "geoip-start-time %s\n"
 -                            "geoip-client-origins %s\n",
 -                            geoip_start, geoip_summary);
 -      control_event_clients_seen(geoip_start, geoip_summary);
 -      tor_free(geoip_summary);
 -      if (result<0)
 -        return -1;
 +  if (should_record_bridge_info(options) && write_stats_to_extrainfo) {
 +    const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now);
 +    if (bridge_stats) {
 +      smartlist_add(chunks, tor_strdup(bridge_stats));
      }
    }
  
 -  len = strlen(s);
 -  strlcat(s+len, "router-signature\n", maxlen-len);
 -  len += strlen(s+len);
 -  if (router_get_extrainfo_hash(s, digest)<0)
 -    return -1;
 -  if (router_append_dirobj_signature(s+len, maxlen-len, digest, ident_key)<0)
 -    return -1;
 +  smartlist_add(chunks, tor_strdup("router-signature\n"));
 +  s = smartlist_join_strings(chunks, "", 0, NULL);
 +
 +  while (strlen(s) > MAX_EXTRAINFO_UPLOAD_SIZE - DIROBJ_MAX_SIG_LEN) {
 +    /* So long as there are at least two chunks (one for the initial
 +     * extra-info line and one for the router-signature), we can keep removing
 +     * things. */
 +    if (smartlist_len(chunks) > 2) {
 +      /* We remove the next-to-last element (remember, len-1 is the last
 +         element), since we need to keep the router-signature element. */
 +      int idx = smartlist_len(chunks) - 2;
 +      char *e = smartlist_get(chunks, idx);
 +      smartlist_del_keeporder(chunks, idx);
 +      log_warn(LD_GENERAL, "We just generated an extra-info descriptor "
 +                           "with statistics that exceeds the 50 KB "
 +                           "upload limit. Removing last added "
 +                           "statistics.");
 +      tor_free(e);
 +      tor_free(s);
 +      s = smartlist_join_strings(chunks, "", 0, NULL);
 +    } else {
 +      log_warn(LD_BUG, "We just generated an extra-info descriptors that "
 +                       "exceeds the 50 KB upload limit.");
 +      goto err;
 +    }
 +  }
  
 -#ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
 -  {
 -    char *cp, *s_dup;
 -    extrainfo_t *ei_tmp;
 -    cp = s_dup = tor_strdup(s);
 -    ei_tmp = extrainfo_parse_entry_from_string(cp, NULL, 1, NULL);
 -    if (!ei_tmp) {
 -      log_err(LD_BUG,
 -              "We just generated an extrainfo descriptor we can't parse.");
 -      log_err(LD_BUG, "Descriptor was: <<%s>>", s);
 -      tor_free(s_dup);
 -      return -1;
 +  memset(sig, 0, sizeof(sig));
 +  if (router_get_extrainfo_hash(s, digest) < 0 ||
 +      router_append_dirobj_signature(sig, sizeof(sig), digest, DIGEST_LEN,
 +                                     ident_key) < 0) {
 +    log_warn(LD_BUG, "Could not append signature to extra-info "
 +                     "descriptor.");
 +    goto err;
 +  }
 +  smartlist_add(chunks, tor_strdup(sig));
 +  tor_free(s);
 +  s = smartlist_join_strings(chunks, "", 0, NULL);
 +
 +  cp = s_dup = tor_strdup(s);
 +  ei_tmp = extrainfo_parse_entry_from_string(cp, NULL, 1, NULL);
 +  if (!ei_tmp) {
 +    if (write_stats_to_extrainfo) {
 +      log_warn(LD_GENERAL, "We just generated an extra-info descriptor "
 +                           "with statistics that we can't parse. Not "
 +                           "adding statistics to this or any future "
 +                           "extra-info descriptors.");
 +      write_stats_to_extrainfo = 0;
 +      result = extrainfo_dump_to_string(s_out, extrainfo, ident_key);
 +      goto done;
 +    } else {
 +      log_warn(LD_BUG, "We just generated an extrainfo descriptor we "
 +                       "can't parse.");
 +      goto err;
      }
 -    tor_free(s_dup);
 -    extrainfo_free(ei_tmp);
    }
 -#endif
  
 -  return (int)strlen(s)+1;
 -}
 +  *s_out = s;
 +  s = NULL; /* prevent free */
 +  result = 0;
 +  goto done;
  
 -/** Wrapper function for geoip_get_client_history(). It first discards
 - * any items in the client history that are too old -- it dumps anything
 - * more than 48 hours old, but it only considers whether to dump at most
 - * once per 48 hours, so we aren't too precise to an observer (see also
 - * r14780).
 - */
 -char *
 -extrainfo_get_client_geoip_summary(time_t now)
 -{
 -  static time_t last_purged_at = 0;
 -  int geoip_purge_interval = 48*60*60;
 -#ifdef ENABLE_GEOIP_STATS
 -  if (get_options()->DirRecordUsageByCountry)
 -    geoip_purge_interval = get_options()->DirRecordUsageRetainIPs;
 -#endif
 -  if (now > last_purged_at+geoip_purge_interval) {
 -    geoip_remove_old_clients(now-geoip_purge_interval);
 -    last_purged_at = now;
 -  }
 -  return geoip_get_client_history(now, GEOIP_CLIENT_CONNECT);
 + err:
 +  result = -1;
 +
 + done:
 +  tor_free(s);
 +  SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
 +  smartlist_free(chunks);
 +  tor_free(s_dup);
 +  extrainfo_free(ei_tmp);
 +
 +  return result;
  }
  
  /** Return true iff <b>s</b> is a legally valid server nickname. */
@@@ -2257,17 -2012,26 +2247,17 @@@ router_purpose_from_string(const char *
  void
  router_free_all(void)
  {
 -  if (onionkey)
 -    crypto_free_pk_env(onionkey);
 -  if (lastonionkey)
 -    crypto_free_pk_env(lastonionkey);
 -  if (identitykey)
 -    crypto_free_pk_env(identitykey);
 -  if (key_lock)
 -    tor_mutex_free(key_lock);
 -  if (desc_routerinfo)
 -    routerinfo_free(desc_routerinfo);
 -  if (desc_extrainfo)
 -    extrainfo_free(desc_extrainfo);
 -  if (authority_signing_key)
 -    crypto_free_pk_env(authority_signing_key);
 -  if (authority_key_certificate)
 -    authority_cert_free(authority_key_certificate);
 -  if (legacy_signing_key)
 -    crypto_free_pk_env(legacy_signing_key);
 -  if (legacy_key_certificate)
 -    authority_cert_free(legacy_key_certificate);
 +  crypto_free_pk_env(onionkey);
 +  crypto_free_pk_env(lastonionkey);
 +  crypto_free_pk_env(server_identitykey);
 +  crypto_free_pk_env(client_identitykey);
 +  tor_mutex_free(key_lock);
 +  routerinfo_free(desc_routerinfo);
 +  extrainfo_free(desc_extrainfo);
 +  crypto_free_pk_env(authority_signing_key);
 +  authority_cert_free(authority_key_certificate);
 +  crypto_free_pk_env(legacy_signing_key);
 +  authority_cert_free(legacy_key_certificate);
  
    if (warned_nonexistent_family) {
      SMARTLIST_FOREACH(warned_nonexistent_family, char *, cp, tor_free(cp));





More information about the tor-commits mailing list