/** Add <b>circ</b> to the end of ol_list and return 0, except * if ol_list is too long, in which case do nothing and return -1. */ int onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) { onion_queue_t *tmp; time_t now = time(NULL); if (onionskin->handshake_type > MAX_ONION_HANDSHAKE_TYPE) { log_warn(LD_BUG, "Handshake %d out of range! Dropping.", onionskin->handshake_type); return -1; } tmp = tor_malloc_zero(sizeof(onion_queue_t)); tmp->circ = circ; tmp->handshake_type = onionskin->handshake_type; tmp->onionskin = onionskin; tmp->when_added = now; if (!have_room_for_onionskin(onionskin->handshake_type)) { #define WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL (60) static ratelim_t last_warned = RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL); char *m; if (onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR && (m = rate_limit_log(&last_warned, approx_time()))) { log_warn(LD_GENERAL, "Your computer is too slow to handle this many circuit " "creation requests! Please consider using the " "MaxAdvertisedBandwidth config option or choosing a more " "restricted exit policy.%s",m); tor_free(m); } tor_free(tmp); return -1; } ++ol_entries[onionskin->handshake_type]; log_info(LD_OR, "New create (%s). Queues now ntor=%d and tap=%d.", onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap", ol_entries[ONION_HANDSHAKE_TYPE_NTOR], ol_entries[ONION_HANDSHAKE_TYPE_TAP]); circ->onionqueue_entry = tmp; TOR_TAILQ_INSERT_TAIL(&ol_list[onionskin->handshake_type], tmp, next); /* cull elderly requests. */ while (1) { onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[onionskin->handshake_type]); if (now - head->when_added < (time_t)ONIONQUEUE_WAIT_CUTOFF) break; circ = head->circ; circ->onionqueue_entry = NULL; onion_queue_entry_remove(head); log_info(LD_CIRC, "Circuit create request is too old; canceling due to overload."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT); } return 0; }
/** Add <b>circ</b> to the end of ol_list and return 0, except * if ol_list is too long, in which case do nothing and return -1. */ int onion_pending_add(or_circuit_t *circ, char *onionskin) { onion_queue_t *tmp; time_t now = time(NULL); tmp = tor_malloc_zero(sizeof(onion_queue_t)); tmp->circ = circ; tmp->onionskin = onionskin; tmp->when_added = now; if (!ol_tail) { tor_assert(!ol_list); tor_assert(!ol_length); ol_list = tmp; ol_tail = tmp; ol_length++; return 0; } tor_assert(ol_list); tor_assert(!ol_tail->next); if (ol_length >= get_options()->MaxOnionsPending) { #define WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL (60) static ratelim_t last_warned = RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL); char *m; if ((m = rate_limit_log(&last_warned, approx_time()))) { log_warn(LD_GENERAL, "Your computer is too slow to handle this many circuit " "creation requests! Please consider using the " "MaxAdvertisedBandwidth config option or choosing a more " "restricted exit policy.%s",m); tor_free(m); } tor_free(tmp); return -1; } ol_length++; ol_tail->next = tmp; ol_tail = tmp; while ((int)(now - ol_list->when_added) >= ONIONQUEUE_WAIT_CUTOFF) { /* cull elderly requests. */ circ = ol_list->circ; onion_pending_remove(ol_list->circ); log_info(LD_CIRC, "Circuit create request is too old; canceling due to overload."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT); } return 0; }
static void test_ratelim(void *arg) { (void) arg; ratelim_t ten_min = RATELIM_INIT(10*60); const time_t start = 1466091600; time_t now = start; /* Initially, we're ready. */ char *msg = NULL; msg = rate_limit_log(&ten_min, now); tt_assert(msg != NULL); tt_str_op(msg, OP_EQ, ""); /* nothing was suppressed. */ tt_int_op(ten_min.last_allowed, OP_EQ, now); tor_free(msg); int i; for (i = 0; i < 9; ++i) { now += 60; /* one minute has passed. */ msg = rate_limit_log(&ten_min, now); tt_assert(msg == NULL); tt_int_op(ten_min.last_allowed, OP_EQ, start); tt_int_op(ten_min.n_calls_since_last_time, OP_EQ, i + 1); } now += 240; /* Okay, we can be done. */ msg = rate_limit_log(&ten_min, now); tt_assert(msg != NULL); tt_str_op(msg, OP_EQ, " [9 similar message(s) suppressed in last 600 seconds]"); done: tor_free(msg); }
/** Process a 'create' <b>cell</b> that just arrived from <b>conn</b>. Make a * new circuit with the p_circ_id specified in cell. Put the circuit in state * onionskin_pending, and pass the onionskin to the cpuworker. Circ will get * picked up again when the cpuworker finishes decrypting it. */ static void command_process_create_cell(cell_t *cell, or_connection_t *conn) { or_circuit_t *circ; const or_options_t *options = get_options(); int id_is_high; if (we_are_hibernating()) { log_info(LD_OR, "Received create cell but we're shutting down. Sending back " "destroy."); connection_or_send_destroy(cell->circ_id, conn, END_CIRC_REASON_HIBERNATING); return; } if (!server_mode(options) || (!public_server_mode(options) && conn->is_outgoing)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received create cell (type %d) from %s:%d, but we're connected " "to it as a client. " "Sending back a destroy.", (int)cell->command, conn->_base.address, conn->_base.port); connection_or_send_destroy(cell->circ_id, conn, END_CIRC_REASON_TORPROTOCOL); return; } /* If the high bit of the circuit ID is not as expected, close the * circ. */ id_is_high = cell->circ_id & (1<<15); if ((id_is_high && conn->circ_id_type == CIRC_ID_TYPE_HIGHER) || (!id_is_high && conn->circ_id_type == CIRC_ID_TYPE_LOWER)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received create cell with unexpected circ_id %d. Closing.", cell->circ_id); connection_or_send_destroy(cell->circ_id, conn, END_CIRC_REASON_TORPROTOCOL); return; } if (circuit_id_in_use_on_orconn(cell->circ_id, conn)) { const node_t *node = node_get_by_id(conn->identity_digest); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received CREATE cell (circID %d) for known circ. " "Dropping (age %d).", cell->circ_id, (int)(time(NULL) - conn->_base.timestamp_created)); if (node) { char *p = esc_for_log(node_get_platform(node)); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Details: router %s, platform %s.", node_describe(node), p); tor_free(p); } return; } circ = or_circuit_new(cell->circ_id, conn); circ->_base.purpose = CIRCUIT_PURPOSE_OR; circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING); if (cell->command == CELL_CREATE) { char *onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN); memcpy(onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN); /* hand it off to the cpuworkers, and then return. */ if (assign_onionskin_to_cpuworker(NULL, circ, onionskin) < 0) { #define WARN_HANDOFF_FAILURE_INTERVAL (6*60*60) static ratelim_t handoff_warning = RATELIM_INIT(WARN_HANDOFF_FAILURE_INTERVAL); char *m; if ((m = rate_limit_log(&handoff_warning, approx_time()))) { log_warn(LD_GENERAL,"Failed to hand off onionskin. Closing.%s",m); tor_free(m); } circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } log_debug(LD_OR,"success: handed off onionskin."); } else { /* This is a CREATE_FAST cell; we can handle it immediately without using * a CPU worker. */ char keys[CPATH_KEY_MATERIAL_LEN]; char reply[DIGEST_LEN*2]; tor_assert(cell->command == CELL_CREATE_FAST); /* Make sure we never try to use the OR connection on which we * received this cell to satisfy an EXTEND request, */ conn->is_connection_with_client = 1; if (fast_server_handshake(cell->payload, (uint8_t*)reply, (uint8_t*)keys, sizeof(keys))<0) { log_warn(LD_OR,"Failed to generate key material. Closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } if (onionskin_answer(circ, CELL_CREATED_FAST, reply, keys)<0) { log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } } }