[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r8571: Disprefer exit nodes for entry, middle positions (fixes bug (in tor/trunk: . doc src/or)



Author: nickm
Date: 2006-10-01 17:59:09 -0400 (Sun, 01 Oct 2006)
New Revision: 8571

Modified:
   tor/trunk/
   tor/trunk/ChangeLog
   tor/trunk/doc/TODO
   tor/trunk/doc/path-spec.txt
   tor/trunk/src/or/circuitbuild.c
   tor/trunk/src/or/or.h
   tor/trunk/src/or/rendservice.c
   tor/trunk/src/or/routerlist.c
Log:
 r8826@totoro:  nickm | 2006-10-01 17:58:45 -0400
 Disprefer exit nodes for entry, middle positions (fixes bug 200).  Also, switch to using a uint64_t to hold "total bandwidth for all nodes" under consideration; crypt_rand_int would have died at 2GB/s network capacity.



Property changes on: tor/trunk
___________________________________________________________________
 svk:merge ticket from /tor/trunk [r8826] on 96637b51-b116-0410-a10e-9941ebb49b64

Modified: tor/trunk/ChangeLog
===================================================================
--- tor/trunk/ChangeLog	2006-10-01 21:59:05 UTC (rev 8570)
+++ tor/trunk/ChangeLog	2006-10-01 21:59:09 UTC (rev 8571)
@@ -47,6 +47,9 @@
       and including the function name only seems to confuse users.
     - Fix CIRC controller events so that controllers can learn the identity
       digests of non-Named servers used in circuit paths. (Fixes bug 336.)
+    - Avoid choosing Exit nodes for entry or middle hops when the bandwidth
+      available in non-Exit nodes is much higher then the bandwidth available
+      in Exit nodes. (Fixes bug 200.)
 
   o Security Fixes, minor:
     - If a client asked for a server by name, and we didn't have a
@@ -93,6 +96,8 @@
       With the old code, if a guard was unreachable by us but listed as
       running, it would clog our guard list forever.
     - Make eventdns give strings for DNS errors, not just error numbers.
+    - Be prepared in case we ever have a network with  more than 2GB per
+      second total advertised capacity.
 
   o Documentation
     - Documented (and renamed) ServerDNSSearchDomains and

Modified: tor/trunk/doc/TODO
===================================================================
--- tor/trunk/doc/TODO	2006-10-01 21:59:05 UTC (rev 8570)
+++ tor/trunk/doc/TODO	2006-10-01 21:59:09 UTC (rev 8571)
@@ -35,12 +35,10 @@
       D The right thing here is to revamp our node selection implementation.
         (Deferred until oprofile says this matters.)
     o make it configurable, so people can turn it on or off.
-N - Add script to grep for identical log msgs.
-N - Bug 200: disprefer exit nodes for entry, middle.
-    - If less than 1/3 support port X, only use as exit.
-    - If 2/3 support port X, weight exits 1/2; weight non-exits 1.
-    - (Exit fraction - 1/3):Non-exit fraction
-    - (e - 1/3)/(1-e)
+  o Add script to grep for identical log msgs.
+  o Bug 200: disprefer exit nodes for entry, middle.
+    o Specify
+    o Implement
   o Bug 303: block exit from circuits created with create-fast
     o Specify and document
     o Implement

Modified: tor/trunk/doc/path-spec.txt
===================================================================
--- tor/trunk/doc/path-spec.txt	2006-10-01 21:59:05 UTC (rev 8570)
+++ tor/trunk/doc/path-spec.txt	2006-10-01 21:59:09 UTC (rev 8571)
@@ -157,16 +157,25 @@
        below)
      - XXXX Choosing the length
 
-   For circuits that are not "fast", when choosing among multiple
-   candidates for a path element, we choose randomly. For "fast" circuits,
-   we choose
-   a given router with probability proportional to its advertised bandwidth
-   [the smaller of the 'rate' and 'observed' arguments to the "bandwidth"
-   element in its descriptor].  If a router's advertised bandwidth is greater
-   than MAX_BELIEVEABLE_BANDWIDTH (1.5 MB/sec), we clip to that value.
+   For circuits that do not need to be not "fast", when choosing among
+   multiple candidates for a path element, we choose randomly.
 
-   (XXXX We should do something to shift traffic away from exit nodes.)
+   For "fast" circuits, we a given router as an exit with probability
+   proportional to its advertised bandwidth [the smaller of the 'rate' and
+   'observed' arguments to the "bandwidth" element in its descriptor].  If a
+   router's advertised bandwidth is greater than MAX_BELIEVEABLE_BANDWIDTH
+   (1.5 MB/sec), we clip to that value.
 
+   For non-exit positions on "fast" circuits, we pick routers as above, but
+   we weight the clipped advertised bandwidth of Exit-flagged nodes depending
+   on the fraction of bandwidth available from non-Exit nodes.  Call the
+   total clipped advertised bandwidth for Exit nodes under consideration E,
+   and the total clipped advertised bandwidth for non-Exit nodes under
+   consideration N.  If E<N/2, we do not consider Exit-flagged nodes.
+   Otherwise, we weight their bandwidth with the factor (E-N/2)/(N+E-N/2) ==
+   (2E - N)/(2E + N).  This ensures that bandwidth is evenly distributed over
+   nodes in 3-hop paths.
+
    Additionally, we may be building circuits with one or more requests in
    mind.  Each kind of request puts certain constraints on paths:
 

Modified: tor/trunk/src/or/circuitbuild.c
===================================================================
--- tor/trunk/src/or/circuitbuild.c	2006-10-01 21:59:05 UTC (rev 8570)
+++ tor/trunk/src/or/circuitbuild.c	2006-10-01 21:59:09 UTC (rev 8571)
@@ -1199,7 +1199,7 @@
     smartlist_subtract(sl,excludedexits);
     if (options->StrictExitNodes || smartlist_overlap(sl,preferredexits))
       smartlist_intersect(sl,preferredexits);
-    router = routerlist_sl_choose_by_bandwidth(sl);
+    router = routerlist_sl_choose_by_bandwidth(sl, 1);
   } else {
     /* Either there are no pending connections, or no routers even seem to
      * possibly support any of them.  Choose a router at random that satisfies
@@ -1238,7 +1238,7 @@
         smartlist_intersect(sl,preferredexits);
         /* XXX sometimes the above results in null, when the requested
          * exit node is down. we should pick it anyway. */
-      router = routerlist_sl_choose_by_bandwidth(sl);
+      router = routerlist_sl_choose_by_bandwidth(sl, 1);
       if (router)
         break;
     }
@@ -1282,14 +1282,14 @@
       if (is_internal) /* pick it like a middle hop */
         return router_choose_random_node(NULL, get_options()->ExcludeNodes,
                NULL, need_uptime, need_capacity, 0,
-               get_options()->_AllowInvalid & ALLOW_INVALID_MIDDLE, 0);
+               get_options()->_AllowInvalid & ALLOW_INVALID_MIDDLE, 0, 0);
       else
         return choose_good_exit_server_general(dir,need_uptime,need_capacity);
     case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
       return router_choose_random_node(
                options->RendNodes, options->RendExcludeNodes,
                NULL, need_uptime, need_capacity, 0,
-               options->_AllowInvalid & ALLOW_INVALID_RENDEZVOUS, 0);
+               options->_AllowInvalid & ALLOW_INVALID_RENDEZVOUS, 0, 0);
   }
   log_warn(LD_BUG,"Bug: unhandled purpose %d", purpose);
   tor_fragile_assert();
@@ -1508,7 +1508,7 @@
   choice = router_choose_random_node(preferred,
            options->ExcludeNodes, excluded,
            state->need_uptime, state->need_capacity, 0,
-           options->_AllowInvalid & ALLOW_INVALID_MIDDLE, 0);
+           options->_AllowInvalid & ALLOW_INVALID_MIDDLE, 0, 0);
   if (preferred)
     tor_free(preferred);
   smartlist_free(excluded);
@@ -1571,7 +1571,7 @@
            excluded, state ? state->need_uptime : 0,
            state ? state->need_capacity : 0,
            state ? 0 : 1,
