Pārlūkot izejas kodu

r11820@Kushana: nickm | 2007-01-03 14:54:05 -0500
Add (and specify) a BadDirectory flag to networkstatuses, so authorities can tell clients that some caches are broken. Also, implement an as-yet-unused function to estimate how many bytes will be sent on a directory connection.


svn:r9255

Nick Mathewson 18 gadi atpakaļ
vecāks
revīzija
2963d4acc2
7 mainītis faili ar 62 papildinājumiem un 6 dzēšanām
  1. 2 0
      ChangeLog
  2. 3 3
      doc/TODO
  3. 6 0
      doc/dir-spec.txt
  4. 29 0
      src/or/dirserv.c
  5. 8 2
      src/or/or.h
  6. 10 1
      src/or/routerlist.c
  7. 4 0
      src/or/routerparse.c

+ 2 - 0
ChangeLog

@@ -76,6 +76,8 @@ Changes in version 0.1.2.5-alpha - 2007-01-03
     - When we change nameservers or IP addresses, reset and re-launch
     - When we change nameservers or IP addresses, reset and re-launch
       our tests for DNS hijacking.
       our tests for DNS hijacking.
     - Block an obscure DoS attack from directory caches.
     - Block an obscure DoS attack from directory caches.
+    - Add a BadDirectory flag to network status docs so that authorities
+      can (eventually) tell clients about caches they believe to be broken.
 
 
   o Security bugfixes:
   o Security bugfixes:
     - Stop sending the HttpProxyAuthenticator string to directory
     - Stop sending the HttpProxyAuthenticator string to directory

+ 3 - 3
doc/TODO

@@ -86,7 +86,7 @@ N - DNS improvements
         D But eventually, we give up after getting a lot of 503s.
         D But eventually, we give up after getting a lot of 503s.
         D Delay when we get a lot of 503s, rather than punting onto the
         D Delay when we get a lot of 503s, rather than punting onto the
           servers that have given us 503s?
           servers that have given us 503s?
-N       - Add a 'BadDirectory' flag to statuses.
+        o Add a 'BadDirectory' flag to statuses.
       - authorities should *never* 503 a cache, and should never 503
       - authorities should *never* 503 a cache, and should never 503
         network status requests. They can 503 client descriptor requests
         network status requests. They can 503 client descriptor requests
         when they feel like it.
         when they feel like it.
@@ -136,8 +136,8 @@ R   - "bandwidth classes", for incoming vs initiated-here conns,
       and to give dir conns lower priority.
       and to give dir conns lower priority.
     . Write limiting; separate token bucket for write
     . Write limiting; separate token bucket for write
       o preemptively give a 503 to some v1 dir requests
       o preemptively give a 503 to some v1 dir requests
-      - preemptively give a 503 to some v2 dir requests
+R     - preemptively give a 503 to some v2 dir requests
-        - Write function to estimate bytes needed for N descriptors
+        o Write function to estimate bytes needed for N descriptors
           statuses
           statuses
       D per-conn write buckets
       D per-conn write buckets
       D separate config options for read vs write limiting
       D separate config options for read vs write limiting

+ 6 - 0
doc/dir-spec.txt

@@ -347,6 +347,8 @@ $Id$
           "Versions" if this directory authority recommends software versions.
           "Versions" if this directory authority recommends software versions.
           "BadExits" if the directory authority flags nodes that it believes
           "BadExits" if the directory authority flags nodes that it believes
               are performing incorrectly as exit nodes.
               are performing incorrectly as exit nodes.
+          "BadDirectories" if the directory authority flags nodes that it
+              believes are performing incorrectly as directory caches.
 
 
    The dir-options entry is optional.  The "-versions" entries are required if
    The dir-options entry is optional.  The "-versions" entries are required if
    the "Versions" flag is present.  The other entries are required and must
    the "Versions" flag is present.  The other entries are required and must
@@ -376,6 +378,10 @@ $Id$
           "BadExit" if the router is believed to be useless as an exit node
           "BadExit" if the router is believed to be useless as an exit node
              (because its ISP censors it, because it is behind a restrictive
              (because its ISP censors it, because it is behind a restrictive
              proxy, or for some similar reason).
              proxy, or for some similar reason).
+          "BadDirectory" if the router is believed to be useless as a
+             directory cache (because its directory port isn't working;
+             because its bandwidth is always throttled, or for some
+             similar reason).
           "Exit" if the router is useful for building general-purpose exit
           "Exit" if the router is useful for building general-purpose exit
              circuits.
              circuits.
           "Fast" if the router is suitable for high-bandwidth circuits.
           "Fast" if the router is suitable for high-bandwidth circuits.

+ 29 - 0
src/or/dirserv.c

@@ -1882,6 +1882,35 @@ dirserv_test_reachability(int try_all)
     ctr = (ctr + 1) % 128;
     ctr = (ctr + 1) % 128;
 }
 }
 
 
+/** Return an approximate estimate of the number of bytes that will be needed
+ * to transmit the server descriptors (if is_serverdescs) or networkstatus
+ * objects (if !is_serverdescs) listed in <b>fps</b>.  If <b>compressed</b> is
+ * set, we guess how large the data will be after compression.
+ *
+ * The return value is an estimate; it might be larger or smaller.
+ **/
+size_t
+dirserv_estimate_data_size(smartlist_t *fps, int is_serverdescs,
+                           int compressed)
+{
+  size_t result;
+  if (is_serverdescs) {
+    int n = smartlist_len(fps);
+    routerinfo_t *me = router_get_my_routerinfo();
+    result = (me?me->cache_info.signed_descriptor_len:2048) * n;
+    if (compressed)
+      result /= 2; /* observed compressability is between 35 and 55%. */
+  } else {
+    result = 0;
+    SMARTLIST_FOREACH(fps, const char *, d, {
+        cached_dir_t *dir = digestmap_get(cached_v2_networkstatus, d);
+        if (dir)
+          result += compressed ? dir->dir_z_len : dir->dir_len;
+      });
+  }
+  return result;
+}
+
 /** When we're spooling data onto our outbuf, add more whenever we dip
 /** When we're spooling data onto our outbuf, add more whenever we dip
  * below this threshold. */
  * below this threshold. */
 #define DIRSERV_BUFFER_MIN 16384
 #define DIRSERV_BUFFER_MIN 16384

+ 8 - 2
src/or/or.h

@@ -1012,6 +1012,8 @@ typedef struct routerstatus_t {
                                      * choice as an entry guard. */
                                      * choice as an entry guard. */
   unsigned int is_bad_exit:1; /**< True iff this node is a bad choice for
   unsigned int is_bad_exit:1; /**< True iff this node is a bad choice for
                                * an exit node. */
                                * an exit node. */
+  unsigned int is_bad_directory:1; /**< Do we think this directory is junky,
+                                    * underpowered, or otherwise useless? */
 
 
   /** True iff we know version info for this router. (i.e., a "v" entry was
   /** True iff we know version info for this router. (i.e., a "v" entry was
    * included.)  We'll replace all these with a big tor_version_t or a char[]
    * included.)  We'll replace all these with a big tor_version_t or a char[]
@@ -1081,9 +1083,11 @@ typedef struct networkstatus_t {
   unsigned int recommends_versions:1; /**< True iff this directory server
   unsigned int recommends_versions:1; /**< True iff this directory server
                                        * recommends client and server software
                                        * recommends client and server software
                                        * versions. */
                                        * versions. */
-  unsigned int lists_bad_exits:1; /** True iff this directory server marks
+  unsigned int lists_bad_exits:1; /**< True iff this directory server marks
                                    * malfunctioning exits as bad. */
                                    * malfunctioning exits as bad. */
-
+  /** True iff this directory server marks malfunctioning directories as
+   * bad. */
+  unsigned int lists_bad_directories:1;
   smartlist_t *entries; /**< List of routerstatus_t*.   This list is kept
   smartlist_t *entries; /**< List of routerstatus_t*.   This list is kept
                          * sorted by identity_digest. */
                          * sorted by identity_digest. */
 } networkstatus_t;
 } networkstatus_t;
@@ -2319,6 +2323,8 @@ void dirserv_test_reachability(int try_all);
 int authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
 int authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
                                    int complain);
                                    int complain);
 int dirserv_would_reject_router(routerstatus_t *rs);
 int dirserv_would_reject_router(routerstatus_t *rs);
+size_t dirserv_estimate_data_size(smartlist_t *fps, int is_serverdescs,
+                                  int compressed);
 void dirserv_free_all(void);
 void dirserv_free_all(void);
 void cached_dir_decref(cached_dir_t *d);
 void cached_dir_decref(cached_dir_t *d);
 
 

+ 10 - 1
src/or/routerlist.c

