Loading changes/bug23817 0 → 100644 +3 −0 Original line number Diff line number Diff line o Minor bugfixes (descriptors): - Don't try fetching microdescriptors from relays that have failed to deliver them in the past. Fixes bug 23817; bugfix on 0.3.0.1-alpha. src/or/directory.c +25 −57 Original line number Diff line number Diff line Loading @@ -116,7 +116,8 @@ static void dir_routerdesc_download_failed(smartlist_t *failed, int was_extrainfo, int was_descriptor_digests); static void dir_microdesc_download_failed(smartlist_t *failed, int status_code); int status_code, const char *dir_id); static int client_likes_consensus(const struct consensus_cache_entry_t *ent, const char *want_url); Loading Loading @@ -469,7 +470,7 @@ directory_pick_generic_dirserver(dirinfo_type_t type, int pds_flags, log_warn(LD_BUG, "Called when we have UseBridges set."); if (should_use_directory_guards(options)) { const node_t *node = guards_choose_dirguard(guard_state_out); const node_t *node = guards_choose_dirguard(dir_purpose, guard_state_out); if (node) rs = node->rs; } else { Loading Loading @@ -603,7 +604,7 @@ directory_get_from_dirserver,( * sort of dir fetch we'll be doing, so it won't return a bridge * that can't answer our question. */ const node_t *node = guards_choose_dirguard(&guard_state); const node_t *node = guards_choose_dirguard(dir_purpose, &guard_state); if (node && node->ri) { /* every bridge has a routerinfo. */ routerinfo_t *ri = node->ri; Loading Loading @@ -1011,48 +1012,6 @@ directory_must_use_begindir(const or_options_t *options) return !public_server_mode(options); } struct directory_request_t { /** * These fields specify which directory we're contacting. Routerstatus, * if present, overrides the other fields. * * @{ */ tor_addr_port_t or_addr_port; tor_addr_port_t dir_addr_port; char digest[DIGEST_LEN]; const routerstatus_t *routerstatus; /** @} */ /** One of DIR_PURPOSE_* other than DIR_PURPOSE_SERVER. Describes what * kind of operation we'll be doing (upload/download), and of what kind * of document. */ uint8_t dir_purpose; /** One of ROUTER_PURPOSE_*; used for uploads and downloads of routerinfo * and extrainfo docs. */ uint8_t router_purpose; /** Enum: determines whether to anonymize, and whether to use dirport or * orport. */ dir_indirection_t indirection; /** Alias to the variable part of the URL for this request */ const char *resource; /** Alias to the payload to upload (if any) */ const char *payload; /** Number of bytes to upload from payload</b> */ size_t payload_len; /** Value to send in an if-modified-since header, or 0 for none. */ time_t if_modified_since; /** Hidden-service-specific information v2. */ const rend_data_t *rend_query; /** Extra headers to append to the request */ config_line_t *additional_headers; /** Hidden-service-specific information for v3+. */ const hs_ident_dir_conn_t *hs_ident; /** Used internally to directory.c: gets informed when the attempt to * connect to the directory succeeds or fails, if that attempt bears on the * directory's usability as a directory guard. */ circuit_guard_state_t *guard_state; }; /** Evaluate the situation and decide if we should use an encrypted * "begindir-style" connection for this directory request. * 0) If there is no DirPort, yes. Loading Loading @@ -2245,8 +2204,6 @@ static int handle_response_fetch_detached_signatures(dir_connection_t *, const response_handler_args_t *); static int handle_response_fetch_desc(dir_connection_t *, const response_handler_args_t *); static int handle_response_fetch_microdesc(dir_connection_t *, const response_handler_args_t *); static int handle_response_upload_dir(dir_connection_t *, const response_handler_args_t *); static int handle_response_upload_vote(dir_connection_t *, Loading Loading @@ -2914,7 +2871,7 @@ handle_response_fetch_desc(dir_connection_t *conn, * Handler function: processes a response to a request for a group of * microdescriptors **/ static int STATIC int handle_response_fetch_microdesc(dir_connection_t *conn, const response_handler_args_t *args) { Loading @@ -2931,6 +2888,7 @@ handle_response_fetch_microdesc(dir_connection_t *conn, conn->base_.port); tor_assert(conn->requested_resource && !strcmpstart(conn->requested_resource, "d/")); tor_assert_nonfatal(!tor_mem_is_zero(conn->identity_digest, DIGEST_LEN)); which = smartlist_new(); dir_split_resource_into_fingerprints(conn->requested_resource+2, which, NULL, Loading @@ -2941,7 +2899,7 @@ handle_response_fetch_microdesc(dir_connection_t *conn, "soon.", status_code, escaped(reason), conn->base_.address, (int)conn->base_.port, conn->requested_resource); dir_microdesc_download_failed(which, status_code); dir_microdesc_download_failed(which, status_code, conn->identity_digest); SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); smartlist_free(which); return 0; Loading @@ -2953,7 +2911,7 @@ handle_response_fetch_microdesc(dir_connection_t *conn, now, which); if (smartlist_len(which)) { /* Mark remaining ones as failed. */ dir_microdesc_download_failed(which, status_code); dir_microdesc_download_failed(which, status_code, conn->identity_digest); } if (mds && smartlist_len(mds)) { control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS, Loading Loading @@ -5794,13 +5752,14 @@ dir_routerdesc_download_failed(smartlist_t *failed, int status_code, * every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */ } /** Called when a connection to download microdescriptors has failed in whole * or in part. <b>failed</b> is a list of every microdesc digest we didn't * get. <b>status_code</b> is the http status code we received. Reschedule the * microdesc downloads as appropriate. */ /** Called when a connection to download microdescriptors from relay with * <b>dir_id</b> has failed in whole or in part. <b>failed</b> is a list * of every microdesc digest we didn't get. <b>status_code</b> is the http * status code we received. Reschedule the microdesc downloads as * appropriate. */ static void dir_microdesc_download_failed(smartlist_t *failed, int status_code) int status_code, const char *dir_id) { networkstatus_t *consensus = networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC); Loading @@ -5811,17 +5770,26 @@ dir_microdesc_download_failed(smartlist_t *failed, if (! consensus) return; /* We failed to fetch a microdescriptor from 'dir_id', note it down * so that we don't try the same relay next time... */ microdesc_note_outdated_dirserver(dir_id); SMARTLIST_FOREACH_BEGIN(failed, const char *, d) { rs = router_get_mutable_consensus_status_by_descriptor_digest(consensus,d); if (!rs) continue; dls = &rs->dl_status; if (dls->n_download_failures >= get_options()->TestingMicrodescMaxDownloadTries) get_options()->TestingMicrodescMaxDownloadTries) { continue; { } { /* Increment the failure count for this md fetch */ char buf[BASE64_DIGEST256_LEN+1]; digest256_to_base64(buf, d); log_info(LD_DIR, "Failed to download md %s from %s", buf, hex_str(dir_id, DIGEST_LEN)); download_status_increment_failure(dls, status_code, buf, server, now); } Loading src/or/directory.h +44 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,48 @@ typedef struct response_handler_args_t { const char *headers; } response_handler_args_t; struct directory_request_t { /** * These fields specify which directory we're contacting. Routerstatus, * if present, overrides the other fields. * * @{ */ tor_addr_port_t or_addr_port; tor_addr_port_t dir_addr_port; char digest[DIGEST_LEN]; const routerstatus_t *routerstatus; /** @} */ /** One of DIR_PURPOSE_* other than DIR_PURPOSE_SERVER. Describes what * kind of operation we'll be doing (upload/download), and of what kind * of document. */ uint8_t dir_purpose; /** One of ROUTER_PURPOSE_*; used for uploads and downloads of routerinfo * and extrainfo docs. */ uint8_t router_purpose; /** Enum: determines whether to anonymize, and whether to use dirport or * orport. */ dir_indirection_t indirection; /** Alias to the variable part of the URL for this request */ const char *resource; /** Alias to the payload to upload (if any) */ const char *payload; /** Number of bytes to upload from payload</b> */ size_t payload_len; /** Value to send in an if-modified-since header, or 0 for none. */ time_t if_modified_since; /** Hidden-service-specific information v2. */ const rend_data_t *rend_query; /** Extra headers to append to the request */ config_line_t *additional_headers; /** Hidden-service-specific information for v3+. */ const hs_ident_dir_conn_t *hs_ident; /** Used internally to directory.c: gets informed when the attempt to * connect to the directory succeeds or fails, if that attempt bears on the * directory's usability as a directory guard. */ struct circuit_guard_state_t *guard_state; }; struct get_handler_args_t; STATIC int handle_get_hs_descriptor_v3(dir_connection_t *conn, const struct get_handler_args_t *args); Loading @@ -193,6 +235,8 @@ STATIC void warn_disallowed_anonymous_compression_method(compress_method_t); STATIC int handle_response_fetch_hsdesc_v3(dir_connection_t *conn, const response_handler_args_t *args); STATIC int handle_response_fetch_microdesc(dir_connection_t *conn, const response_handler_args_t *args); STATIC int handle_response_fetch_consensus(dir_connection_t *conn, const response_handler_args_t *args); Loading src/or/entrynodes.c +110 −11 Original line number Diff line number Diff line Loading @@ -1460,6 +1460,96 @@ guard_in_node_family(const entry_guard_t *guard, const node_t *node) } } /* Allocate and return a new exit guard restriction (where <b>exit_id</b> is of * size DIGEST_LEN) */ STATIC entry_guard_restriction_t * guard_create_exit_restriction(const uint8_t *exit_id) { entry_guard_restriction_t *rst = NULL; rst = tor_malloc_zero(sizeof(entry_guard_restriction_t)); rst->type = RST_EXIT_NODE; memcpy(rst->exclude_id, exit_id, DIGEST_LEN); return rst; } /** If we have fewer than this many possible guards, don't set * MD-availability-based restrictions: we might blacklist all of * them. */ #define MIN_GUARDS_FOR_MD_RESTRICTION 10 /** Return true if we should set md dirserver restrictions. We might not want * to set those if our network is too restricted, since we don't want to * blacklist all our nodes. */ static int should_set_md_dirserver_restriction(void) { const guard_selection_t *gs = get_guard_selection_info(); /* Compute the number of filtered guards */ int n_filtered_guards = 0; SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, guard) { if (guard->is_filtered_guard) { ++n_filtered_guards; } } SMARTLIST_FOREACH_END(guard); /* Do we have enough filtered guards that we feel okay about blacklisting * some for MD restriction? */ return (n_filtered_guards >= MIN_GUARDS_FOR_MD_RESTRICTION); } /** Allocate and return an outdated md guard restriction. Return NULL if no * such restriction is needed. */ STATIC entry_guard_restriction_t * guard_create_dirserver_md_restriction(void) { entry_guard_restriction_t *rst = NULL; if (!should_set_md_dirserver_restriction()) { log_debug(LD_GUARD, "Not setting md restriction: too few " "filtered guards."); return NULL; } rst = tor_malloc_zero(sizeof(entry_guard_restriction_t)); rst->type = RST_OUTDATED_MD_DIRSERVER; return rst; } /* Return True if <b>guard</b> obeys the exit restriction <b>rst</b>. */ static int guard_obeys_exit_restriction(const entry_guard_t *guard, const entry_guard_restriction_t *rst) { tor_assert(rst->type == RST_EXIT_NODE); // Exclude the exit ID and all of its family. const node_t *node = node_get_by_id((const char*)rst->exclude_id); if (node && guard_in_node_family(guard, node)) return 0; return tor_memneq(guard->identity, rst->exclude_id, DIGEST_LEN); } /** Return True if <b>guard</b> should be used as a dirserver for fetching * microdescriptors. */ static int guard_obeys_md_dirserver_restriction(const entry_guard_t *guard) { /* If this guard is an outdated dirserver, don't use it. */ if (microdesc_relay_is_outdated_dirserver(guard->identity)) { log_info(LD_GENERAL, "Skipping %s dirserver: outdated", hex_str(guard->identity, DIGEST_LEN)); return 0; } log_debug(LD_GENERAL, "%s dirserver obeys md restrictions", hex_str(guard->identity, DIGEST_LEN)); return 1; } /** * Return true iff <b>guard</b> obeys the restrictions defined in <b>rst</b>. * (If <b>rst</b> is NULL, there are no restrictions.) Loading @@ -1472,13 +1562,14 @@ entry_guard_obeys_restriction(const entry_guard_t *guard, if (! rst) return 1; // No restriction? No problem. // Only one kind of restriction exists right now: excluding an exit // ID and all of its family. const node_t *node = node_get_by_id((const char*)rst->exclude_id); if (node && guard_in_node_family(guard, node)) return 0; if (rst->type == RST_EXIT_NODE) { return guard_obeys_exit_restriction(guard, rst); } else if (rst->type == RST_OUTDATED_MD_DIRSERVER) { return guard_obeys_md_dirserver_restriction(guard); } return tor_memneq(guard->identity, rst->exclude_id, DIGEST_LEN); tor_assert_nonfatal_unreached(); return 0; } /** Loading Loading @@ -2105,7 +2196,7 @@ entry_guard_has_higher_priority(entry_guard_t *a, entry_guard_t *b) } /** Release all storage held in <b>restriction</b> */ static void STATIC void entry_guard_restriction_free(entry_guard_restriction_t *rst) { tor_free(rst); Loading Loading @@ -3358,8 +3449,8 @@ guards_choose_guard(cpath_build_state_t *state, /* We're building to a targeted exit node, so that node can't be * chosen as our guard for this circuit. Remember that fact in a * restriction. */ rst = tor_malloc_zero(sizeof(entry_guard_restriction_t)); memcpy(rst->exclude_id, exit_id, DIGEST_LEN); rst = guard_create_exit_restriction(exit_id); tor_assert(rst); } if (entry_guard_pick_for_circuit(get_guard_selection_info(), GUARD_USAGE_TRAFFIC, Loading Loading @@ -3411,12 +3502,20 @@ remove_all_entry_guards(void) /** Helper: pick a directory guard, with whatever algorithm is used. */ const node_t * guards_choose_dirguard(circuit_guard_state_t **guard_state_out) guards_choose_dirguard(uint8_t dir_purpose, circuit_guard_state_t **guard_state_out) { const node_t *r = NULL; entry_guard_restriction_t *rst = NULL; /* If we are fetching microdescs, don't query outdated dirservers. */ if (dir_purpose == DIR_PURPOSE_FETCH_MICRODESC) { rst = guard_create_dirserver_md_restriction(); } if (entry_guard_pick_for_circuit(get_guard_selection_info(), GUARD_USAGE_DIRGUARD, NULL, rst, &r, guard_state_out) < 0) { tor_assert(r == NULL); Loading src/or/entrynodes.h +24 −9 Original line number Diff line number Diff line Loading @@ -272,22 +272,28 @@ struct guard_selection_s { struct entry_guard_handle_t; /** Types of restrictions we impose when picking guard nodes */ typedef enum guard_restriction_type_t { /* Don't pick the same guard node as our exit node (or its family) */ RST_EXIT_NODE = 0, /* Don't pick dirguards that have previously shown to be outdated */ RST_OUTDATED_MD_DIRSERVER = 1 } guard_restriction_type_t; /** * A restriction to remember which entry guards are off-limits for a given * circuit. * * Right now, we only use restrictions to block a single guard and its family * from being selected; this mechanism is designed to be more extensible in * the future, however. * * Note: This mechanism is NOT for recording which guards are never to be * used: only which guards cannot be used on <em>one particular circuit</em>. */ struct entry_guard_restriction_t { /** * The guard's RSA identity digest must not equal this; and it must not * be in the same family as any node with this digest. */ /* What type of restriction are we imposing? */ guard_restriction_type_t type; /* In case of restriction type RST_EXIT_NODE, the guard's RSA identity * digest must not equal this; and it must not be in the same family as any * node with this digest. */ uint8_t exclude_id[DIGEST_LEN]; }; Loading Loading @@ -316,7 +322,8 @@ struct circuit_guard_state_t { int guards_update_all(void); const node_t *guards_choose_guard(cpath_build_state_t *state, circuit_guard_state_t **guard_state_out); const node_t *guards_choose_dirguard(circuit_guard_state_t **guard_state_out); const node_t *guards_choose_dirguard(uint8_t dir_purpose, circuit_guard_state_t **guard_state_out); #if 1 /* XXXX NM I would prefer that all of this stuff be private to Loading Loading @@ -554,6 +561,14 @@ STATIC unsigned entry_guards_note_guard_success(guard_selection_t *gs, unsigned old_state); STATIC int entry_guard_has_higher_priority(entry_guard_t *a, entry_guard_t *b); STATIC char *getinfo_helper_format_single_entry_guard(const entry_guard_t *e); STATIC entry_guard_restriction_t *guard_create_exit_restriction( const uint8_t *exit_id); STATIC entry_guard_restriction_t *guard_create_dirserver_md_restriction(void); STATIC void entry_guard_restriction_free(entry_guard_restriction_t *rst); #endif /* defined(ENTRYNODES_PRIVATE) */ void remove_all_entry_guards_for_guard_selection(guard_selection_t *gs); Loading Loading
changes/bug23817 0 → 100644 +3 −0 Original line number Diff line number Diff line o Minor bugfixes (descriptors): - Don't try fetching microdescriptors from relays that have failed to deliver them in the past. Fixes bug 23817; bugfix on 0.3.0.1-alpha.
src/or/directory.c +25 −57 Original line number Diff line number Diff line Loading @@ -116,7 +116,8 @@ static void dir_routerdesc_download_failed(smartlist_t *failed, int was_extrainfo, int was_descriptor_digests); static void dir_microdesc_download_failed(smartlist_t *failed, int status_code); int status_code, const char *dir_id); static int client_likes_consensus(const struct consensus_cache_entry_t *ent, const char *want_url); Loading Loading @@ -469,7 +470,7 @@ directory_pick_generic_dirserver(dirinfo_type_t type, int pds_flags, log_warn(LD_BUG, "Called when we have UseBridges set."); if (should_use_directory_guards(options)) { const node_t *node = guards_choose_dirguard(guard_state_out); const node_t *node = guards_choose_dirguard(dir_purpose, guard_state_out); if (node) rs = node->rs; } else { Loading Loading @@ -603,7 +604,7 @@ directory_get_from_dirserver,( * sort of dir fetch we'll be doing, so it won't return a bridge * that can't answer our question. */ const node_t *node = guards_choose_dirguard(&guard_state); const node_t *node = guards_choose_dirguard(dir_purpose, &guard_state); if (node && node->ri) { /* every bridge has a routerinfo. */ routerinfo_t *ri = node->ri; Loading Loading @@ -1011,48 +1012,6 @@ directory_must_use_begindir(const or_options_t *options) return !public_server_mode(options); } struct directory_request_t { /** * These fields specify which directory we're contacting. Routerstatus, * if present, overrides the other fields. * * @{ */ tor_addr_port_t or_addr_port; tor_addr_port_t dir_addr_port; char digest[DIGEST_LEN]; const routerstatus_t *routerstatus; /** @} */ /** One of DIR_PURPOSE_* other than DIR_PURPOSE_SERVER. Describes what * kind of operation we'll be doing (upload/download), and of what kind * of document. */ uint8_t dir_purpose; /** One of ROUTER_PURPOSE_*; used for uploads and downloads of routerinfo * and extrainfo docs. */ uint8_t router_purpose; /** Enum: determines whether to anonymize, and whether to use dirport or * orport. */ dir_indirection_t indirection; /** Alias to the variable part of the URL for this request */ const char *resource; /** Alias to the payload to upload (if any) */ const char *payload; /** Number of bytes to upload from payload</b> */ size_t payload_len; /** Value to send in an if-modified-since header, or 0 for none. */ time_t if_modified_since; /** Hidden-service-specific information v2. */ const rend_data_t *rend_query; /** Extra headers to append to the request */ config_line_t *additional_headers; /** Hidden-service-specific information for v3+. */ const hs_ident_dir_conn_t *hs_ident; /** Used internally to directory.c: gets informed when the attempt to * connect to the directory succeeds or fails, if that attempt bears on the * directory's usability as a directory guard. */ circuit_guard_state_t *guard_state; }; /** Evaluate the situation and decide if we should use an encrypted * "begindir-style" connection for this directory request. * 0) If there is no DirPort, yes. Loading Loading @@ -2245,8 +2204,6 @@ static int handle_response_fetch_detached_signatures(dir_connection_t *, const response_handler_args_t *); static int handle_response_fetch_desc(dir_connection_t *, const response_handler_args_t *); static int handle_response_fetch_microdesc(dir_connection_t *, const response_handler_args_t *); static int handle_response_upload_dir(dir_connection_t *, const response_handler_args_t *); static int handle_response_upload_vote(dir_connection_t *, Loading Loading @@ -2914,7 +2871,7 @@ handle_response_fetch_desc(dir_connection_t *conn, * Handler function: processes a response to a request for a group of * microdescriptors **/ static int STATIC int handle_response_fetch_microdesc(dir_connection_t *conn, const response_handler_args_t *args) { Loading @@ -2931,6 +2888,7 @@ handle_response_fetch_microdesc(dir_connection_t *conn, conn->base_.port); tor_assert(conn->requested_resource && !strcmpstart(conn->requested_resource, "d/")); tor_assert_nonfatal(!tor_mem_is_zero(conn->identity_digest, DIGEST_LEN)); which = smartlist_new(); dir_split_resource_into_fingerprints(conn->requested_resource+2, which, NULL, Loading @@ -2941,7 +2899,7 @@ handle_response_fetch_microdesc(dir_connection_t *conn, "soon.", status_code, escaped(reason), conn->base_.address, (int)conn->base_.port, conn->requested_resource); dir_microdesc_download_failed(which, status_code); dir_microdesc_download_failed(which, status_code, conn->identity_digest); SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); smartlist_free(which); return 0; Loading @@ -2953,7 +2911,7 @@ handle_response_fetch_microdesc(dir_connection_t *conn, now, which); if (smartlist_len(which)) { /* Mark remaining ones as failed. */ dir_microdesc_download_failed(which, status_code); dir_microdesc_download_failed(which, status_code, conn->identity_digest); } if (mds && smartlist_len(mds)) { control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS, Loading Loading @@ -5794,13 +5752,14 @@ dir_routerdesc_download_failed(smartlist_t *failed, int status_code, * every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */ } /** Called when a connection to download microdescriptors has failed in whole * or in part. <b>failed</b> is a list of every microdesc digest we didn't * get. <b>status_code</b> is the http status code we received. Reschedule the * microdesc downloads as appropriate. */ /** Called when a connection to download microdescriptors from relay with * <b>dir_id</b> has failed in whole or in part. <b>failed</b> is a list * of every microdesc digest we didn't get. <b>status_code</b> is the http * status code we received. Reschedule the microdesc downloads as * appropriate. */ static void dir_microdesc_download_failed(smartlist_t *failed, int status_code) int status_code, const char *dir_id) { networkstatus_t *consensus = networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC); Loading @@ -5811,17 +5770,26 @@ dir_microdesc_download_failed(smartlist_t *failed, if (! consensus) return; /* We failed to fetch a microdescriptor from 'dir_id', note it down * so that we don't try the same relay next time... */ microdesc_note_outdated_dirserver(dir_id); SMARTLIST_FOREACH_BEGIN(failed, const char *, d) { rs = router_get_mutable_consensus_status_by_descriptor_digest(consensus,d); if (!rs) continue; dls = &rs->dl_status; if (dls->n_download_failures >= get_options()->TestingMicrodescMaxDownloadTries) get_options()->TestingMicrodescMaxDownloadTries) { continue; { } { /* Increment the failure count for this md fetch */ char buf[BASE64_DIGEST256_LEN+1]; digest256_to_base64(buf, d); log_info(LD_DIR, "Failed to download md %s from %s", buf, hex_str(dir_id, DIGEST_LEN)); download_status_increment_failure(dls, status_code, buf, server, now); } Loading
src/or/directory.h +44 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,48 @@ typedef struct response_handler_args_t { const char *headers; } response_handler_args_t; struct directory_request_t { /** * These fields specify which directory we're contacting. Routerstatus, * if present, overrides the other fields. * * @{ */ tor_addr_port_t or_addr_port; tor_addr_port_t dir_addr_port; char digest[DIGEST_LEN]; const routerstatus_t *routerstatus; /** @} */ /** One of DIR_PURPOSE_* other than DIR_PURPOSE_SERVER. Describes what * kind of operation we'll be doing (upload/download), and of what kind * of document. */ uint8_t dir_purpose; /** One of ROUTER_PURPOSE_*; used for uploads and downloads of routerinfo * and extrainfo docs. */ uint8_t router_purpose; /** Enum: determines whether to anonymize, and whether to use dirport or * orport. */ dir_indirection_t indirection; /** Alias to the variable part of the URL for this request */ const char *resource; /** Alias to the payload to upload (if any) */ const char *payload; /** Number of bytes to upload from payload</b> */ size_t payload_len; /** Value to send in an if-modified-since header, or 0 for none. */ time_t if_modified_since; /** Hidden-service-specific information v2. */ const rend_data_t *rend_query; /** Extra headers to append to the request */ config_line_t *additional_headers; /** Hidden-service-specific information for v3+. */ const hs_ident_dir_conn_t *hs_ident; /** Used internally to directory.c: gets informed when the attempt to * connect to the directory succeeds or fails, if that attempt bears on the * directory's usability as a directory guard. */ struct circuit_guard_state_t *guard_state; }; struct get_handler_args_t; STATIC int handle_get_hs_descriptor_v3(dir_connection_t *conn, const struct get_handler_args_t *args); Loading @@ -193,6 +235,8 @@ STATIC void warn_disallowed_anonymous_compression_method(compress_method_t); STATIC int handle_response_fetch_hsdesc_v3(dir_connection_t *conn, const response_handler_args_t *args); STATIC int handle_response_fetch_microdesc(dir_connection_t *conn, const response_handler_args_t *args); STATIC int handle_response_fetch_consensus(dir_connection_t *conn, const response_handler_args_t *args); Loading
src/or/entrynodes.c +110 −11 Original line number Diff line number Diff line Loading @@ -1460,6 +1460,96 @@ guard_in_node_family(const entry_guard_t *guard, const node_t *node) } } /* Allocate and return a new exit guard restriction (where <b>exit_id</b> is of * size DIGEST_LEN) */ STATIC entry_guard_restriction_t * guard_create_exit_restriction(const uint8_t *exit_id) { entry_guard_restriction_t *rst = NULL; rst = tor_malloc_zero(sizeof(entry_guard_restriction_t)); rst->type = RST_EXIT_NODE; memcpy(rst->exclude_id, exit_id, DIGEST_LEN); return rst; } /** If we have fewer than this many possible guards, don't set * MD-availability-based restrictions: we might blacklist all of * them. */ #define MIN_GUARDS_FOR_MD_RESTRICTION 10 /** Return true if we should set md dirserver restrictions. We might not want * to set those if our network is too restricted, since we don't want to * blacklist all our nodes. */ static int should_set_md_dirserver_restriction(void) { const guard_selection_t *gs = get_guard_selection_info(); /* Compute the number of filtered guards */ int n_filtered_guards = 0; SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, guard) { if (guard->is_filtered_guard) { ++n_filtered_guards; } } SMARTLIST_FOREACH_END(guard); /* Do we have enough filtered guards that we feel okay about blacklisting * some for MD restriction? */ return (n_filtered_guards >= MIN_GUARDS_FOR_MD_RESTRICTION); } /** Allocate and return an outdated md guard restriction. Return NULL if no * such restriction is needed. */ STATIC entry_guard_restriction_t * guard_create_dirserver_md_restriction(void) { entry_guard_restriction_t *rst = NULL; if (!should_set_md_dirserver_restriction()) { log_debug(LD_GUARD, "Not setting md restriction: too few " "filtered guards."); return NULL; } rst = tor_malloc_zero(sizeof(entry_guard_restriction_t)); rst->type = RST_OUTDATED_MD_DIRSERVER; return rst; } /* Return True if <b>guard</b> obeys the exit restriction <b>rst</b>. */ static int guard_obeys_exit_restriction(const entry_guard_t *guard, const entry_guard_restriction_t *rst) { tor_assert(rst->type == RST_EXIT_NODE); // Exclude the exit ID and all of its family. const node_t *node = node_get_by_id((const char*)rst->exclude_id); if (node && guard_in_node_family(guard, node)) return 0; return tor_memneq(guard->identity, rst->exclude_id, DIGEST_LEN); } /** Return True if <b>guard</b> should be used as a dirserver for fetching * microdescriptors. */ static int guard_obeys_md_dirserver_restriction(const entry_guard_t *guard) { /* If this guard is an outdated dirserver, don't use it. */ if (microdesc_relay_is_outdated_dirserver(guard->identity)) { log_info(LD_GENERAL, "Skipping %s dirserver: outdated", hex_str(guard->identity, DIGEST_LEN)); return 0; } log_debug(LD_GENERAL, "%s dirserver obeys md restrictions", hex_str(guard->identity, DIGEST_LEN)); return 1; } /** * Return true iff <b>guard</b> obeys the restrictions defined in <b>rst</b>. * (If <b>rst</b> is NULL, there are no restrictions.) Loading @@ -1472,13 +1562,14 @@ entry_guard_obeys_restriction(const entry_guard_t *guard, if (! rst) return 1; // No restriction? No problem. // Only one kind of restriction exists right now: excluding an exit // ID and all of its family. const node_t *node = node_get_by_id((const char*)rst->exclude_id); if (node && guard_in_node_family(guard, node)) return 0; if (rst->type == RST_EXIT_NODE) { return guard_obeys_exit_restriction(guard, rst); } else if (rst->type == RST_OUTDATED_MD_DIRSERVER) { return guard_obeys_md_dirserver_restriction(guard); } return tor_memneq(guard->identity, rst->exclude_id, DIGEST_LEN); tor_assert_nonfatal_unreached(); return 0; } /** Loading Loading @@ -2105,7 +2196,7 @@ entry_guard_has_higher_priority(entry_guard_t *a, entry_guard_t *b) } /** Release all storage held in <b>restriction</b> */ static void STATIC void entry_guard_restriction_free(entry_guard_restriction_t *rst) { tor_free(rst); Loading Loading @@ -3358,8 +3449,8 @@ guards_choose_guard(cpath_build_state_t *state, /* We're building to a targeted exit node, so that node can't be * chosen as our guard for this circuit. Remember that fact in a * restriction. */ rst = tor_malloc_zero(sizeof(entry_guard_restriction_t)); memcpy(rst->exclude_id, exit_id, DIGEST_LEN); rst = guard_create_exit_restriction(exit_id); tor_assert(rst); } if (entry_guard_pick_for_circuit(get_guard_selection_info(), GUARD_USAGE_TRAFFIC, Loading Loading @@ -3411,12 +3502,20 @@ remove_all_entry_guards(void) /** Helper: pick a directory guard, with whatever algorithm is used. */ const node_t * guards_choose_dirguard(circuit_guard_state_t **guard_state_out) guards_choose_dirguard(uint8_t dir_purpose, circuit_guard_state_t **guard_state_out) { const node_t *r = NULL; entry_guard_restriction_t *rst = NULL; /* If we are fetching microdescs, don't query outdated dirservers. */ if (dir_purpose == DIR_PURPOSE_FETCH_MICRODESC) { rst = guard_create_dirserver_md_restriction(); } if (entry_guard_pick_for_circuit(get_guard_selection_info(), GUARD_USAGE_DIRGUARD, NULL, rst, &r, guard_state_out) < 0) { tor_assert(r == NULL); Loading
src/or/entrynodes.h +24 −9 Original line number Diff line number Diff line Loading @@ -272,22 +272,28 @@ struct guard_selection_s { struct entry_guard_handle_t; /** Types of restrictions we impose when picking guard nodes */ typedef enum guard_restriction_type_t { /* Don't pick the same guard node as our exit node (or its family) */ RST_EXIT_NODE = 0, /* Don't pick dirguards that have previously shown to be outdated */ RST_OUTDATED_MD_DIRSERVER = 1 } guard_restriction_type_t; /** * A restriction to remember which entry guards are off-limits for a given * circuit. * * Right now, we only use restrictions to block a single guard and its family * from being selected; this mechanism is designed to be more extensible in * the future, however. * * Note: This mechanism is NOT for recording which guards are never to be * used: only which guards cannot be used on <em>one particular circuit</em>. */ struct entry_guard_restriction_t { /** * The guard's RSA identity digest must not equal this; and it must not * be in the same family as any node with this digest. */ /* What type of restriction are we imposing? */ guard_restriction_type_t type; /* In case of restriction type RST_EXIT_NODE, the guard's RSA identity * digest must not equal this; and it must not be in the same family as any * node with this digest. */ uint8_t exclude_id[DIGEST_LEN]; }; Loading Loading @@ -316,7 +322,8 @@ struct circuit_guard_state_t { int guards_update_all(void); const node_t *guards_choose_guard(cpath_build_state_t *state, circuit_guard_state_t **guard_state_out); const node_t *guards_choose_dirguard(circuit_guard_state_t **guard_state_out); const node_t *guards_choose_dirguard(uint8_t dir_purpose, circuit_guard_state_t **guard_state_out); #if 1 /* XXXX NM I would prefer that all of this stuff be private to Loading Loading @@ -554,6 +561,14 @@ STATIC unsigned entry_guards_note_guard_success(guard_selection_t *gs, unsigned old_state); STATIC int entry_guard_has_higher_priority(entry_guard_t *a, entry_guard_t *b); STATIC char *getinfo_helper_format_single_entry_guard(const entry_guard_t *e); STATIC entry_guard_restriction_t *guard_create_exit_restriction( const uint8_t *exit_id); STATIC entry_guard_restriction_t *guard_create_dirserver_md_restriction(void); STATIC void entry_guard_restriction_free(entry_guard_restriction_t *rst); #endif /* defined(ENTRYNODES_PRIVATE) */ void remove_all_entry_guards_for_guard_selection(guard_selection_t *gs); Loading