/** Return a pointer to a suitable router to be the exit node for the * circuit of purpose <b>purpose</b> that we're about to build (or NULL * if no router is suitable). * * For general-purpose circuits, pass it off to * choose_good_exit_server_general() * * For client-side rendezvous circuits, choose a random node, weighted * toward the preferences in 'options'. */ staticconstnode_t * choose_good_exit_server(origin_circuit_t *circ, router_crn_flags_t flags, int is_internal) { constor_options_t *options = get_options(); flags |= CRN_NEED_DESC;
switch (TO_CIRCUIT(circ)->purpose) { case CIRCUIT_PURPOSE_C_HSDIR_GET: case CIRCUIT_PURPOSE_S_HSDIR_POST: case CIRCUIT_PURPOSE_HS_VANGUARDS: case CIRCUIT_PURPOSE_C_ESTABLISH_REND: /* For these three, we want to pick the exit like a middle hop, * since it should be random. */ tor_assert_nonfatal(is_internal); /* We want to avoid picking certain nodes for HS purposes. */ flags |= CRN_FOR_HS; FALLTHROUGH; case CIRCUIT_PURPOSE_CONFLUX_UNLINKED: case CIRCUIT_PURPOSE_C_GENERAL: if (is_internal) /* pick it like a middle hop */ return router_choose_random_node(NULL, options->ExcludeNodes, flags); else return choose_good_exit_server_general(flags); } log_warn(LD_BUG,"Unhandled purpose %d", TO_CIRCUIT(circ)->purpose); tor_fragile_assert(); returnNULL; }
/** Return a pointer to a suitable router to be the exit node for the * circuit of purpose <b>purpose</b> that we're about to build (or NULL * if no router is suitable). * * For general-purpose circuits, pass it off to * choose_good_exit_server_general() * * For client-side rendezvous circuits, choose a random node, weighted * toward the preferences in 'options'. */ staticconstnode_t * choose_good_exit_server(origin_circuit_t *circ, router_crn_flags_t flags, int is_internal) { constor_options_t *options = get_options(); flags |= CRN_NEED_DESC;
switch (TO_CIRCUIT(circ)->purpose) { case CIRCUIT_PURPOSE_C_HSDIR_GET: case CIRCUIT_PURPOSE_S_HSDIR_POST: case CIRCUIT_PURPOSE_HS_VANGUARDS: case CIRCUIT_PURPOSE_C_ESTABLISH_REND: /* For these three, we want to pick the exit like a middle hop, * since it should be random. */ tor_assert_nonfatal(is_internal); /* We want to avoid picking certain nodes for HS purposes. */ flags |= CRN_FOR_HS; /* BORING TEST */ /* If ExitNodes is configured, force the client rendezvous point to be * chosen from that set as well, including IP-based routerset entries. */ if (TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND && options->ExitNodes) { constnode_t *node = choose_good_exit_server_from_routerset( options->ExitNodes, options->ExcludeExitNodesUnion_, flags); if (!node) { log_warn(LD_CIRC, "No nodes in ExitNodes%s seem usable as a rendezvous " "point: can't choose a rendezvous point.", options->ExcludeExitNodesUnion_ ? ", except possibly those excluded by your configuration, " : ""); } return node; } /* BORING TEST */ FALLTHROUGH; case CIRCUIT_PURPOSE_CONFLUX_UNLINKED: case CIRCUIT_PURPOSE_C_GENERAL: if (is_internal) /* pick it like a middle hop */ return router_choose_random_node(NULL, options->ExcludeNodes, flags); else return choose_good_exit_server_general(flags); } log_warn(LD_BUG,"Unhandled purpose %d", TO_CIRCUIT(circ)->purpose); tor_fragile_assert(); returnNULL; }
/* Pick a node from a configured routerset, but still enforce the normal * suitability checks for this circuit position and purpose. */ staticconstnode_t * choose_good_exit_server_from_routerset(constrouterset_t *pick_from, constrouterset_t *exclude_set, router_crn_flags_t flags) { constnode_t *node = NULL; smartlist_t *live_nodes = smartlist_new();
// circuitbuild.c warn_if_last_router_excluded() case CIRCUIT_PURPOSE_C_REND_JOINED: /* BORING TEST */ /* Rendezvous points now follow the same exit exclusion set as normal * exits so diagnostics match the enforced selection behavior. */ description = "chosen rendezvous point"; rs = options->ExcludeExitNodesUnion_; /* BORING TEST */ break;
/** * Return true for the set of conditions for which it is OK to use * a cannibalized circuit. * * Don't cannibalize for onehops, or certain purposes. */ staticint circuit_should_cannibalize_to_build(uint8_t purpose_to_build, int has_extend_info, int onehop_tunnel) { constor_options_t *options = get_options();
/* Do not try to cannibalize if this is a one hop circuit. */ if (onehop_tunnel) { return0; }
/* Don't try to cannibalize for general purpose circuits that do not * specify a custom exit. */ if (purpose_to_build == CIRCUIT_PURPOSE_C_GENERAL && !has_extend_info) { return0; }
/* Don't cannibalize for testing circuits. We want to see if they * complete normally. Also don't cannibalize for vanguard-purpose * circuits, since those are specially pre-built for later * cannibalization by the actual specific circuit types that need * vanguards. */ if (purpose_to_build == CIRCUIT_PURPOSE_TESTING || purpose_to_build == CIRCUIT_PURPOSE_HS_VANGUARDS) { return0; }
/* The server-side intro circ is not cannibalized because it only * needs a 3 hop circuit. It is also long-lived, so it is more * important that it have lower latency than get built fast. */ if (purpose_to_build == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) { return0; }
/* Do not cannibalize for conflux circuits */ if (purpose_to_build == CIRCUIT_PURPOSE_CONFLUX_UNLINKED) { return0; }
/* BORING TEST */ /* A client rendezvous circuit with ExitNodes configured must be built with * a freshly chosen final hop, otherwise cannibalizing an existing internal * circuit would keep its random endpoint and bypass the forced RP choice. */ if (purpose_to_build == CIRCUIT_PURPOSE_C_ESTABLISH_REND && options->ExitNodes) { return0; } /* BORING TEST */