/** Helper for new_route_len(). Choose a circuit length for purpose * <b>purpose</b>: DEFAULT_ROUTE_LEN (+ 1 if someone else chose the * exit). If someone else chose the exit, they could be colluding * with the exit, so add a randomly selected node to preserve * anonymity. * * Here, "exit node" sometimes means an OR acting as an internal * endpoint, rather than as a relay to an external endpoint. This * means there need to be at least DEFAULT_ROUTE_LEN routers between * us and the internal endpoint to preserve the same anonymity * properties that we would get when connecting to an external * endpoint. These internal endpoints can include: * * - Connections to a directory of hidden services * (CIRCUIT_PURPOSE_C_GENERAL) * * - A client connecting to an introduction point, which the hidden * service picked (CIRCUIT_PURPOSE_C_INTRODUCING, via * circuit_get_open_circ_or_launch() which rewrites it from * CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) * * - A hidden service connecting to a rendezvous point, which the * client picked (CIRCUIT_PURPOSE_S_CONNECT_REND. * * There are currently two situations where we picked the exit node * ourselves, making DEFAULT_ROUTE_LEN a safe circuit length: * * - We are a hidden service connecting to an introduction point * (CIRCUIT_PURPOSE_S_ESTABLISH_INTRO). * * - We are a router testing its own reachabiity * (CIRCUIT_PURPOSE_TESTING, via router_do_reachability_checks()) * * onion_pick_cpath_exit() bypasses us (by not calling * new_route_len()) in the one-hop tunnel case, so we don't need to * handle that. */
/** Receive a relay cell: * - Crypt it (encrypt if headed toward the origin or if we <b>are</b> the * origin; decrypt if we're headed toward the exit). * - Check if recognized (if exitward). * - If recognized and the digest checks out, then find if there's a stream * that the cell is intended for, and deliver it to the right * connection_edge. * - If not recognized, then we need to relay it: append it to the appropriate * cell_queue on <b>circ</b>. * * Return -<b>reason</b> on failure, else 0. */ int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, cell_direction_t cell_direction) { channel_t *chan = NULL; crypt_path_t *layer_hint=NULL; char recognized=0; int reason;
if (circ->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) { if (pathbias_check_probe_response(circ, msg) == -1) { pathbias_count_valid_cells(circ, msg); }
/* We need to drop this cell no matter what to avoid code that expects * a certain purpose (such as the hidserv code). */ return0; }
conn = relay_lookup_conn(circ, msg, cell_direction, layer_hint); if (cell_direction == CELL_DIRECTION_OUT) { ++stats_n_relay_cells_delivered; log_debug(LD_OR,"Sending away from origin."); reason = connection_edge_process_relay_cell(msg, circ, conn, NULL); if (reason < 0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "connection_edge_process_relay_cell (away from origin) " "failed."); return reason; } } elseif (cell_direction == CELL_DIRECTION_IN) { ++stats_n_relay_cells_delivered; log_debug(LD_OR,"Sending to origin."); reason = connection_edge_process_relay_cell(msg, circ, conn, layer_hint); if (reason < 0) { /* If a client is trying to connect to unknown hidden service port, * END_CIRC_AT_ORIGIN is sent back so we can then close the circuit. * Do not log warn as this is an expected behavior for a service. */ if (reason != END_CIRC_AT_ORIGIN) { log_warn(LD_OR, "connection_edge_process_relay_cell (at origin) failed."); } return reason; } } return0; }