Przeglądaj źródła

Merge branch 'microdesc-use-v2-squashed'

Nick Mathewson 14 lat temu
rodzic
commit
ad35b8f40d

+ 10 - 0
changes/microdesc_use

@@ -0,0 +1,10 @@
+  o Major features
+    - Clients can now use microdescriptors instead of regular descriptors
+      to build circuits.  Microdescriptors are authority-generated and
+      -authenticated summaries of regular descriptors' contents, designed
+      to change very rarely.  This feature is designed to save bandwidth,
+      especially for clients on slow internet connections.  It's off
+      by default for now, since nearly no caches support it, but it will
+      be on-by-default for clients in a future version.  You can use the
+      UseMicrodescriptors option to turn it on.
+

+ 1 - 1
src/or/circuitbuild.c

@@ -4649,7 +4649,7 @@ retry_bridge_descriptor_fetch_directly(const char *digest)
 void
 fetch_bridge_descriptors(or_options_t *options, time_t now)
 {
-  int num_bridge_auths = get_n_authorities(BRIDGE_AUTHORITY);
+  int num_bridge_auths = get_n_authorities(BRIDGE_DIRINFO);
   int ask_bridge_directly;
   int can_use_bridge_authority;
 

+ 63 - 51
src/or/config.c

@@ -49,6 +49,8 @@ typedef enum config_type_t {
   CONFIG_TYPE_MEMUNIT,      /**< A number of bytes, with optional units*/
   CONFIG_TYPE_DOUBLE,       /**< A floating-point value */
   CONFIG_TYPE_BOOL,         /**< A boolean value, expressed as 0 or 1. */
+  CONFIG_TYPE_AUTOBOOL,     /**< A boolean+auto value, expressed 0 for false,
+                             * 1 for true, and -1 for auto  */
   CONFIG_TYPE_ISOTIME,      /**< An ISO-formatted time relative to GMT. */
   CONFIG_TYPE_CSV,          /**< A list of strings, separated by commas and
                               * optional whitespace. */
@@ -338,7 +340,7 @@ static config_var_t _option_vars[] = {
   V(RecommendedClientVersions,   LINELIST, NULL),
   V(RecommendedServerVersions,   LINELIST, NULL),
   OBSOLETE("RedirectExit"),
-  V(RefuseUnknownExits,          STRING,   "auto"),
+  V(RefuseUnknownExits,          AUTOBOOL, "auto"),
   V(RejectPlaintextPorts,        CSV,      ""),
   V(RelayBandwidthBurst,         MEMUNIT,  "0"),
   V(RelayBandwidthRate,          MEMUNIT,  "0"),
@@ -379,6 +381,7 @@ static config_var_t _option_vars[] = {
   V(UpdateBridgesFromAuthority,  BOOL,     "0"),
   V(UseBridges,                  BOOL,     "0"),
   V(UseEntryGuards,              BOOL,     "1"),
+  V(UseMicrodescriptors,         AUTOBOOL, "0"),
   V(User,                        STRING,   NULL),
   VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir,   "0"),
   VAR("V2AuthoritativeDirectory",BOOL, V2AuthoritativeDir,   "0"),
@@ -559,7 +562,7 @@ static void config_register_addressmaps(or_options_t *options);
 
 static int parse_bridge_line(const char *line, int validate_only);
 static int parse_dir_server_line(const char *line,
-                                 authority_type_t required_type,
+                                 dirinfo_type_t required_type,
                                  int validate_only);
 static int validate_data_directory(or_options_t *options);
 static int write_configuration_file(const char *fname, or_options_t *options);
@@ -799,7 +802,7 @@ escaped_safe_str(const char *address)
 /** Add the default directory authorities directly into the trusted dir list,
  * but only add them insofar as they share bits with <b>type</b>. */
 static void
-add_default_trusted_dir_authorities(authority_type_t type)
+add_default_trusted_dir_authorities(dirinfo_type_t type)
 {
   int i;
   const char *dirservers[] = {
@@ -873,16 +876,16 @@ validate_dir_authorities(or_options_t *options, or_options_t *old_options)
   /* Now go through the four ways you can configure an alternate
    * set of directory authorities, and make sure none are broken. */
   for (cl = options->DirServers; cl; cl = cl->next)
-    if (parse_dir_server_line(cl->value, NO_AUTHORITY, 1)<0)
+    if (parse_dir_server_line(cl->value, NO_DIRINFO, 1)<0)
       return -1;
   for (cl = options->AlternateBridgeAuthority; cl; cl = cl->next)
-    if (parse_dir_server_line(cl->value, NO_AUTHORITY, 1)<0)
+    if (parse_dir_server_line(cl->value, NO_DIRINFO, 1)<0)
       return -1;
   for (cl = options->AlternateDirAuthority; cl; cl = cl->next)
-    if (parse_dir_server_line(cl->value, NO_AUTHORITY, 1)<0)
+    if (parse_dir_server_line(cl->value, NO_DIRINFO, 1)<0)
       return -1;
   for (cl = options->AlternateHSAuthority; cl; cl = cl->next)
-    if (parse_dir_server_line(cl->value, NO_AUTHORITY, 1)<0)
+    if (parse_dir_server_line(cl->value, NO_DIRINFO, 1)<0)
       return -1;
   return 0;
 }
@@ -913,27 +916,28 @@ consider_adding_dir_authorities(or_options_t *options,
 
   if (!options->DirServers) {
     /* then we may want some of the defaults */
-    authority_type_t type = NO_AUTHORITY;
+    dirinfo_type_t type = NO_DIRINFO;
     if (!options->AlternateBridgeAuthority)
-      type |= BRIDGE_AUTHORITY;
+      type |= BRIDGE_DIRINFO;
     if (!options->AlternateDirAuthority)
-      type |= V1_AUTHORITY | V2_AUTHORITY | V3_AUTHORITY;
+      type |= V1_DIRINFO | V2_DIRINFO | V3_DIRINFO | EXTRAINFO_DIRINFO |
+        MICRODESC_DIRINFO;
     if (!options->AlternateHSAuthority)
-      type |= HIDSERV_AUTHORITY;
+      type |= HIDSERV_DIRINFO;
     add_default_trusted_dir_authorities(type);
   }
 
   for (cl = options->DirServers; cl; cl = cl->next)
-    if (parse_dir_server_line(cl->value, NO_AUTHORITY, 0)<0)
+    if (parse_dir_server_line(cl->value, NO_DIRINFO, 0)<0)
       return -1;
   for (cl = options->AlternateBridgeAuthority; cl; cl = cl->next)
-    if (parse_dir_server_line(cl->value, NO_AUTHORITY, 0)<0)
+    if (parse_dir_server_line(cl->value, NO_DIRINFO, 0)<0)
       return -1;
   for (cl = options->AlternateDirAuthority; cl; cl = cl->next)
-    if (parse_dir_server_line(cl->value, NO_AUTHORITY, 0)<0)
+    if (parse_dir_server_line(cl->value, NO_DIRINFO, 0)<0)
       return -1;
   for (cl = options->AlternateHSAuthority; cl; cl = cl->next)
-    if (parse_dir_server_line(cl->value, NO_AUTHORITY, 0)<0)
+    if (parse_dir_server_line(cl->value, NO_DIRINFO, 0)<0)
       return -1;
   return 0;
 }
@@ -1271,18 +1275,6 @@ options_act(or_options_t *old_options)
     connection_bucket_init();
 #endif
 
-  /* parse RefuseUnknownExits tristate */
-  if (!strcmp(options->RefuseUnknownExits, "0"))
-    options->RefuseUnknownExits_ = 0;
-  else if (!strcmp(options->RefuseUnknownExits, "1"))
-    options->RefuseUnknownExits_ = 1;
-  else if (!strcmp(options->RefuseUnknownExits, "auto"))
-    options->RefuseUnknownExits_ = -1;
-  else {
-    /* Should have caught this in options_validate */
-    return -1;
-  }
-
   /* Change the cell EWMA settings */
   cell_ewma_set_scale_factor(options, networkstatus_get_latest_consensus());
 
@@ -1788,6 +1780,20 @@ config_assign_value(config_format_t *fmt, or_options_t *options,
     *(int *)lvalue = i;
     break;
 
+  case CONFIG_TYPE_AUTOBOOL:
+    if (!strcmp(c->value, "auto"))
+      *(int *)lvalue = -1;
+    else if (!strcmp(c->value, "0"))
+      *(int *)lvalue = 0;
+    else if (!strcmp(c->value, "1"))
+      *(int *)lvalue = 1;
+    else {
+      tor_asprintf(msg, "Boolean '%s %s' expects 0, 1, or 'auto'.",
+                   c->key, c->value);
+      return -1;
+    }
+    break;
+
   case CONFIG_TYPE_STRING:
   case CONFIG_TYPE_FILENAME:
     tor_free(*(char **)lvalue);
@@ -2068,6 +2074,14 @@ get_assigned_option(config_format_t *fmt, void *options,
       tor_asprintf(&result->value, "%f", *(double*)value);
       escape_val = 0; /* Can't need escape. */
       break;
+
+    case CONFIG_TYPE_AUTOBOOL:
+      if (*(int*)value == -1) {
+        result->value = tor_strdup("auto");
+        escape_val = 0;
+        break;
+      }
+      /* fall through */
     case CONFIG_TYPE_BOOL:
       result->value = tor_strdup(*(int*)value ? "1" : "0");
       escape_val = 0; /* Can't need escape. */
@@ -2285,6 +2299,9 @@ option_clear(config_format_t *fmt, or_options_t *options, config_var_t *var)
     case CONFIG_TYPE_BOOL:
       *(int*)lvalue = 0;
       break;
+    case CONFIG_TYPE_AUTOBOOL:
+      *(int*)lvalue = -1;
+      break;
     case CONFIG_TYPE_MEMUNIT:
       *(uint64_t*)lvalue = 0;
       break;
@@ -2833,24 +2850,24 @@ static int
 compute_publishserverdescriptor(or_options_t *options)
 {
   smartlist_t *list = options->PublishServerDescriptor;
-  authority_type_t *auth = &options->_PublishServerDescriptor;
-  *auth = NO_AUTHORITY;
+  dirinfo_type_t *auth = &options->_PublishServerDescriptor;
+  *auth = NO_DIRINFO;
   if (!list) /* empty list, answer is none */
     return 0;
   SMARTLIST_FOREACH(list, const char *, string, {
     if (!strcasecmp(string, "v1"))
-      *auth |= V1_AUTHORITY;
+      *auth |= V1_DIRINFO;
     else if (!strcmp(string, "1"))
       if (options->BridgeRelay)
-        *auth |= BRIDGE_AUTHORITY;
+        *auth |= BRIDGE_DIRINFO;
       else
-        *auth |= V2_AUTHORITY | V3_AUTHORITY;
+        *auth |= V2_DIRINFO | V3_DIRINFO;
     else if (!strcasecmp(string, "v2"))
-      *auth |= V2_AUTHORITY;
+      *auth |= V2_DIRINFO;
     else if (!strcasecmp(string, "v3"))
-      *auth |= V3_AUTHORITY;
+      *auth |= V3_DIRINFO;
     else if (!strcasecmp(string, "bridge"))
-      *auth |= BRIDGE_AUTHORITY;
+      *auth |= BRIDGE_DIRINFO;
     else if (!strcasecmp(string, "hidserv"))
       log_warn(LD_CONFIG,
                "PublishServerDescriptor hidserv is invalid. See "
@@ -3014,12 +3031,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
       REJECT("Failed to resolve/guess local address. See logs for details.");
   }
 
-  if (strcmp(options->RefuseUnknownExits, "0") &&
-      strcmp(options->RefuseUnknownExits, "1") &&
-      strcmp(options->RefuseUnknownExits, "auto")) {
-    REJECT("RefuseUnknownExits must be 0, 1, or auto");
-  }
-
 #ifndef MS_WINDOWS
   if (options->RunAsDaemon && torrc_fname && path_is_relative(torrc_fname))
     REJECT("Can't use a relative path to torrc when RunAsDaemon is set.");
@@ -3302,9 +3313,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
   }
 
   if ((options->BridgeRelay
-        || options->_PublishServerDescriptor & BRIDGE_AUTHORITY)
+        || options->_PublishServerDescriptor & BRIDGE_DIRINFO)
       && (options->_PublishServerDescriptor
-          & (V1_AUTHORITY|V2_AUTHORITY|V3_AUTHORITY))) {
+          & (V1_DIRINFO|V2_DIRINFO|V3_DIRINFO))) {
     REJECT("Bridges are not supposed to publish router descriptors to the "
            "directory authorities. Please correct your "
            "PublishServerDescriptor line.");
@@ -4543,7 +4554,7 @@ parse_bridge_line(const char *line, int validate_only)
  * bits it's missing) as a valid authority. Return 0 on success,
  * or -1 if the line isn't well-formed or if we can't add it. */
 static int
-parse_dir_server_line(const char *line, authority_type_t required_type,
+parse_dir_server_line(const char *line, dirinfo_type_t required_type,
                       int validate_only)
 {
   smartlist_t *items = NULL;
@@ -4552,7 +4563,7 @@ parse_dir_server_line(const char *line, authority_type_t required_type,
   uint16_t dir_port = 0, or_port = 0;
   char digest[DIGEST_LEN];
   char v3_digest[DIGEST_LEN];
-  authority_type_t type = V2_AUTHORITY;
+  dirinfo_type_t type = V2_DIRINFO;
   int is_not_hidserv_authority = 0, is_not_v2_authority = 0;
 
   items = smartlist_create();
@@ -4573,13 +4584,13 @@ parse_dir_server_line(const char *line, authority_type_t required_type,
     if (TOR_ISDIGIT(flag[0]))
       break;
     if (!strcasecmp(flag, "v1")) {
-      type |= (V1_AUTHORITY | HIDSERV_AUTHORITY);
+      type |= (V1_DIRINFO | HIDSERV_DIRINFO);
     } else if (!strcasecmp(flag, "hs")) {
-      type |= HIDSERV_AUTHORITY;
+      type |= HIDSERV_DIRINFO;
     } else if (!strcasecmp(flag, "no-hs")) {
       is_not_hidserv_authority = 1;
     } else if (!strcasecmp(flag, "bridge")) {
-      type |= BRIDGE_AUTHORITY;
+      type |= BRIDGE_DIRINFO;
     } else if (!strcasecmp(flag, "no-v2")) {
       is_not_v2_authority = 1;
     } else if (!strcasecmpstart(flag, "orport=")) {
@@ -4596,7 +4607,7 @@ parse_dir_server_line(const char *line, authority_type_t required_type,
         log_warn(LD_CONFIG, "Bad v3 identity digest '%s' on DirServer line",
                  flag);
       } else {
-        type |= V3_AUTHORITY;
+        type |= V3_DIRINFO|EXTRAINFO_DIRINFO|MICRODESC_DIRINFO;
       }
     } else {
       log_warn(LD_CONFIG, "Unrecognized flag '%s' on DirServer line",
@@ -4606,9 +4617,9 @@ parse_dir_server_line(const char *line, authority_type_t required_type,
     smartlist_del_keeporder(items, 0);
   }
   if (is_not_hidserv_authority)
-    type &= ~HIDSERV_AUTHORITY;
+    type &= ~HIDSERV_DIRINFO;
   if (is_not_v2_authority)
-    type &= ~V2_AUTHORITY;
+    type &= ~V2_DIRINFO;
 
   if (smartlist_len(items) < 2) {
     log_warn(LD_CONFIG, "Too few arguments to DirServer line.");
@@ -5408,6 +5419,7 @@ getinfo_helper_config(control_connection_t *conn,
         case CONFIG_TYPE_MEMUNIT: type = "DataSize"; break;
         case CONFIG_TYPE_DOUBLE: type = "Float"; break;
         case CONFIG_TYPE_BOOL: type = "Boolean"; break;
+        case CONFIG_TYPE_AUTOBOOL: type = "Boolean+Auto"; break;
         case CONFIG_TYPE_ISOTIME: type = "Time"; break;
         case CONFIG_TYPE_ROUTERSET: type = "RouterList"; break;
         case CONFIG_TYPE_CSV: type = "CommaList"; break;

+ 1 - 1
src/or/control.c

@@ -1847,7 +1847,7 @@ getinfo_helper_events(control_connection_t *control_conn,
       } else if (!strcmp(question, "status/version/num-versioning") ||
                  !strcmp(question, "status/version/num-concurring")) {
         char s[33];
-        tor_snprintf(s, sizeof(s), "%d", get_n_authorities(V3_AUTHORITY));
+        tor_snprintf(s, sizeof(s), "%d", get_n_authorities(V3_DIRINFO));
         *answer = tor_strdup(s);
         log_warn(LD_GENERAL, "%s is deprecated; it no longer gives useful "
                  "information", question);

+ 29 - 28
src/or/directory.c

@@ -147,21 +147,22 @@ purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose)
   return 1;
 }
 
-/** Return a newly allocated string describing <b>auth</b>. */
-char *
-authority_type_to_string(authority_type_t auth)
+/** Return a newly allocated string describing <b>auth</b>. Only describes
+ * authority features. */
+static char *
+authdir_type_to_string(dirinfo_type_t auth)
 {
   char *result;
   smartlist_t *lst = smartlist_create();
-  if (auth & V1_AUTHORITY)
+  if (auth & V1_DIRINFO)
     smartlist_add(lst, (void*)"V1");
-  if (auth & V2_AUTHORITY)
+  if (auth & V2_DIRINFO)
     smartlist_add(lst, (void*)"V2");
-  if (auth & V3_AUTHORITY)
+  if (auth & V3_DIRINFO)
     smartlist_add(lst, (void*)"V3");
-  if (auth & BRIDGE_AUTHORITY)
+  if (auth & BRIDGE_DIRINFO)
     smartlist_add(lst, (void*)"Bridge");
-  if (auth & HIDSERV_AUTHORITY)
+  if (auth & HIDSERV_DIRINFO)
     smartlist_add(lst, (void*)"Hidden service");
   if (smartlist_len(lst)) {
     result = smartlist_join_strings(lst, ", ", 0, NULL);
@@ -280,7 +281,7 @@ directories_have_accepted_server_descriptor(void)
  */
 void
 directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
-                             authority_type_t type,
+                             dirinfo_type_t type,
                              const char *payload,
                              size_t payload_len, size_t extrainfo_len)
 {
@@ -328,7 +329,7 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
                                               NULL, payload, upload_len, 0);
   } SMARTLIST_FOREACH_END(ds);
   if (!found) {
-    char *s = authority_type_to_string(type);
+    char *s = authdir_type_to_string(type);
     log_warn(LD_DIR, "Publishing server descriptor to directory authorities "
              "of type '%s', but no authorities of that type listed!", s);
     tor_free(s);
@@ -349,37 +350,37 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
   or_options_t *options = get_options();
   int prefer_authority = directory_fetches_from_authorities(options);
   int get_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose);
-  authority_type_t type;
+  dirinfo_type_t type;
   time_t if_modified_since = 0;
 
   /* FFFF we could break this switch into its own function, and call
    * it elsewhere in directory.c. -RD */
   switch (dir_purpose) {
     case DIR_PURPOSE_FETCH_EXTRAINFO:
-      type = EXTRAINFO_CACHE |
-             (router_purpose == ROUTER_PURPOSE_BRIDGE ? BRIDGE_AUTHORITY :
-                                                        V3_AUTHORITY);
+      type = EXTRAINFO_DIRINFO |
+             (router_purpose == ROUTER_PURPOSE_BRIDGE ? BRIDGE_DIRINFO :
+                                                        V3_DIRINFO);
       break;
     case DIR_PURPOSE_FETCH_V2_NETWORKSTATUS:
-      type = V2_AUTHORITY;
+      type = V2_DIRINFO;
       break;
     case DIR_PURPOSE_FETCH_SERVERDESC:
-      type = (router_purpose == ROUTER_PURPOSE_BRIDGE ? BRIDGE_AUTHORITY :
-                                                        V3_AUTHORITY);
+      type = (router_purpose == ROUTER_PURPOSE_BRIDGE ? BRIDGE_DIRINFO :
+                                                        V3_DIRINFO);
       break;
     case DIR_PURPOSE_FETCH_RENDDESC:
-      type = HIDSERV_AUTHORITY;
+      type = HIDSERV_DIRINFO;
       break;
     case DIR_PURPOSE_FETCH_STATUS_VOTE:
     case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
-      type = V3_AUTHORITY;
+      type = V3_DIRINFO;
       break;
     case DIR_PURPOSE_FETCH_CONSENSUS:
     case DIR_PURPOSE_FETCH_CERTIFICATE:
-      type = V3_AUTHORITY;
+      type = V3_DIRINFO;
       break;
     case DIR_PURPOSE_FETCH_MICRODESC:
-      type = V3_AUTHORITY;
+      type = MICRODESC_DIRINFO;
       break;
     default:
       log_warn(LD_BUG, "Unexpected purpose %d", (int)dir_purpose);
@@ -407,11 +408,11 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
     }
   }
 
-  if (!options->FetchServerDescriptors && type != HIDSERV_AUTHORITY)
+  if (!options->FetchServerDescriptors && type != HIDSERV_DIRINFO)
     return;
 
   if (!get_via_tor) {
-    if (options->UseBridges && type != BRIDGE_AUTHORITY) {
+    if (options->UseBridges && type != BRIDGE_DIRINFO) {
       /* want to ask a running bridge for which we have a descriptor. */
       /* XXX023 we assume that all of our bridges can answer any
        * possible directory question. This won't be true forever. -RD */
@@ -435,7 +436,7 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
                            "nodes are available yet.");
       return;
     } else {
-      if (prefer_authority || type == BRIDGE_AUTHORITY) {
+      if (prefer_authority || type == BRIDGE_DIRINFO) {
         /* only ask authdirservers, and don't ask myself */
         rs = router_pick_trusteddirserver(type, pds_flags);
         if (rs == NULL && (pds_flags & (PDS_NO_EXISTING_SERVERDESC_FETCH|
@@ -457,7 +458,7 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
           }
         }
       }
-      if (!rs && type != BRIDGE_AUTHORITY) {
+      if (!rs && type != BRIDGE_DIRINFO) {
         /* anybody with a non-zero dirport will do */
         rs = router_pick_directory_server(type, pds_flags);
         if (!rs) {
@@ -474,7 +475,7 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
     if (dir_purpose == DIR_PURPOSE_FETCH_RENDDESC) {
       /* only ask hidserv authorities, any of them will do */
       pds_flags |= PDS_IGNORE_FASCISTFIREWALL|PDS_ALLOW_SELF;
-      rs = router_pick_trusteddirserver(HIDSERV_AUTHORITY, pds_flags);
+      rs = router_pick_trusteddirserver(HIDSERV_DIRINFO, pds_flags);
     } else {
       /* anybody with a non-zero dirport will do. Disregard firewalls. */
       pds_flags |= PDS_IGNORE_FASCISTFIREWALL;
@@ -520,7 +521,7 @@ directory_get_from_all_authorities(uint8_t dir_purpose,
       routerstatus_t *rs;
       if (router_digest_is_me(ds->digest))
         continue;
-      if (!(ds->type & V3_AUTHORITY))
+      if (!(ds->type & V3_DIRINFO))
         continue;
       rs = &ds->fake_status;
       directory_initiate_command_routerstatus(rs, dir_purpose, router_purpose,
@@ -1047,7 +1048,7 @@ directory_get_consensus_url(int supports_conditional_consensus,
                       trusted_dir_server_t *, ds,
       {
         char *hex;
-        if (!(ds->type & V3_AUTHORITY))
+        if (!(ds->type & V3_DIRINFO))
           continue;
 
         hex = tor_malloc(2*CONDITIONAL_CONSENSUS_FPR_LEN+1);

+ 1 - 2
src/or/directory.h

@@ -13,9 +13,8 @@
 #define _TOR_DIRECTORY_H
 
 int directories_have_accepted_server_descriptor(void);
-char *authority_type_to_string(authority_type_t auth);
 void directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
-                                  authority_type_t type, const char *payload,
+                                  dirinfo_type_t type, const char *payload,
                                   size_t payload_len, size_t extrainfo_len);
 void directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
                                   const char *resource,

+ 6 - 6
src/or/dirserv.c

@@ -1552,11 +1552,11 @@ dirserv_pick_cached_dir_obj(cached_dir_t *cache_src,
                             cached_dir_t *auth_src,
                             time_t dirty, cached_dir_t *(*regenerate)(void),
                             const char *name,
-                            authority_type_t auth_type)
+                            dirinfo_type_t auth_type)
 {
   or_options_t *options = get_options();
-  int authority = (auth_type == V1_AUTHORITY && authdir_mode_v1(options)) ||
-                  (auth_type == V2_AUTHORITY && authdir_mode_v2(options));
+  int authority = (auth_type == V1_DIRINFO && authdir_mode_v1(options)) ||
+                  (auth_type == V2_DIRINFO && authdir_mode_v2(options));
 
   if (!authority || authdir_mode_bridge(options)) {
     return cache_src;
@@ -1585,7 +1585,7 @@ dirserv_get_directory(void)
   return dirserv_pick_cached_dir_obj(cached_directory, the_directory,
                                      the_directory_is_dirty,
                                      dirserv_regenerate_directory,
-                                     "v1 server directory", V1_AUTHORITY);
+                                     "v1 server directory", V1_DIRINFO);
 }
 
 /** Only called by v1 auth dirservers.
@@ -1678,7 +1678,7 @@ dirserv_get_runningrouters(void)
                          &cached_runningrouters, &the_runningrouters,
                          runningrouters_is_dirty,
                          generate_runningrouters,
-                         "v1 network status list", V1_AUTHORITY);
+                         "v1 network status list", V1_DIRINFO);
 }
 
 /** Return the latest downloaded consensus networkstatus in encoded, signed,
@@ -2967,7 +2967,7 @@ dirserv_get_networkstatus_v2_fingerprints(smartlist_t *result,
     } else {
       SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
                   trusted_dir_server_t *, ds,
-                  if (ds->type & V2_AUTHORITY)
+                  if (ds->type & V2_DIRINFO)
                     smartlist_add(result, tor_memdup(ds->digest, DIGEST_LEN)));
     }
     smartlist_sort_digests(result);

+ 5 - 5
src/or/dirvote.c

@@ -2742,7 +2742,7 @@ dirvote_perform_vote(void)
 
   directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_VOTE,
                                ROUTER_PURPOSE_GENERAL,
-                               V3_AUTHORITY,
+                               V3_DIRINFO,
                                pending_vote->vote_body->dir,
                                pending_vote->vote_body->dir_len, 0);
   log_notice(LD_DIR, "Vote posted.");
@@ -2761,7 +2761,7 @@ dirvote_fetch_missing_votes(void)
   SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
                     trusted_dir_server_t *, ds,
     {
-      if (!(ds->type & V3_AUTHORITY))
+      if (!(ds->type & V3_DIRINFO))
         continue;
       if (!dirvote_get_vote(ds->v3_identity_digest,
                             DGV_BY_ID|DGV_INCLUDE_PENDING)) {
@@ -2874,7 +2874,7 @@ list_v3_auth_ids(void)
   char *keys;
   SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
                     trusted_dir_server_t *, ds,
-    if ((ds->type & V3_AUTHORITY) &&
+    if ((ds->type & V3_DIRINFO) &&
         !tor_digest_is_zero(ds->v3_identity_digest))
       smartlist_add(known_v3_keys,
                     tor_strdup(hex_str(ds->v3_identity_digest, DIGEST_LEN))));
@@ -3069,7 +3069,7 @@ dirvote_compute_consensuses(void)
   if (!pending_vote_list)
     pending_vote_list = smartlist_create();
 
-  n_voters = get_n_authorities(V3_AUTHORITY);
+  n_voters = get_n_authorities(V3_DIRINFO);
   n_votes = smartlist_len(pending_vote_list);
   if (n_votes <= n_voters/2) {
     log_warn(LD_DIR, "We don't have enough votes to generate a consensus: "
@@ -3208,7 +3208,7 @@ dirvote_compute_consensuses(void)
 
   directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_SIGNATURES,
                                ROUTER_PURPOSE_GENERAL,
-                               V3_AUTHORITY,
+                               V3_DIRINFO,
                                pending_consensus_signatures,
                                strlen(pending_consensus_signatures), 0);
   log_notice(LD_DIR, "Signature(s) posted.");

+ 3 - 6
src/or/main.c

@@ -872,13 +872,11 @@ directory_info_has_arrived(time_t now, int from_cache)
     log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR,
         "I learned some more directory information, but not enough to "
         "build a circuit: %s", get_dir_info_status_string());
-    update_router_descriptor_downloads(now);
-    update_microdesc_downloads(now);
+    update_all_descriptor_downloads(now);
     return;
   } else {
     if (directory_fetches_from_authorities(options)) {
-      update_router_descriptor_downloads(now);
-      update_microdesc_downloads(now);
+      update_all_descriptor_downloads(now);
     }
 
     /* if we have enough dir info, then update our guard status with
@@ -1110,9 +1108,8 @@ run_scheduled_events(time_t now)
   }
 
   if (time_to_try_getting_descriptors < now) {
-    update_router_descriptor_downloads(now);
+    update_all_descriptor_downloads(now);
     update_extrainfo_downloads(now);
-    update_microdesc_downloads(now);
     if (options->UseBridges)
       fetch_bridge_descriptors(options, now);
     if (router_have_minimum_dir_info())

+ 55 - 4
src/or/microdesc.c

@@ -9,6 +9,7 @@
 #include "networkstatus.h"
 #include "nodelist.h"
 #include "policies.h"
+#include "router.h"
 #include "routerlist.h"
 #include "routerparse.h"
 
@@ -251,6 +252,9 @@ microdescs_add_list_to_cache(microdesc_cache_t *cache,
       SMARTLIST_FOREACH(added, microdesc_t *, md, nodelist_add_microdesc(md));
   }
 
+  if (smartlist_len(added))
+    router_dir_info_changed();
+
   return added;
 }
 
@@ -570,6 +574,8 @@ microdesc_list_missing_digest256(networkstatus_t *ns, microdesc_cache_t *cache,
       continue;
     if (skip && digestmap_get(skip, rs->descriptor_digest))
       continue;
+    if (tor_mem_is_zero(rs->descriptor_digest, DIGEST256_LEN))
+      continue; /* This indicates a bug somewhere XXXX023*/
     /* XXXX Also skip if we're a noncache and wouldn't use this router.
      * XXXX NM Microdesc
      */
@@ -602,11 +608,8 @@ update_microdesc_downloads(time_t now)
   if (!consensus)
     return;
 
-  if (!directory_caches_dir_info(options)) {
-    /* Right now, only caches fetch microdescriptors.
-     * XXXX NM Microdescs */
+  if (!we_fetch_microdescriptors(options))
     return;
-  }
 
   pending = digestmap_new();
   list_pending_microdesc_downloads(pending);
@@ -647,3 +650,51 @@ update_microdescs_from_networkstatus(time_t now)
   } SMARTLIST_FOREACH_END(rs);
 }
 
+/** Return true iff we should prefer to use microdescriptors rather than
+ * routerdescs for building circuits. */
+int
+we_use_microdescriptors_for_circuits(or_options_t *options)
+{
+  int ret = options->UseMicrodescriptors;
+  if (ret == -1) {
+    /* UseMicrodescriptors is "auto"; we need to decide: */
+#if 0
+    /* So we decide that we'll use microdescriptors iff we are not a server */
+    ret = ! server_mode(options);
+#else
+    /* We don't use microdescs for now: not enough caches are running
+     * 0.2.3.1-alpha */
+    ret = 0;
+#endif
+  }
+  return ret;
+}
+
+/** Return true iff we should try to download microdescriptors at all. */
+int
+we_fetch_microdescriptors(or_options_t *options)
+{
+  if (directory_caches_dir_info(options))
+    return 1;
+  return we_use_microdescriptors_for_circuits(options);
+}
+
+/** Return true iff we should try to download router descriptors at all. */
+int
+we_fetch_router_descriptors(or_options_t *options)
+{
+  if (directory_caches_dir_info(options))
+    return 1;
+  return ! we_use_microdescriptors_for_circuits(options);
+}
+
+/** Return the consensus flavor we actually want to use to build circuits. */
+int
+usable_consensus_flavor(void)
+{
+  if (we_use_microdescriptors_for_circuits(get_options())) {
+    return FLAV_MICRODESC;
+  } else {
+    return FLAV_NS;
+  }
+}

+ 5 - 0
src/or/microdesc.h

@@ -43,5 +43,10 @@ void microdesc_free_all(void);
 void update_microdesc_downloads(time_t now);
 void update_microdescs_from_networkstatus(time_t now);
 
+int usable_consensus_flavor(void);
+int we_fetch_microdescriptors(or_options_t *options);
+int we_fetch_router_descriptors(or_options_t *options);
+int we_use_microdescriptors_for_circuits(or_options_t *options);
+
 #endif
 

+ 14 - 12
src/or/networkstatus.c

@@ -50,7 +50,9 @@ static strmap_t *unnamed_server_map = NULL;
  * of whichever type we are using for our own circuits.  This will be the same
  * as one of current_ns_consensus or current_md_consensus.
  */
-#define current_consensus current_ns_consensus
+#define current_consensus                                       \
+  (we_use_microdescriptors_for_circuits(get_options()) ?        \
+   current_md_consensus : current_ns_consensus)
 
 /** Most recently received and validated v3 "ns"-flavored consensus network
  * status. */
@@ -482,7 +484,7 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus,
   int n_bad = 0;
   int n_unknown = 0;
   int n_no_signature = 0;
-  int n_v3_authorities = get_n_authorities(V3_AUTHORITY);
+  int n_v3_authorities = get_n_authorities(V3_DIRINFO);
   int n_required = n_v3_authorities/2 + 1;
   smartlist_t *need_certs_from = smartlist_create();
   smartlist_t *unrecognized = smartlist_create();
@@ -553,7 +555,7 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus,
   SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
                     trusted_dir_server_t *, ds,
     {
-      if ((ds->type & V3_AUTHORITY) &&
+      if ((ds->type & V3_DIRINFO) &&
           !networkstatus_get_voter_by_id(consensus, ds->v3_identity_digest))
         smartlist_add(missing_authorities, ds);
     });
@@ -736,7 +738,7 @@ router_set_networkstatus_v2(const char *s, time_t arrived_at,
   base16_encode(fp, HEX_DIGEST_LEN+1, ns->identity_digest, DIGEST_LEN);
   if (!(trusted_dir =
         router_get_trusteddirserver_by_digest(ns->identity_digest)) ||
-      !(trusted_dir->type & V2_AUTHORITY)) {
+      !(trusted_dir->type & V2_DIRINFO)) {
     log_info(LD_DIR, "Network status was signed, but not by an authoritative "
              "directory we recognize.");
     source_desc = fp;
@@ -1130,7 +1132,7 @@ update_v2_networkstatus_cache_downloads(time_t now)
       {
          char resource[HEX_DIGEST_LEN+6]; /* fp/hexdigit.z\0 */
          tor_addr_t addr;
-         if (!(ds->type & V2_AUTHORITY))
+         if (!(ds->type & V2_DIRINFO))
            continue;
          if (router_digest_is_me(ds->digest))
            continue;
@@ -1187,7 +1189,7 @@ we_want_to_fetch_flavor(or_options_t *options, int flavor)
   }
   /* Otherwise, we want the flavor only if we want to use it to build
    * circuits. */
-  return (flavor == USABLE_CONSENSUS_FLAVOR);
+  return flavor == usable_consensus_flavor();
 }
 
 /** How many times will we try to fetch a consensus before we give up? */
@@ -1392,7 +1394,7 @@ update_certificate_downloads(time_t now)
 int
 consensus_is_waiting_for_certs(void)
 {
-  return consensus_waiting_for_certs[USABLE_CONSENSUS_FLAVOR].consensus
+  return consensus_waiting_for_certs[usable_consensus_flavor()].consensus
     ? 1 : 0;
 }
 
@@ -1621,7 +1623,7 @@ networkstatus_set_current_consensus(const char *consensus,
     flavor = networkstatus_get_flavor_name(flav);
   }
 
-  if (flav != USABLE_CONSENSUS_FLAVOR &&
+  if (flav != usable_consensus_flavor() &&
       !directory_caches_dir_info(options)) {
     /* This consensus is totally boring to us: we won't use it, and we won't
      * serve it.  Drop it. */
@@ -1726,14 +1728,14 @@ networkstatus_set_current_consensus(const char *consensus,
     }
   }
 
-  if (!from_cache && flav == USABLE_CONSENSUS_FLAVOR)
+  if (!from_cache && flav == usable_consensus_flavor())
     control_event_client_status(LOG_NOTICE, "CONSENSUS_ARRIVED");
 
   /* Are we missing any certificates at all? */
   if (r != 1 && dl_certs)
     authority_certs_fetch_missing(c, now);
 
-  if (flav == USABLE_CONSENSUS_FLAVOR) {
+  if (flav == usable_consensus_flavor()) {
     notify_control_networkstatus_changed(current_consensus, c);
   }
   if (flav == FLAV_NS) {
@@ -1780,8 +1782,8 @@ networkstatus_set_current_consensus(const char *consensus,
       download_status_failed(&consensus_dl_status[flav], 0);
   }
 
-  if (flav == USABLE_CONSENSUS_FLAVOR) {
-    /* XXXXNM Microdescs: needs a non-ns variant. */
+  if (flav == usable_consensus_flavor()) {
+    /* XXXXNM Microdescs: needs a non-ns variant. ???? NM*/
     update_consensus_networkstatus_fetch_time(now);
 
     nodelist_set_consensus(current_consensus);

+ 32 - 21
src/or/or.h

@@ -1641,6 +1641,9 @@ typedef struct routerstatus_t {
   /** True iff this router is a version that, if it caches directory info,
    * we can get v3 downloads from. */
   unsigned int version_supports_v3_dir:1;
+  /** True iff this router is a version that, if it caches directory info,
+   * we can get microdescriptors from. */
+  unsigned int version_supports_microdesc_cache:1;
 
   unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */
   unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */
@@ -1918,9 +1921,6 @@ typedef enum {
   FLAV_MICRODESC = 1,
 } consensus_flavor_t;
 
-/** Which consensus flavor do we actually want to use to build circuits? */
-#define USABLE_CONSENSUS_FLAVOR FLAV_NS
-
 /** How many different consensus flavors are there? */
 #define N_CONSENSUS_FLAVORS ((int)(FLAV_MICRODESC)+1)
 
@@ -2090,24 +2090,33 @@ typedef struct authority_cert_t {
   uint8_t is_cross_certified;
 } authority_cert_t;
 
-/** Bitfield enum type listing types of directory authority/directory
- * server.  */
+/** Bitfield enum type listing types of information that directory authorities
+ * can be authoritative about, and that directory caches may or may not cache.
+ *
+ * Note that the granularity here is based on authority granularity and on
+ * cache capabilities.  Thus, one particular bit may correspond in practice to
+ * a few types of directory info, so long as every authority that pronounces
+ * officially about one of the types prounounces officially about all of them,
+ * and so long as every cache that caches one of them caches all of them.
+ */
 typedef enum {
-  NO_AUTHORITY      = 0,
+  NO_DIRINFO      = 0,
   /** Serves/signs v1 directory information: Big lists of routers, and short
    * routerstatus documents. */
-  V1_AUTHORITY      = 1 << 0,
+  V1_DIRINFO      = 1 << 0,
   /** Serves/signs v2 directory information: i.e. v2 networkstatus documents */
-  V2_AUTHORITY      = 1 << 1,
+  V2_DIRINFO      = 1 << 1,
   /** Serves/signs v3 directory information: votes, consensuses, certs */
-  V3_AUTHORITY      = 1 << 2,
+  V3_DIRINFO      = 1 << 2,
   /** Serves hidden service descriptors. */
-  HIDSERV_AUTHORITY = 1 << 3,
+  HIDSERV_DIRINFO = 1 << 3,
   /** Serves bridge descriptors. */
-  BRIDGE_AUTHORITY  = 1 << 4,
-  /** Serves extrainfo documents. (XXX Not precisely an authority type)*/
-  EXTRAINFO_CACHE   = 1 << 5,
-} authority_type_t;
+  BRIDGE_DIRINFO  = 1 << 4,
+  /** Serves extrainfo documents. */
+  EXTRAINFO_DIRINFO=1 << 5,
+  /** Serves microdescriptors. */
+  MICRODESC_DIRINFO=1 << 6,
+} dirinfo_type_t;
 
 #define CRYPT_PATH_MAGIC 0x70127012u
 
@@ -2641,8 +2650,8 @@ typedef struct {
   /** To what authority types do we publish our descriptor? Choices are
    * "v1", "v2", "v3", "bridge", or "". */
   smartlist_t *PublishServerDescriptor;
-  /** An authority type, derived from PublishServerDescriptor. */
-  authority_type_t _PublishServerDescriptor;
+  /** A bitfield of authority types, derived from PublishServerDescriptor. */
+  dirinfo_type_t _PublishServerDescriptor;
   /** Boolean: do we publish hidden service descriptors to the HS auths? */
   int PublishHidServDescriptors;
   int FetchServerDescriptors; /**< Do we fetch server descriptors as normal? */
@@ -2669,12 +2678,10 @@ typedef struct {
   uint64_t ConstrainedSockSize; /**< Size of constrained buffers. */
 
   /** Whether we should drop exit streams from Tors that we don't know are
-   * relays.  One of "0" (never refuse), "1" (always refuse), or "auto" (do
+   * relays.  One of "0" (never refuse), "1" (always refuse), or "-1" (do
    * what the consensus says, defaulting to 'refuse' if the consensus says
    * nothing). */
-  char *RefuseUnknownExits;
-  /** Parsed version of RefuseUnknownExits. -1 for auto. */
-  int RefuseUnknownExits_;
+  int RefuseUnknownExits;
 
   /** Application ports that require all nodes in circ to have sufficient
    * uptime. */
@@ -3044,6 +3051,10 @@ typedef struct {
    * the defaults have changed. */
   int _UsingTestNetworkDefaults;
 
+  /** If 1, we try to use microdescriptors to build circuits.  If 0, we don't.
+   * If -1, Tor decides. */
+  int UseMicrodescriptors;
+
 } or_options_t;
 
 /** Persistent state for an onion router, as saved to disk. */
@@ -3650,7 +3661,7 @@ typedef struct trusted_dir_server_t {
   unsigned int has_accepted_serverdesc:1;
 
   /** What kind of authority is this? (Bitfield.) */
-  authority_type_t type;
+  dirinfo_type_t type;
 
   download_status_t v2_ns_dl_status; /**< Status of downloading this server's
                                * v2 network status. */

+ 15 - 14
src/or/router.c

@@ -497,7 +497,7 @@ init_keys(void)
   char v3_digest[20];
   char *cp;
   or_options_t *options = get_options();
-  authority_type_t type;
+  dirinfo_type_t type;
   time_t now = time(NULL);
   trusted_dir_server_t *ds;
   int v3_digest_set = 0;
@@ -697,11 +697,12 @@ init_keys(void)
   }
   /* 6b. [authdirserver only] add own key to approved directories. */
   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) |
-          (options->BridgeAuthoritativeDir ? BRIDGE_AUTHORITY : NO_AUTHORITY) |
-          (options->HSAuthoritativeDir ? HIDSERV_AUTHORITY : NO_AUTHORITY));
+  type = ((options->V1AuthoritativeDir ? V1_DIRINFO : NO_DIRINFO) |
+          (options->V2AuthoritativeDir ? V2_DIRINFO : NO_DIRINFO) |
+          (options->V3AuthoritativeDir ?
+               (V3_DIRINFO|MICRODESC_DIRINFO|EXTRAINFO_DIRINFO) : NO_DIRINFO) |
+          (options->BridgeAuthoritativeDir ? BRIDGE_DIRINFO : NO_DIRINFO) |
+          (options->HSAuthoritativeDir ? HIDSERV_DIRINFO : NO_DIRINFO));
 
   ds = router_get_trusteddirserver_by_digest(digest);
   if (!ds) {
@@ -723,7 +724,7 @@ init_keys(void)
              type, ds->type);
     ds->type = type;
   }
-  if (v3_digest_set && (ds->type & V3_AUTHORITY) &&
+  if (v3_digest_set && (ds->type & V3_DIRINFO) &&
       memcmp(v3_digest, ds->v3_identity_digest, DIGEST_LEN)) {
     log_warn(LD_DIR, "V3 identity key does not match identity declared in "
              "DirServer line.  Adjusting.");
@@ -910,7 +911,7 @@ router_orport_found_reachable(void)
   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 ?
+               get_options()->_PublishServerDescriptor != NO_DIRINFO ?
                  " Publishing server descriptor." : "");
     can_reach_or_port = 1;
     mark_my_descriptor_dirty();
@@ -1080,8 +1081,8 @@ public_server_mode(or_options_t *options)
 int
 should_refuse_unknown_exits(or_options_t *options)
 {
-  if (options->RefuseUnknownExits_ != -1) {
-    return options->RefuseUnknownExits_;
+  if (options->RefuseUnknownExits != -1) {
+    return options->RefuseUnknownExits;
   } else {
     return networkstatus_get_param(NULL, "refuseunknownexits", 1, 0, 1);
   }
@@ -1135,7 +1136,7 @@ decide_if_publishable_server(void)
 
   if (options->ClientOnly)
     return 0;
-  if (options->_PublishServerDescriptor == NO_AUTHORITY)
+  if (options->_PublishServerDescriptor == NO_DIRINFO)
     return 0;
   if (!server_mode(options))
     return 0;
@@ -1195,7 +1196,7 @@ router_upload_dir_desc_to_dirservers(int force)
   extrainfo_t *ei;
   char *msg;
   size_t desc_len, extra_len = 0, total_len;
-  authority_type_t auth = get_options()->_PublishServerDescriptor;
+  dirinfo_type_t auth = get_options()->_PublishServerDescriptor;
 
   ri = router_get_my_routerinfo();
   if (!ri) {
@@ -1203,7 +1204,7 @@ router_upload_dir_desc_to_dirservers(int force)
     return;
   }
   ei = router_get_my_extrainfo();
-  if (auth == NO_AUTHORITY)
+  if (auth == NO_DIRINFO)
     return;
   if (!force && !desc_needs_upload)
     return;
@@ -1220,7 +1221,7 @@ router_upload_dir_desc_to_dirservers(int force)
   msg[desc_len+extra_len] = 0;
 
   directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_DIR,
-                               (auth & BRIDGE_AUTHORITY) ?
+                               (auth & BRIDGE_DIRINFO) ?
                                  ROUTER_PURPOSE_BRIDGE :
                                  ROUTER_PURPOSE_GENERAL,
                                auth, msg, desc_len, extra_len);

+ 81 - 65
src/or/routerlist.c

@@ -40,9 +40,9 @@
 
 /* static function prototypes */
 static const routerstatus_t *router_pick_directory_server_impl(
-                                           authority_type_t auth, int flags);
+                                           dirinfo_type_t auth, int flags);
 static const routerstatus_t *router_pick_trusteddirserver_impl(
-                          authority_type_t auth, int flags, int *n_busy_out);
+                          dirinfo_type_t auth, int flags, int *n_busy_out);
 static void mark_all_trusteddirservers_up(void);
 static int router_nickname_matches(const routerinfo_t *router,
                                    const char *nickname);
@@ -56,6 +56,8 @@ static const char *signed_descriptor_get_body_impl(
                                               int with_annotations);
 static void list_pending_downloads(digestmap_t *result,
                                    int purpose, const char *prefix);
+static void launch_dummy_descriptor_download_as_needed(time_t now,
+                                                       or_options_t *options);
 
 DECLARE_TYPED_DIGESTMAP_FNS(sdmap_, digest_sd_map_t, signed_descriptor_t)
 DECLARE_TYPED_DIGESTMAP_FNS(rimap_, digest_ri_map_t, routerinfo_t)
@@ -97,7 +99,7 @@ static smartlist_t *warned_nicknames = NULL;
 /** The last time we tried to download any routerdesc, or 0 for "never".  We
  * use this to rate-limit download attempts when the number of routerdescs to
  * download is low. */
-static time_t last_routerdesc_download_attempted = 0;
+static time_t last_descriptor_download_attempted = 0;
 
 /** When we last computed the weights to use for bandwidths on directory
  * requests, what were the total weighted bandwidth, and our share of that
@@ -109,7 +111,7 @@ static uint64_t sl_last_total_weighted_bw = 0,
 /** Return the number of directory authorities whose type matches some bit set
  * in <b>type</b>  */
 int
-get_n_authorities(authority_type_t type)
+get_n_authorities(dirinfo_type_t type)
 {
   int n = 0;
   if (!trusted_dir_servers)
@@ -120,7 +122,7 @@ get_n_authorities(authority_type_t type)
   return n;
 }
 
-#define get_n_v2_authorities() get_n_authorities(V2_AUTHORITY)
+#define get_n_v2_authorities() get_n_authorities(V2_DIRINFO)
 
 /** Helper: Return the cert_list_t for an authority whose authority ID is
  * <b>id_digest</b>, allocating a new list if necessary. */
@@ -518,7 +520,7 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now)
   }
   SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, trusted_dir_server_t *, ds) {
     int found = 0;
-    if (!(ds->type & V3_AUTHORITY))
+    if (!(ds->type & V3_DIRINFO))
       continue;
     if (smartlist_digest_isin(missing_digests, ds->v3_identity_digest))
       continue;
@@ -931,7 +933,7 @@ router_get_trusted_dir_servers(void)
  * servers that have returned 503 recently.
  */
 const routerstatus_t *
-router_pick_directory_server(authority_type_t type, int flags)
+router_pick_directory_server(dirinfo_type_t type, int flags)
 {
   const routerstatus_t *choice;
   if (get_options()->PreferTunneledDirConns)
@@ -976,7 +978,7 @@ router_get_my_share_of_directory_requests(double *v2_share_out,
   /* XXXX This is a bit of a kludge */
   if (rs->is_v2_dir) {
     sl_last_total_weighted_bw = 0;
-    router_pick_directory_server(V2_AUTHORITY, pds_flags);
+    router_pick_directory_server(V2_DIRINFO, pds_flags);
     if (sl_last_total_weighted_bw != 0) {
       *v2_share_out = U64_TO_DBL(sl_last_weighted_bw_of_me) /
         U64_TO_DBL(sl_last_total_weighted_bw);
@@ -985,7 +987,7 @@ router_get_my_share_of_directory_requests(double *v2_share_out,
 
   if (rs->version_supports_v3_dir) {
     sl_last_total_weighted_bw = 0;
-    router_pick_directory_server(V3_AUTHORITY, pds_flags);
+    router_pick_directory_server(V3_DIRINFO, pds_flags);
     if (sl_last_total_weighted_bw != 0) {
       *v3_share_out = U64_TO_DBL(sl_last_weighted_bw_of_me) /
         U64_TO_DBL(sl_last_total_weighted_bw);
@@ -1026,7 +1028,7 @@ trusteddirserver_get_by_v3_auth_digest(const char *digest)
   SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
      {
        if (!memcmp(ds->v3_identity_digest, digest, DIGEST_LEN) &&
-           (ds->type & V3_AUTHORITY))
+           (ds->type & V3_DIRINFO))
          return ds;
      });
 
@@ -1037,7 +1039,7 @@ trusteddirserver_get_by_v3_auth_digest(const char *digest)
  * router_pick_directory_server.
  */
 const routerstatus_t *
-router_pick_trusteddirserver(authority_type_t type, int flags)
+router_pick_trusteddirserver(dirinfo_type_t type, int flags)
 {
   const routerstatus_t *choice;
   int busy = 0;
@@ -1073,7 +1075,7 @@ router_pick_trusteddirserver(authority_type_t type, int flags)
  * that we can use with BEGINDIR.
  */
 static const routerstatus_t *
-router_pick_directory_server_impl(authority_type_t type, int flags)
+router_pick_directory_server_impl(dirinfo_type_t type, int flags)
 {
   or_options_t *options = get_options();
   const node_t *result;
@@ -1115,18 +1117,21 @@ router_pick_directory_server_impl(authority_type_t type, int flags)
       continue;
     if (requireother && router_digest_is_me(node->identity))
       continue;
-    if (type & V3_AUTHORITY) {
+    if (type & V3_DIRINFO) {
       if (!(status->version_supports_v3_dir ||
             router_digest_is_trusted_dir_type(node->identity,
-                                              V3_AUTHORITY)))
+                                              V3_DIRINFO)))
         continue;
     }
     is_trusted = router_digest_is_trusted_dir(node->identity);
-    if ((type & V2_AUTHORITY) && !(node->rs->is_v2_dir || is_trusted))
+    if ((type & V2_DIRINFO) && !(node->rs->is_v2_dir || is_trusted))
       continue;
-    if ((type & EXTRAINFO_CACHE) &&
+    if ((type & EXTRAINFO_DIRINFO) &&
         !router_supports_extrainfo(node->identity, 0))
       continue;
+    if ((type & MICRODESC_DIRINFO) && !is_trusted &&
+        !node->rs->version_supports_microdesc_cache)
+      continue;
     if (try_excluding && options->ExcludeNodes &&
         routerset_contains_routerstatus(options->ExcludeNodes, status,
                                         country)) {
@@ -1192,7 +1197,7 @@ router_pick_directory_server_impl(authority_type_t type, int flags)
  * are as for router_pick_directory_server_impl().
  */
 static const routerstatus_t *
-router_pick_trusteddirserver_impl(authority_type_t type, int flags,
+router_pick_trusteddirserver_impl(dirinfo_type_t type, int flags,
                                   int *n_busy_out)
 {
   or_options_t *options = get_options();
@@ -1227,7 +1232,7 @@ router_pick_trusteddirserver_impl(authority_type_t type, int flags,
       if (!d->is_running) continue;
       if ((type & d->type) == 0)
         continue;
-      if ((type & EXTRAINFO_CACHE) &&
+      if ((type & EXTRAINFO_DIRINFO) &&
           !router_supports_extrainfo(d->digest, 1))
         continue;
       if (requireother && me && router_digest_is_me(d->digest))
@@ -2443,23 +2448,11 @@ router_get_by_nickname(const char *nickname, int warn_if_unnamed)
 #endif
 }
 
-/** Try to find a routerinfo for <b>digest</b>. If we don't have one,
- * return 1. If we do, ask tor_version_as_new_as() for the answer.
- */
-int
-router_digest_version_as_new_as(const char *digest, const char *cutoff)
-{
-  const routerinfo_t *router = router_get_by_id_digest(digest);
-  if (!router)
-    return 1;
-  return tor_version_as_new_as(router->platform, cutoff);
-}
-
 /** Return true iff <b>digest</b> is the digest of the identity key of a
  * trusted directory matching at least one bit of <b>type</b>.  If <b>type</b>
  * is zero, any authority is okay. */
 int
-router_digest_is_trusted_dir_type(const char *digest, authority_type_t type)
+router_digest_is_trusted_dir_type(const char *digest, dirinfo_type_t type)
 {
   if (!trusted_dir_servers)
     return 0;
@@ -4000,6 +3993,16 @@ signed_desc_digest_is_recognized(signed_descriptor_t *desc)
   return 0;
 }
 
+/** Update downloads for router descriptors and/or microdescriptors as
+ * appropriate. */
+void
+update_all_descriptor_downloads(time_t now)
+{
+  update_router_descriptor_downloads(now);
+  update_microdesc_downloads(now);
+  launch_dummy_descriptor_download_as_needed(now, get_options());
+}
+
 /** Clear all our timeouts for fetching v2 and v3 directory stuff, and then
  * give it all a try again. */
 void
@@ -4008,8 +4011,7 @@ routerlist_retry_directory_downloads(time_t now)
   router_reset_status_download_failures();
   router_reset_descriptor_download_failures();
   update_networkstatus_downloads(now);
-  update_router_descriptor_downloads(now);
-  update_microdesc_downloads(now);
+  update_all_descriptor_downloads(now);
 }
 
 /** Return 1 if all running sufficiently-stable routers we can use will reject
@@ -4049,7 +4051,7 @@ trusted_dir_server_t *
 add_trusted_dir_server(const char *nickname, const char *address,
                        uint16_t dir_port, uint16_t or_port,
                        const char *digest, const char *v3_auth_digest,
-                       authority_type_t type)
+                       dirinfo_type_t type)
 {
   trusted_dir_server_t *ent;
   uint32_t a;
@@ -4084,7 +4086,7 @@ add_trusted_dir_server(const char *nickname, const char *address,
   ent->is_running = 1;
   ent->type = type;
   memcpy(ent->digest, digest, DIGEST_LEN);
-  if (v3_auth_digest && (type & V3_AUTHORITY))
+  if (v3_auth_digest && (type & V3_DIRINFO))
     memcpy(ent->v3_identity_digest, v3_auth_digest, DIGEST_LEN);
 
   dlen = 64 + strlen(hostname) + (nickname?strlen(nickname):0);
@@ -4163,7 +4165,7 @@ int
 any_trusted_dir_is_v1_authority(void)
 {
   if (trusted_dir_servers)
-    return get_n_authorities(V1_AUTHORITY) > 0;
+    return get_n_authorities(V1_DIRINFO) > 0;
 
   return 0;
 }
@@ -4363,15 +4365,15 @@ launch_descriptor_downloads(int purpose,
                 descname);
       should_delay = 0;
     } else {
-      should_delay = (last_routerdesc_download_attempted +
+      should_delay = (last_descriptor_download_attempted +
                       MAX_CLIENT_INTERVAL_WITHOUT_REQUEST) > now;
       if (!should_delay && n_downloadable) {
-        if (last_routerdesc_download_attempted) {
+        if (last_descriptor_download_attempted) {
           log_info(LD_DIR,
                    "There are not many downloadable %ss, but we've "
                    "been waiting long enough (%d seconds). Downloading.",
                    descname,
-                   (int)(now-last_routerdesc_download_attempted));
+                   (int)(now-last_descriptor_download_attempted));
         } else {
           log_info(LD_DIR,
                    "There are not many downloadable %ss, but we haven't "
@@ -4434,7 +4436,7 @@ launch_descriptor_downloads(int purpose,
                                     downloadable, i, i+n_per_request,
                                     pds_flags);
     }
-    last_routerdesc_download_attempted = now;
+    last_descriptor_download_attempted = now;
   }
 }
 
@@ -4718,30 +4720,19 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
  * do this only when we aren't seeing incoming data. see bug 652. */
 #define DUMMY_DOWNLOAD_INTERVAL (20*60)
 
-/** Launch downloads for router status as needed. */
-void
-update_router_descriptor_downloads(time_t now)
+/** As needed, launch a dummy router descriptor fetch to see if our
+ * address has changed. */
+static void
+launch_dummy_descriptor_download_as_needed(time_t now, or_options_t *options)
 {
-  or_options_t *options = get_options();
   static time_t last_dummy_download = 0;
-  if (should_delay_dir_fetches(options))
-    return;
-  if (directory_fetches_dir_info_early(options)) {
-    update_router_descriptor_cache_downloads_v2(now);
-  }
-
-  update_consensus_router_descriptor_downloads(now, 0,
-                  networkstatus_get_reasonably_live_consensus(now, FLAV_NS));
-
   /* XXXX023 we could be smarter here; see notes on bug 652. */
-  /* XXXX NM Microdescs: if we're not fetching microdescriptors, we need
-   * to make something else invoke this. */
   /* If we're a server that doesn't have a configured address, we rely on
    * directory fetches to learn when our address changes.  So if we haven't
    * tried to get any routerdescs in a long time, try a dummy fetch now. */
   if (!options->Address &&
       server_mode(options) &&
-      last_routerdesc_download_attempted + DUMMY_DOWNLOAD_INTERVAL < now &&
+      last_descriptor_download_attempted + DUMMY_DOWNLOAD_INTERVAL < now &&
       last_dummy_download + DUMMY_DOWNLOAD_INTERVAL < now) {
     last_dummy_download = now;
     directory_get_from_dirserver(DIR_PURPOSE_FETCH_SERVERDESC,
@@ -4750,6 +4741,23 @@ update_router_descriptor_downloads(time_t now)
   }
 }
 
+/** Launch downloads for router status as needed. */
+void
+update_router_descriptor_downloads(time_t now)
+{
+  or_options_t *options = get_options();
+  if (should_delay_dir_fetches(options))
+    return;
+  if (!we_fetch_router_descriptors(options))
+    return;
+  if (directory_fetches_dir_info_early(options)) {
+    update_router_descriptor_cache_downloads_v2(now);
+  }
+
+  update_consensus_router_descriptor_downloads(now, 0,
+                  networkstatus_get_reasonably_live_consensus(now, FLAV_NS));
+}
+
 /** Launch extrainfo downloads as needed. */
 void
 update_extrainfo_downloads(time_t now)
@@ -4879,20 +4887,28 @@ count_usable_descriptors(int *num_present, int *num_usable,
                          or_options_t *options, time_t now,
                          routerset_t *in_set)
 {
+  const int md = (consensus->flavor == FLAV_MICRODESC);
   *num_present = 0, *num_usable=0;
 
-  SMARTLIST_FOREACH(consensus->routerstatus_list, routerstatus_t *, rs,
-     {
+  SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, routerstatus_t *, rs)
+    {
        if (in_set && ! routerset_contains_routerstatus(in_set, rs, -1))
          continue;
        if (client_would_use_router(rs, now, options)) {
+         const char * const digest = rs->descriptor_digest;
+         int present;
          ++*num_usable; /* the consensus says we want it. */
-         if (router_get_by_descriptor_digest(rs->descriptor_digest)) {
+         if (md)
+           present = NULL != (microdesc_cache_lookup_by_digest256(NULL, digest));
+         else
+           present = NULL != router_get_by_descriptor_digest(digest);
+         if (present) {
            /* we have the descriptor listed in the consensus. */
            ++*num_present;
          }
        }
-     });
+     }
+  SMARTLIST_FOREACH_END(rs);
 
   log_debug(LD_DIR, "%d usable, %d present.", *num_usable, *num_present);
 }
@@ -4906,7 +4922,7 @@ count_loading_descriptors_progress(void)
   int num_present = 0, num_usable=0;
   time_t now = time(NULL);
   const networkstatus_t *consensus =
-    networkstatus_get_reasonably_live_consensus(now, FLAV_NS);
+    networkstatus_get_reasonably_live_consensus(now, usable_consensus_flavor());
   double fraction;
 
   if (!consensus)
@@ -4936,14 +4952,14 @@ update_router_have_minimum_dir_info(void)
   int res;
   or_options_t *options = get_options();
   const networkstatus_t *consensus =
-    networkstatus_get_reasonably_live_consensus(now, FLAV_NS);
+    networkstatus_get_reasonably_live_consensus(now, usable_consensus_flavor());
 
   if (!consensus) {
     if (!networkstatus_get_latest_consensus())
-      strlcpy(dir_info_status, "We have no network-status consensus.",
+      strlcpy(dir_info_status, "We have no usable consensus.",
               sizeof(dir_info_status));
     else
-      strlcpy(dir_info_status, "We have no recent network-status consensus.",
+      strlcpy(dir_info_status, "We have no recent usable consensus.",
               sizeof(dir_info_status));
     res = 0;
     goto done;
@@ -5022,7 +5038,7 @@ void
 router_reset_descriptor_download_failures(void)
 {
   networkstatus_reset_download_failures();
-  last_routerdesc_download_attempted = 0;
+  last_descriptor_download_attempted = 0;
   if (!routerlist)
     return;
   SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, ri,

+ 7 - 7
src/or/routerlist.h

@@ -11,7 +11,7 @@
 #ifndef _TOR_ROUTERLIST_H
 #define _TOR_ROUTERLIST_H
 
-int get_n_authorities(authority_type_t type);
+int get_n_authorities(dirinfo_type_t type);
 int trusted_dirs_reload_certs(void);
 int trusted_dirs_load_certs_from_string(const char *contents, int from_store,
                                         int flush);
@@ -27,11 +27,11 @@ int router_reload_router_list(void);
 int authority_cert_dl_looks_uncertain(const char *id_digest);
 smartlist_t *router_get_trusted_dir_servers(void);
 
-const routerstatus_t *router_pick_directory_server(authority_type_t type,
+const routerstatus_t *router_pick_directory_server(dirinfo_type_t type,
                                                    int flags);
 trusted_dir_server_t *router_get_trusteddirserver_by_digest(const char *d);
 trusted_dir_server_t *trusteddirserver_get_by_v3_auth_digest(const char *d);
-const routerstatus_t *router_pick_trusteddirserver(authority_type_t type,
+const routerstatus_t *router_pick_trusteddirserver(dirinfo_type_t type,
                                                    int flags);
 int router_get_my_share_of_directory_requests(double *v2_share_out,
                                               double *v3_share_out);
@@ -56,11 +56,10 @@ const node_t *router_choose_random_node(smartlist_t *excludedsmartlist,
 
 const routerinfo_t *router_get_by_nickname(const char *nickname,
                                      int warn_if_unnamed);
-int router_digest_version_as_new_as(const char *digest, const char *cutoff);
 int router_digest_is_trusted_dir_type(const char *digest,
-                                      authority_type_t type);
+                                      dirinfo_type_t type);
 #define router_digest_is_trusted_dir(d) \
-  router_digest_is_trusted_dir_type((d), NO_AUTHORITY)
+  router_digest_is_trusted_dir_type((d), NO_DIRINFO)
 
 int router_addr_is_trusted_dir(uint32_t addr);
 int hexdigest_to_digest(const char *hexdigest, char *digest);
@@ -138,13 +137,14 @@ trusted_dir_server_t *add_trusted_dir_server(const char *nickname,
                            const char *address,
                            uint16_t dir_port, uint16_t or_port,
                            const char *digest, const char *v3_auth_digest,
-                           authority_type_t type);
+                           dirinfo_type_t type);
 void authority_cert_free(authority_cert_t *cert);
 void clear_trusted_dir_servers(void);
 int any_trusted_dir_is_v1_authority(void);
 void update_consensus_router_descriptor_downloads(time_t now, int is_vote,
                                                   networkstatus_t *consensus);
 void update_router_descriptor_downloads(time_t now);
+void update_all_descriptor_downloads(time_t now);
 void update_extrainfo_downloads(time_t now);
 int router_have_minimum_dir_info(void);
 void router_dir_info_changed(void);

+ 9 - 0
src/or/routerparse.c

@@ -2085,6 +2085,7 @@ routerstatus_parse_entry_from_string(memarea_t *area,
       rs->version_supports_begindir = 1;
       rs->version_supports_extrainfo_upload = 1;
       rs->version_supports_conditional_consensus = 1;
+      rs->version_supports_microdesc_cache = 1;
     } else {
       rs->version_supports_begindir =
         tor_version_as_new_as(tok->args[0], "0.2.0.1-alpha");
@@ -2094,6 +2095,14 @@ routerstatus_parse_entry_from_string(memarea_t *area,
         tor_version_as_new_as(tok->args[0], "0.2.0.8-alpha");
       rs->version_supports_conditional_consensus =
         tor_version_as_new_as(tok->args[0], "0.2.1.1-alpha");
+      /* XXXX023 NM microdescs: 0.2.3.1-alpha isn't widely used yet, but
+       * not all 0.2.3.0-alpha "versions" actually support microdesc cacheing
+       * right.  There's a compromise here.  Since this is 5 May, let's
+       * err on the side of having some possible caches to use.  Once more
+       * caches are running 0.2.3.1-alpha, we can bump this version number.
+       */
+      rs->version_supports_microdesc_cache =
+        tor_version_as_new_as(tok->args[0], "0.2.3.0-alpha");
     }
     if (vote_rs) {
       vote_rs->version = tor_strdup(tok->args[0]);