-           options->_AllowInvalid & ALLOW_INVALID_ENTRY, 0);
+           options->_AllowInvalid & ALLOW_INVALID_ENTRY, 0, 0);
   smartlist_free(excluded);
   return choice;
 }

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2006-10-01 21:59:05 UTC (rev 8570)
+++ tor/trunk/src/or/or.h	2006-10-01 21:59:09 UTC (rev 8571)
@@ -918,6 +918,7 @@
   unsigned int is_fast:1; /** Do we think this is a fast OR? */
   unsigned int is_stable:1; /** Do we think this is a stable OR? */
   unsigned int is_possible_guard:1; /**< Do we think this is an OK guard? */
+  unsigned int is_exit:1; /**< Do we think this is an OK exit? */
 
 /** Tor can use this desc for circuit-building. */
 #define ROUTER_PURPOSE_GENERAL 0
@@ -2562,13 +2563,15 @@
 int router_is_unreliable(routerinfo_t *router, int need_uptime,
                          int need_capacity, int need_guard);
 uint32_t router_get_advertised_bandwidth(routerinfo_t *router);
-routerinfo_t *routerlist_sl_choose_by_bandwidth(smartlist_t *sl);
+routerinfo_t *routerlist_sl_choose_by_bandwidth(smartlist_t *sl, int for_exit);
+
 routerinfo_t *router_choose_random_node(const char *preferred,
                                         const char *excluded,
                                         smartlist_t *excludedsmartlist,
                                         int need_uptime, int need_bandwidth,
                                         int need_guard,
-                                        int allow_invalid, int strict);
+                                        int allow_invalid, int strict,
+                                        int weight_for_exit);
 routerinfo_t *router_get_by_nickname(const char *nickname,
                                      int warn_if_unnamed);
 routerinfo_t *router_get_by_hexdigest(const char *hexdigest);

Modified: tor/trunk/src/or/rendservice.c
===================================================================
--- tor/trunk/src/or/rendservice.c	2006-10-01 21:59:05 UTC (rev 8570)
+++ tor/trunk/src/or/rendservice.c	2006-10-01 21:59:09 UTC (rev 8571)
@@ -1005,7 +1005,7 @@
       router = router_choose_random_node(service->intro_prefer_nodes,
                service->intro_exclude_nodes, exclude_routers, 1, 0, 0,
                get_options()->_AllowInvalid & ALLOW_INVALID_INTRODUCTION,
-               0);
+               0, 0);
       if (!router) {
         log_warn(LD_REND,
                  "Could only establish %d introduction points for %s.",

Modified: tor/trunk/src/or/routerlist.c
===================================================================
--- tor/trunk/src/or/routerlist.c	2006-10-01 21:59:05 UTC (rev 8570)
+++ tor/trunk/src/or/routerlist.c	2006-10-01 21:59:09 UTC (rev 8571)
@@ -884,46 +884,70 @@
  * the advertised bandwidth of each router.
  */
 routerinfo_t *
-routerlist_sl_choose_by_bandwidth(smartlist_t *sl)
+routerlist_sl_choose_by_bandwidth(smartlist_t *sl, int for_exit)
 {
   int i;
   routerinfo_t *router;
-  smartlist_t *bandwidths;
-  uint32_t this_bw, tmp, total_bw=0, rand_bw;
-  uint32_t *p;
+  uint32_t *bandwidths;
+  uint32_t this_bw;
+  uint64_t total_nonexit_bw = 0, total_exit_bw = 0, total_bw = 0;
+  uint64_t rand_bw, tmp;
+  double exit_weight;
 
   /* First count the total bandwidth weight, and make a smartlist
    * of each value. */
-  bandwidths = smartlist_create();
+  bandwidths = tor_malloc(sizeof(uint32_t)*smartlist_len(sl));
   for (i = 0; i < smartlist_len(sl); ++i) {
     router = smartlist_get(sl, i);
     this_bw = router_get_advertised_bandwidth(router);
     /* if they claim something huge, don't believe it */
     if (this_bw > MAX_BELIEVABLE_BANDWIDTH)
       this_bw = MAX_BELIEVABLE_BANDWIDTH;
-    p = tor_malloc(sizeof(uint32_t));
-    *p = this_bw;
-    smartlist_add(bandwidths, p);
-    total_bw += this_bw;
+    bandwidths[i] = this_bw;
+    if (router->is_exit)
+      total_exit_bw += this_bw;
+    else
+      total_nonexit_bw += this_bw;
   }
-  if (!total_bw) {
-    SMARTLIST_FOREACH(bandwidths, uint32_t*, p, tor_free(p));
-    smartlist_free(bandwidths);
+  if (!(total_exit_bw+total_nonexit_bw)) {
+    tor_free(bandwidths);
     return smartlist_choose(sl);
   }
+  if (for_exit) {
+    exit_weight = 1.0;
+    total_bw = total_exit_bw + total_nonexit_bw;
+  } else if (total_exit_bw < total_nonexit_bw / 2) {
+    exit_weight = 0.0;
+    total_bw = total_nonexit_bw;
+  } else {
+    uint64_t leftover = (total_exit_bw - total_nonexit_bw / 2);
+    exit_weight = U64_TO_DBL(leftover) /
+      U64_TO_DBL(leftover + total_nonexit_bw);
+    total_bw =  total_nonexit_bw +
+      DBL_TO_U64(exit_weight * U64_TO_DBL(total_exit_bw));
+  }
+  /*
+  log_debug(LD_CIRC, "Total bw = "U64_FORMAT", total exit bw = "U64_FORMAT
+            ", total nonexit bw = "U64_FORMAT", exit weight = %lf "
+            "(for exit == %d)",
+            U64_PRINTF_ARG(total_bw), U64_PRINTF_ARG(total_exit_bw),
+            U64_PRINTF_ARG(total_nonexit_bw), exit_weight, for_exit);
+  */
+
   /* Second, choose a random value from the bandwidth weights. */
-  rand_bw = crypto_rand_int(total_bw);
+  rand_bw = crypto_rand_uint64(total_bw);
   /* Last, count through sl until we get to the element we picked */
   tmp = 0;
-  for (i=0; ; i++) {
-    tor_assert(i < smartlist_len(sl));
-    p = smartlist_get(bandwidths, i);
-    tmp += *p;
+  for (i=0; i < smartlist_len(sl); i++) {
+    router = smartlist_get(sl, i);
+    if (router->is_exit)
+      tmp += ((uint64_t)(bandwidths[i] * exit_weight));
+    else
+      tmp += bandwidths[i];
     if (tmp >= rand_bw)
       break;
   }
-  SMARTLIST_FOREACH(bandwidths, uint32_t*, p, tor_free(p));
-  smartlist_free(bandwidths);
+  tor_free(bandwidths);
   return (routerinfo_t *)smartlist_get(sl, i);
 }
 
@@ -944,7 +968,8 @@
                           smartlist_t *excludedsmartlist,
                           int need_uptime, int need_capacity,
                           int need_guard,
-                          int allow_invalid, int strict)
+                          int allow_invalid, int strict,
+                          int weight_for_exit)
 {
   smartlist_t *sl, *excludednodes;
   routerinfo_t *choice = NULL;
@@ -975,8 +1000,8 @@
       smartlist_subtract(sl,excludedsmartlist);
     routerlist_sl_remove_unreliable_routers(sl, need_uptime,
                                             need_capacity, need_guard);
-    if (need_capacity)
-      choice = routerlist_sl_choose_by_bandwidth(sl);
+    if (need_capacity) /* XXXX Is this documented in path spec. -NM */
+      choice = routerlist_sl_choose_by_bandwidth(sl, weight_for_exit);
     else
       choice = smartlist_choose(sl);
     smartlist_free(sl);
@@ -989,7 +1014,8 @@
                need_uptime?", stable":"",
                need_guard?", guard":"");
       choice = router_choose_random_node(
-        NULL, excluded, excludedsmartlist, 0, 0, 0, allow_invalid, 0);
+        NULL, excluded, excludedsmartlist,
+        0, 0, 0, allow_invalid, 0, weight_for_exit);
     }
   }
   smartlist_free(excludednodes);
@@ -3422,6 +3448,7 @@
       router->is_fast = rs->status.is_fast;
       router->is_stable = rs->status.is_stable;
       router->is_possible_guard = rs->status.is_possible_guard;
+      router->is_exit =  rs->status.is_exit;
     }
     if (router->is_running && ds) {
       ds->n_networkstatus_failures = 0;