@@ -546,6 +546,8 @@ router_pick_directory_server_impl(int requireother, int fascistfirewall,
     int is_overloaded = _local_status->last_dir_503_at + DIR_503_TIMEOUT > now;
     int is_overloaded = _local_status->last_dir_503_at + DIR_503_TIMEOUT > now;
     if (!status->is_running || !status->dir_port || !status->is_valid)
     if (!status->is_running || !status->dir_port || !status->is_valid)
       continue;
       continue;
+    if (status->is_bad_directory)
+      continue;
     if (requireother && router_digest_is_me(status->identity_digest))
     if (requireother && router_digest_is_me(status->identity_digest))
       continue;
       continue;
     is_trusted = router_digest_is_trusted_dir(status->identity_digest);
     is_trusted = router_digest_is_trusted_dir(status->identity_digest);
@@ -3212,7 +3214,7 @@ routerstatus_list_update_from_networkstatus(time_t now)
 {
 {
   or_options_t *options = get_options();
   or_options_t *options = get_options();
   int n_trusted, n_statuses, n_recent = 0, n_naming = 0;
   int n_trusted, n_statuses, n_recent = 0, n_naming = 0;
-  int n_listing_bad_exits = 0;
+  int n_listing_bad_exits = 0, n_listing_bad_directories = 0;
   int i, j, warned;
   int i, j, warned;
   int *index, *size;
   int *index, *size;
   networkstatus_t **networkstatus;
   networkstatus_t **networkstatus;
@@ -3262,6 +3264,8 @@ routerstatus_list_update_from_networkstatus(time_t now)
       ++n_recent;
       ++n_recent;
     if (networkstatus[i]->lists_bad_exits)
     if (networkstatus[i]->lists_bad_exits)
       ++n_listing_bad_exits;
       ++n_listing_bad_exits;
+    if (networkstatus[i]->lists_bad_directories)
+      ++n_listing_bad_directories;
   }
   }
 
 
   /** Iterate over all entries in all networkstatuses, and build
   /** Iterate over all entries in all networkstatuses, and build
@@ -3333,6 +3337,7 @@ routerstatus_list_update_from_networkstatus(time_t now)
   while (1) {
   while (1) {
     int n_running=0, n_named=0, n_valid=0, n_listing=0;
     int n_running=0, n_named=0, n_valid=0, n_listing=0;
     int n_v2_dir=0, n_fast=0, n_stable=0, n_exit=0, n_guard=0, n_bad_exit=0;
     int n_v2_dir=0, n_fast=0, n_stable=0, n_exit=0, n_guard=0, n_bad_exit=0;
+    int n_bad_directory=0;
     int n_version_known=0, n_supports_begindir=0;
     int n_version_known=0, n_supports_begindir=0;
     int n_desc_digests=0, highest_count=0;
     int n_desc_digests=0, highest_count=0;
     const char *the_name = NULL;
     const char *the_name = NULL;
@@ -3421,6 +3426,8 @@ routerstatus_list_update_from_networkstatus(time_t now)
         ++n_v2_dir;
         ++n_v2_dir;
       if (rs->is_bad_exit)
       if (rs->is_bad_exit)
         ++n_bad_exit;
         ++n_bad_exit;
+      if (rs->is_bad_directory)
+        ++n_bad_directory;
       if (rs->version_known)
       if (rs->version_known)
         ++n_version_known;
         ++n_version_known;
       if (rs->version_supports_begindir)
       if (rs->version_supports_begindir)
@@ -3475,6 +3482,8 @@ routerstatus_list_update_from_networkstatus(time_t now)
     rs_out->status.is_stable = n_stable > n_statuses/2;
     rs_out->status.is_stable = n_stable > n_statuses/2;
     rs_out->status.is_v2_dir = n_v2_dir > n_statuses/2;
     rs_out->status.is_v2_dir = n_v2_dir > n_statuses/2;
     rs_out->status.is_bad_exit = n_bad_exit > n_listing_bad_exits/2;
     rs_out->status.is_bad_exit = n_bad_exit > n_listing_bad_exits/2;
+    rs_out->status.is_bad_directory =
+      n_bad_directory > n_listing_bad_directories/2;
     rs_out->status.version_known = n_version_known > 0;
     rs_out->status.version_known = n_version_known > 0;
     rs_out->status.version_supports_begindir =
     rs_out->status.version_supports_begindir =
       n_supports_begindir > n_version_known/2;
       n_supports_begindir > n_version_known/2;

+ 4 - 0
src/or/routerparse.c

@@ -1077,6 +1077,8 @@ routerstatus_parse_entry_from_string(const char **s, smartlist_t *tokens)
         rs->is_possible_guard = 1;
         rs->is_possible_guard = 1;
       else if (!strcmp(tok->args[i], "BadExit"))
       else if (!strcmp(tok->args[i], "BadExit"))
         rs->is_bad_exit = 1;
         rs->is_bad_exit = 1;
+      else if (!strcmp(tok->args[i], "BadDirectory"))
+        rs->is_bad_directory = 1;
     }
     }
   }
   }
   if ((tok = find_first_by_keyword(tokens, K_V))) {
   if ((tok = find_first_by_keyword(tokens, K_V))) {
@@ -1224,6 +1226,8 @@ networkstatus_parse_from_string(const char *s)
         ns->recommends_versions = 1;
         ns->recommends_versions = 1;
       if (!strcmp(tok->args[i], "BadExits"))
       if (!strcmp(tok->args[i], "BadExits"))
         ns->lists_bad_exits = 1;
         ns->lists_bad_exits = 1;
+      if (!strcmp(tok->args[i], "BadDirectories"))
+        ns->lists_bad_directories = 1;
     }
     }
   }
   }