|  | @@ -643,7 +643,8 @@ router_nickname_is_in_list(routerinfo_t *router, const char *list)
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  static void
 | 
	
		
			
				|  |  |  router_add_running_routers_to_smartlist(smartlist_t *sl, int allow_unverified,
 | 
	
		
			
				|  |  | -                                        int need_uptime, int need_capacity)
 | 
	
		
			
				|  |  | +                                        int need_uptime, int need_capacity,
 | 
	
		
			
				|  |  | +                                        int need_guard)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    if (!routerlist)
 | 
	
		
			
				|  |  |      return;
 | 
	
	
		
			
				|  | @@ -653,7 +654,8 @@ router_add_running_routers_to_smartlist(smartlist_t *sl, int allow_unverified,
 | 
	
		
			
				|  |  |      if (router->is_running &&
 | 
	
		
			
				|  |  |          (router->is_verified ||
 | 
	
		
			
				|  |  |          (allow_unverified &&
 | 
	
		
			
				|  |  | -         !router_is_unreliable(router, need_uptime, need_capacity)))) {
 | 
	
		
			
				|  |  | +         !router_is_unreliable(router, need_uptime,
 | 
	
		
			
				|  |  | +                               need_capacity, need_guard)))) {
 | 
	
		
			
				|  |  |        /* If it's running, and either it's verified or we're ok picking
 | 
	
		
			
				|  |  |         * unverified routers and this one is suitable.
 | 
	
		
			
				|  |  |         */
 | 
	
	
		
			
				|  | @@ -709,25 +711,30 @@ router_find_exact_exit_enclave(const char *address, uint16_t port)
 | 
	
		
			
				|  |  |   * bandwidth.
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  | -router_is_unreliable(routerinfo_t *router, int need_uptime, int need_capacity)
 | 
	
		
			
				|  |  | +router_is_unreliable(routerinfo_t *router, int need_uptime,
 | 
	
		
			
				|  |  | +                     int need_capacity, int need_guard)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    if (need_uptime && !router->is_stable)
 | 
	
		
			
				|  |  |      return 1;
 | 
	
		
			
				|  |  |    if (need_capacity && !router->is_fast)
 | 
	
		
			
				|  |  |      return 1;
 | 
	
		
			
				|  |  | +  if (need_guard && !router->is_possible_guard)
 | 
	
		
			
				|  |  | +    return 1;
 | 
	
		
			
				|  |  |    return 0;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -/** Remove from routerlist <b>sl</b> all routers who have a low uptime. */
 | 
	
		
			
				|  |  | +/** Remove from routerlist <b>sl</b> all routers that are not
 | 
	
		
			
				|  |  | + * sufficiently stable. */
 | 
	
		
			
				|  |  |  static void
 | 
	
		
			
				|  |  | -routerlist_sl_remove_unreliable_routers(smartlist_t *sl)
 | 
	
		
			
				|  |  | +routerlist_sl_remove_unreliable_routers(smartlist_t *sl,
 | 
	
		
			
				|  |  | +                                        int need_uptime, int need_guard)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    int i;
 | 
	
		
			
				|  |  |    routerinfo_t *router;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    for (i = 0; i < smartlist_len(sl); ++i) {
 | 
	
		
			
				|  |  |      router = smartlist_get(sl, i);
 | 
	
		
			
				|  |  | -    if (router_is_unreliable(router, 1, 0)) {
 | 
	
		
			
				|  |  | +    if (router_is_unreliable(router, need_uptime, 0, need_guard)) {
 | 
	
		
			
				|  |  |  //      log(LOG_DEBUG, "Router '%s' has insufficient uptime; deleting.",
 | 
	
		
			
				|  |  |   //         router->nickname);
 | 
	
		
			
				|  |  |        smartlist_del(sl, i--);
 | 
	
	
		
			
				|  | @@ -801,6 +808,7 @@ router_choose_random_node(const char *preferred,
 | 
	
		
			
				|  |  |                            const char *excluded,
 | 
	
		
			
				|  |  |                            smartlist_t *excludedsmartlist,
 | 
	
		
			
				|  |  |                            int need_uptime, int need_capacity,
 | 
	
		
			
				|  |  | +                          int need_guard,
 | 
	
		
			
				|  |  |                            int allow_unverified, int strict)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    smartlist_t *sl, *excludednodes;
 | 
	
	
		
			
				|  | @@ -809,8 +817,8 @@ router_choose_random_node(const char *preferred,
 | 
	
		
			
				|  |  |    excludednodes = smartlist_create();
 | 
	
		
			
				|  |  |    add_nickname_list_to_smartlist(excludednodes,excluded,0,0,1);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* Try the preferred nodes first. Ignore need_uptime and need_capacity,
 | 
	
		
			
				|  |  | -   * since the user explicitly asked for these nodes. */
 | 
	
		
			
				|  |  | +  /* Try the preferred nodes first. Ignore need_uptime and need_capacity
 | 
	
		
			
				|  |  | +   * and need_guard, since the user explicitly asked for these nodes. */
 | 
	
		
			
				|  |  |    if (preferred) {
 | 
	
		
			
				|  |  |      sl = smartlist_create();
 | 
	
		
			
				|  |  |      add_nickname_list_to_smartlist(sl,preferred,1,1,1);
 | 
	
	
		
			
				|  | @@ -825,25 +833,27 @@ router_choose_random_node(const char *preferred,
 | 
	
		
			
				|  |  |       * will do that has the required attributes. */
 | 
	
		
			
				|  |  |      sl = smartlist_create();
 | 
	
		
			
				|  |  |      router_add_running_routers_to_smartlist(sl, allow_unverified,
 | 
	
		
			
				|  |  | -                                            need_uptime, need_capacity);
 | 
	
		
			
				|  |  | +                                            need_uptime, need_capacity,
 | 
	
		
			
				|  |  | +                                            need_guard);
 | 
	
		
			
				|  |  |      smartlist_subtract(sl,excludednodes);
 | 
	
		
			
				|  |  |      if (excludedsmartlist)
 | 
	
		
			
				|  |  |        smartlist_subtract(sl,excludedsmartlist);
 | 
	
		
			
				|  |  | -    if (need_uptime)
 | 
	
		
			
				|  |  | -      routerlist_sl_remove_unreliable_routers(sl);
 | 
	
		
			
				|  |  | +    if (need_uptime || need_guard)
 | 
	
		
			
				|  |  | +      routerlist_sl_remove_unreliable_routers(sl, need_uptime, need_guard);
 | 
	
		
			
				|  |  |      if (need_capacity)
 | 
	
		
			
				|  |  |        choice = routerlist_sl_choose_by_bandwidth(sl);
 | 
	
		
			
				|  |  |      else
 | 
	
		
			
				|  |  |        choice = smartlist_choose(sl);
 | 
	
		
			
				|  |  |      smartlist_free(sl);
 | 
	
		
			
				|  |  | -    if (!choice && (need_uptime || need_capacity)) {
 | 
	
		
			
				|  |  | +    if (!choice && (need_uptime || need_capacity || need_guard)) {
 | 
	
		
			
				|  |  |        /* try once more -- recurse but with fewer restrictions. */
 | 
	
		
			
				|  |  | -      info(LD_CIRC, "We couldn't find any live%s%s routers; falling back "
 | 
	
		
			
				|  |  | +      info(LD_CIRC, "We couldn't find any live%s%s%s routers; falling back "
 | 
	
		
			
				|  |  |             "to list of all routers.",
 | 
	
		
			
				|  |  |             need_capacity?", fast":"",
 | 
	
		
			
				|  |  | -           need_uptime?", stable":"");
 | 
	
		
			
				|  |  | +           need_uptime?", stable":"",
 | 
	
		
			
				|  |  | +           need_guard?", guard":"");
 | 
	
		
			
				|  |  |        choice = router_choose_random_node(
 | 
	
		
			
				|  |  | -        NULL, excluded, excludedsmartlist, 0, 0, allow_unverified, 0);
 | 
	
		
			
				|  |  | +        NULL, excluded, excludedsmartlist, 0, 0, 0, allow_unverified, 0);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    smartlist_free(excludednodes);
 | 
	
	
		
			
				|  | @@ -2458,7 +2468,7 @@ router_exit_policy_all_routers_reject(uint32_t addr, uint16_t port,
 | 
	
		
			
				|  |  |    SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
 | 
	
		
			
				|  |  |    {
 | 
	
		
			
				|  |  |      if (router->is_running &&
 | 
	
		
			
				|  |  | -        !router_is_unreliable(router, need_uptime, 0)) {
 | 
	
		
			
				|  |  | +        !router_is_unreliable(router, need_uptime, 0, 0)) {
 | 
	
		
			
				|  |  |        r = router_compare_addr_to_addr_policy(addr, port, router->exit_policy);
 | 
	
		
			
				|  |  |        if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED)
 | 
	
		
			
				|  |  |          return 0; /* this one could be ok. good enough. */
 | 
	
	
		
			
				|  | @@ -3203,6 +3213,7 @@ routers_update_status_from_networkstatus(smartlist_t *routers,
 | 
	
		
			
				|  |  |        router->is_running = rs->status.is_running;
 | 
	
		
			
				|  |  |        router->is_fast = rs->status.is_fast;
 | 
	
		
			
				|  |  |        router->is_stable = rs->status.is_stable;
 | 
	
		
			
				|  |  | +      router->is_possible_guard = rs->status.is_possible_guard;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      if (router->is_running && ds) {
 | 
	
		
			
				|  |  |        ds->n_networkstatus_failures = 0;
 |