|
@@ -0,0 +1,604 @@
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ * \file sendme.c
|
|
|
+ * \brief Code that is related to SENDME cells both in terms of
|
|
|
+ * creating/parsing cells and handling the content.
|
|
|
+ */
|
|
|
+
|
|
|
+#define SENDME_PRIVATE
|
|
|
+
|
|
|
+#include "core/or/or.h"
|
|
|
+
|
|
|
+#include "app/config/config.h"
|
|
|
+#include "core/crypto/relay_crypto.h"
|
|
|
+#include "core/mainloop/connection.h"
|
|
|
+#include "core/or/cell_st.h"
|
|
|
+#include "core/or/circuitlist.h"
|
|
|
+#include "core/or/circuituse.h"
|
|
|
+#include "core/or/or_circuit_st.h"
|
|
|
+#include "core/or/relay.h"
|
|
|
+#include "core/or/sendme.h"
|
|
|
+#include "feature/nodelist/networkstatus.h"
|
|
|
+#include "lib/ctime/di_ops.h"
|
|
|
+#include "trunnel/sendme.h"
|
|
|
+
|
|
|
+
|
|
|
+ * recognized as a valid SENDME. */
|
|
|
+#define SENDME_MAX_SUPPORTED_VERSION 1
|
|
|
+
|
|
|
+
|
|
|
+#define SENDME_EMIT_MIN_VERSION_DEFAULT 0
|
|
|
+#define SENDME_EMIT_MIN_VERSION_MIN 0
|
|
|
+#define SENDME_EMIT_MIN_VERSION_MAX UINT8_MAX
|
|
|
+
|
|
|
+
|
|
|
+#define SENDME_ACCEPT_MIN_VERSION_DEFAULT 0
|
|
|
+#define SENDME_ACCEPT_MIN_VERSION_MIN 0
|
|
|
+#define SENDME_ACCEPT_MIN_VERSION_MAX UINT8_MAX
|
|
|
+
|
|
|
+
|
|
|
+ * used when emitting a SENDME cell. */
|
|
|
+STATIC int
|
|
|
+get_emit_min_version(void)
|
|
|
+{
|
|
|
+ return networkstatus_get_param(NULL, "sendme_emit_min_version",
|
|
|
+ SENDME_EMIT_MIN_VERSION_DEFAULT,
|
|
|
+ SENDME_EMIT_MIN_VERSION_MIN,
|
|
|
+ SENDME_EMIT_MIN_VERSION_MAX);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * accepted when receiving a SENDME cell. */
|
|
|
+STATIC int
|
|
|
+get_accept_min_version(void)
|
|
|
+{
|
|
|
+ return networkstatus_get_param(NULL, "sendme_accept_min_version",
|
|
|
+ SENDME_ACCEPT_MIN_VERSION_DEFAULT,
|
|
|
+ SENDME_ACCEPT_MIN_VERSION_MIN,
|
|
|
+ SENDME_ACCEPT_MIN_VERSION_MAX);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * circuit sendme list. */
|
|
|
+static bool
|
|
|
+v1_digest_matches(const circuit_t *circ, const uint8_t *cell_digest)
|
|
|
+{
|
|
|
+ bool ret = false;
|
|
|
+ uint8_t *circ_digest = NULL;
|
|
|
+
|
|
|
+ tor_assert(circ);
|
|
|
+ tor_assert(cell_digest);
|
|
|
+
|
|
|
+
|
|
|
+ * protocol warning because it can be tricked by sending many SENDMEs
|
|
|
+ * without prior data cell. */
|
|
|
+ if (circ->sendme_last_digests == NULL ||
|
|
|
+ smartlist_len(circ->sendme_last_digests) == 0) {
|
|
|
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
|
|
+ "We received a SENDME but we have no cell digests to match. "
|
|
|
+ "Closing circuit.");
|
|
|
+ goto no_match;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ circ_digest = smartlist_get(circ->sendme_last_digests, 0);
|
|
|
+ smartlist_del_keeporder(circ->sendme_last_digests, 0);
|
|
|
+
|
|
|
+
|
|
|
+ * without a perfect match. */
|
|
|
+ if (tor_memneq(circ_digest, cell_digest, TRUNNEL_SENDME_V1_DIGEST_LEN)) {
|
|
|
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
|
|
+ "SENDME v1 cell digest do not match.");
|
|
|
+ goto no_match;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = true;
|
|
|
+
|
|
|
+ no_match:
|
|
|
+
|
|
|
+ * we have no more use for it. */
|
|
|
+ tor_free(circ_digest);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * matches the expected digest on the circuit.
|
|
|
+ *
|
|
|
+ * Validation is done by comparing the digest in the cell from the previous
|
|
|
+ * cell we saw which tells us that the other side has in fact seen that cell.
|
|
|
+ * See proposal 289 for more details. */
|
|
|
+static bool
|
|
|
+cell_v1_is_valid(const sendme_cell_t *cell, const circuit_t *circ)
|
|
|
+{
|
|
|
+ tor_assert(cell);
|
|
|
+ tor_assert(circ);
|
|
|
+
|
|
|
+ const uint8_t *cell_digest = sendme_cell_getconstarray_data_v1_digest(cell);
|
|
|
+ return v1_digest_matches(circ, cell_digest);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * accepted version from the consensus is known to us. */
|
|
|
+STATIC bool
|
|
|
+cell_version_is_valid(uint8_t cell_version)
|
|
|
+{
|
|
|
+ int accept_version = get_accept_min_version();
|
|
|
+
|
|
|
+
|
|
|
+ if (accept_version > SENDME_MAX_SUPPORTED_VERSION) {
|
|
|
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
|
|
+ "Unable to accept SENDME version %u (from consensus). "
|
|
|
+ "We only support <= %d. Probably your tor is too old?",
|
|
|
+ accept_version, cell_version);
|
|
|
+ goto invalid;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (cell_version < accept_version) {
|
|
|
+ log_info(LD_PROTOCOL, "Unacceptable SENDME version %d. Only "
|
|
|
+ "accepting %u (from consensus). Closing circuit.",
|
|
|
+ cell_version, accept_version);
|
|
|
+ goto invalid;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 1;
|
|
|
+ invalid:
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * cell_payload_len is valid. For each version:
|
|
|
+ *
|
|
|
+ * 0: No validation
|
|
|
+ * 1: Authenticated with last cell digest.
|
|
|
+ *
|
|
|
+ * This is the main critical function to make sure we can continue to
|
|
|
+ * send/recv cells on a circuit. If the SENDME is invalid, the circuit should
|
|
|
+ * be mark for close. */
|
|
|
+STATIC bool
|
|
|
+sendme_is_valid(const circuit_t *circ, const uint8_t *cell_payload,
|
|
|
+ size_t cell_payload_len)
|
|
|
+{
|
|
|
+ uint8_t cell_version;
|
|
|
+ sendme_cell_t *cell = NULL;
|
|
|
+
|
|
|
+ tor_assert(circ);
|
|
|
+ tor_assert(cell_payload);
|
|
|
+
|
|
|
+
|
|
|
+ * able to parse a 0 length buffer into a valid SENDME cell. */
|
|
|
+ if (cell_payload_len == 0) {
|
|
|
+ cell_version = 0;
|
|
|
+ } else {
|
|
|
+
|
|
|
+ if (sendme_cell_parse(&cell, cell_payload, cell_payload_len) < 0) {
|
|
|
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
|
|
+ "Unparseable SENDME cell received. Closing circuit.");
|
|
|
+ goto invalid;
|
|
|
+ }
|
|
|
+ cell_version = sendme_cell_get_version(cell);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (!cell_version_is_valid(cell_version)) {
|
|
|
+ goto invalid;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ switch (cell_version) {
|
|
|
+ case 0x01:
|
|
|
+ if (!cell_v1_is_valid(cell, circ)) {
|
|
|
+ goto invalid;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 0x00:
|
|
|
+
|
|
|
+ * it is necessarily valid if we pass the version validation. */
|
|
|
+ default:
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ sendme_cell_free(cell);
|
|
|
+ return 1;
|
|
|
+ invalid:
|
|
|
+ sendme_cell_free(cell);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * least of RELAY_PAYLOAD_SIZE bytes, using the digest for the cell data.
|
|
|
+ *
|
|
|
+ * Return the size in bytes of the encoded cell in payload. A negative value
|
|
|
+ * is returned on encoding failure. */
|
|
|
+STATIC ssize_t
|
|
|
+build_cell_payload_v1(const uint8_t *cell_digest, uint8_t *payload)
|
|
|
+{
|
|
|
+ ssize_t len = -1;
|
|
|
+ sendme_cell_t *cell = NULL;
|
|
|
+
|
|
|
+ tor_assert(cell_digest);
|
|
|
+ tor_assert(payload);
|
|
|
+
|
|
|
+ cell = sendme_cell_new();
|
|
|
+
|
|
|
+
|
|
|
+ sendme_cell_set_version(cell, 0x01);
|
|
|
+
|
|
|
+ sendme_cell_set_data_len(cell, TRUNNEL_SENDME_V1_DIGEST_LEN);
|
|
|
+
|
|
|
+
|
|
|
+ memcpy(sendme_cell_getarray_data_v1_digest(cell), cell_digest,
|
|
|
+ sendme_cell_get_data_len(cell));
|
|
|
+
|
|
|
+
|
|
|
+ len = sendme_cell_encode(payload, RELAY_PAYLOAD_SIZE, cell);
|
|
|
+
|
|
|
+ sendme_cell_free(cell);
|
|
|
+ return len;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * not NULL. The digest is only used for version 1.
|
|
|
+ *
|
|
|
+ * Return 0 on success else a negative value and the circuit will be closed
|
|
|
+ * because we failed to send the cell on it. */
|
|
|
+static int
|
|
|
+send_circuit_level_sendme(circuit_t *circ, crypt_path_t *layer_hint,
|
|
|
+ const uint8_t *cell_digest)
|
|
|
+{
|
|
|
+ uint8_t emit_version;
|
|
|
+ uint8_t payload[RELAY_PAYLOAD_SIZE];
|
|
|
+ ssize_t payload_len;
|
|
|
+
|
|
|
+ tor_assert(circ);
|
|
|
+ tor_assert(cell_digest);
|
|
|
+
|
|
|
+ emit_version = get_emit_min_version();
|
|
|
+ switch (emit_version) {
|
|
|
+ case 0x01:
|
|
|
+ payload_len = build_cell_payload_v1(cell_digest, payload);
|
|
|
+ if (BUG(payload_len < 0)) {
|
|
|
+
|
|
|
+ * the circuit but in theory it should never happen. */
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ log_debug(LD_PROTOCOL, "Emitting SENDME version 1 cell.");
|
|
|
+ break;
|
|
|
+ case 0x00:
|
|
|
+
|
|
|
+ default:
|
|
|
+
|
|
|
+ payload_len = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (relay_send_command_from_edge(0, circ, RELAY_COMMAND_SENDME,
|
|
|
+ (char *) payload, payload_len,
|
|
|
+ layer_hint) < 0) {
|
|
|
+ log_warn(LD_CIRC,
|
|
|
+ "SENDME relay_send_command_from_edge failed. Circuit's closed.");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * Public API
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+ * is only done by the client as the circuit came back from the Exit. */
|
|
|
+void
|
|
|
+sendme_circuit_record_outbound_cell(or_circuit_t *or_circ)
|
|
|
+{
|
|
|
+ tor_assert(or_circ);
|
|
|
+ relay_crypto_record_sendme_digest(&or_circ->crypto);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * is only done by the client as the circuit came back from the Exit. */
|
|
|
+void
|
|
|
+sendme_circuit_record_inbound_cell(crypt_path_t *cpath)
|
|
|
+{
|
|
|
+ tor_assert(cpath);
|
|
|
+ relay_crypto_record_sendme_digest(&cpath->crypto);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * a SENDME.
|
|
|
+ *
|
|
|
+ * We are able to know that because the package or deliver window value minus
|
|
|
+ * one cell (the possible SENDME cell) should be a multiple of the increment
|
|
|
+ * window value. */
|
|
|
+bool
|
|
|
+sendme_circuit_cell_is_next(int window)
|
|
|
+{
|
|
|
+
|
|
|
+ * deliver window reaches a multiple of the increment, after this cell, we
|
|
|
+ * should expect a SENDME. */
|
|
|
+ if (((window - 1) % CIRCWINDOW_INCREMENT) != 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * finished flushing all bytes to stream <b>conn</b>, or when we've flushed
|
|
|
+ * *some* bytes to the stream <b>conn</b>.
|
|
|
+ *
|
|
|
+ * If conn->outbuf is not too full, and our deliver window is low, send back a
|
|
|
+ * suitable number of stream-level sendme cells.
|
|
|
+ */
|
|
|
+void
|
|
|
+sendme_connection_edge_consider_sending(edge_connection_t *conn)
|
|
|
+{
|
|
|
+ tor_assert(conn);
|
|
|
+
|
|
|
+ int log_domain = TO_CONN(conn)->type == CONN_TYPE_AP ? LD_APP : LD_EXIT;
|
|
|
+
|
|
|
+
|
|
|
+ if (connection_outbuf_too_full(TO_CONN(conn))) {
|
|
|
+ goto end;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (circuit_get_by_edge_conn(conn) == NULL) {
|
|
|
+
|
|
|
+ * torn down the circuit. */
|
|
|
+ log_info(log_domain, "No circuit associated with edge connection. "
|
|
|
+ "Skipping sending SENDME.");
|
|
|
+ goto end;
|
|
|
+ }
|
|
|
+
|
|
|
+ while (conn->deliver_window <=
|
|
|
+ (STREAMWINDOW_START - STREAMWINDOW_INCREMENT)) {
|
|
|
+ log_debug(log_domain, "Outbuf %" TOR_PRIuSZ ", queuing stream SENDME.",
|
|
|
+ TO_CONN(conn)->outbuf_flushlen);
|
|
|
+ conn->deliver_window += STREAMWINDOW_INCREMENT;
|
|
|
+ if (connection_edge_send_command(conn, RELAY_COMMAND_SENDME,
|
|
|
+ NULL, 0) < 0) {
|
|
|
+ log_warn(LD_BUG, "connection_edge_send_command failed while sending "
|
|
|
+ "a SENDME. Circuit probably closed, skipping.");
|
|
|
+ goto end;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ end:
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * <b>layer_hint</b> if it's defined) is low enough that we should
|
|
|
+ * send a circuit-level sendme back down the circuit. If so, send
|
|
|
+ * enough sendmes that the window would be overfull if we sent any
|
|
|
+ * more.
|
|
|
+ */
|
|
|
+void
|
|
|
+sendme_circuit_consider_sending(circuit_t *circ, crypt_path_t *layer_hint)
|
|
|
+{
|
|
|
+ const uint8_t *digest;
|
|
|
+
|
|
|
+ while ((layer_hint ? layer_hint->deliver_window : circ->deliver_window) <=
|
|
|
+ CIRCWINDOW_START - CIRCWINDOW_INCREMENT) {
|
|
|
+ log_debug(LD_CIRC,"Queuing circuit sendme.");
|
|
|
+ if (layer_hint) {
|
|
|
+ layer_hint->deliver_window += CIRCWINDOW_INCREMENT;
|
|
|
+ digest = relay_crypto_get_sendme_digest(&layer_hint->crypto);
|
|
|
+ } else {
|
|
|
+ circ->deliver_window += CIRCWINDOW_INCREMENT;
|
|
|
+ digest = relay_crypto_get_sendme_digest(&TO_OR_CIRCUIT(circ)->crypto);
|
|
|
+ }
|
|
|
+ if (send_circuit_level_sendme(circ, layer_hint, digest) < 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * if not NULL, is the Exit hop of the connection which means that we are a
|
|
|
+ * client. In that case, circ must be an origin circuit. The cell_body_len is
|
|
|
+ * the length of the SENDME cell payload (excluding the header). The
|
|
|
+ * cell_payload is the payload.
|
|
|
+ *
|
|
|
+ * Return 0 on success that is the SENDME is valid and the package window has
|
|
|
+ * been updated properly.
|
|
|
+ *
|
|
|
+ * On error, a negative value is returned which indicate that the circuit must
|
|
|
+ * be closed using the value as the reason for it. */
|
|
|
+int
|
|
|
+sendme_process_circuit_level(crypt_path_t *layer_hint,
|
|
|
+ circuit_t *circ, const uint8_t *cell_payload,
|
|
|
+ uint16_t cell_payload_len)
|
|
|
+{
|
|
|
+ tor_assert(circ);
|
|
|
+ tor_assert(cell_payload);
|
|
|
+
|
|
|
+
|
|
|
+ * layer hint (the Exit hop) for the package window tracking. */
|
|
|
+ if (CIRCUIT_IS_ORIGIN(circ)) {
|
|
|
+ if ((layer_hint->package_window + CIRCWINDOW_INCREMENT) >
|
|
|
+ CIRCWINDOW_START_MAX) {
|
|
|
+ static struct ratelim_t exit_warn_ratelim = RATELIM_INIT(600);
|
|
|
+ log_fn_ratelim(&exit_warn_ratelim, LOG_WARN, LD_PROTOCOL,
|
|
|
+ "Unexpected sendme cell from exit relay. "
|
|
|
+ "Closing circ.");
|
|
|
+ return -END_CIRC_REASON_TORPROTOCOL;
|
|
|
+ }
|
|
|
+ layer_hint->package_window += CIRCWINDOW_INCREMENT;
|
|
|
+ log_debug(LD_APP, "circ-level sendme at origin, packagewindow %d.",
|
|
|
+ layer_hint->package_window);
|
|
|
+
|
|
|
+
|
|
|
+ * are rate limited. */
|
|
|
+ circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), cell_payload_len);
|
|
|
+ } else {
|
|
|
+
|
|
|
+ * validation can be done. An invalid SENDME requires us to close the
|
|
|
+ * circuit. It is only done if we are the Exit of the circuit. */
|
|
|
+ if (!sendme_is_valid(circ, cell_payload, cell_payload_len)) {
|
|
|
+ return -END_CIRC_REASON_TORPROTOCOL;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * track the package window with the circuit object. */
|
|
|
+ if ((circ->package_window + CIRCWINDOW_INCREMENT) >
|
|
|
+ CIRCWINDOW_START_MAX) {
|
|
|
+ static struct ratelim_t client_warn_ratelim = RATELIM_INIT(600);
|
|
|
+ log_fn_ratelim(&client_warn_ratelim, LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
|
|
+ "Unexpected sendme cell from client. "
|
|
|
+ "Closing circ (window %d).", circ->package_window);
|
|
|
+ return -END_CIRC_REASON_TORPROTOCOL;
|
|
|
+ }
|
|
|
+ circ->package_window += CIRCWINDOW_INCREMENT;
|
|
|
+ log_debug(LD_EXIT, "circ-level sendme at non-origin, packagewindow %d.",
|
|
|
+ circ->package_window);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * edge connection (stream) that the circuit circ is associated with. The
|
|
|
+ * cell_body_len is the length of the payload (excluding the header).
|
|
|
+ *
|
|
|
+ * Return 0 on success that is the SENDME is valid and the package window has
|
|
|
+ * been updated properly.
|
|
|
+ *
|
|
|
+ * On error, a negative value is returned which indicate that the circuit must
|
|
|
+ * be closed using the value as the reason for it. */
|
|
|
+int
|
|
|
+sendme_process_stream_level(edge_connection_t *conn, circuit_t *circ,
|
|
|
+ uint16_t cell_body_len)
|
|
|
+{
|
|
|
+ tor_assert(conn);
|
|
|
+ tor_assert(circ);
|
|
|
+
|
|
|
+
|
|
|
+ * initial) stream SENDME window worth of data. Well-behaved stock clients
|
|
|
+ * will not request more than this max (as per the check in the while loop
|
|
|
+ * of sendme_connection_edge_consider_sending()). */
|
|
|
+ if ((conn->package_window + STREAMWINDOW_INCREMENT) >
|
|
|
+ STREAMWINDOW_START_MAX) {
|
|
|
+ static struct ratelim_t stream_warn_ratelim = RATELIM_INIT(600);
|
|
|
+ log_fn_ratelim(&stream_warn_ratelim, LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
|
|
+ "Unexpected stream sendme cell. Closing circ (window %d).",
|
|
|
+ conn->package_window);
|
|
|
+ return -END_CIRC_REASON_TORPROTOCOL;
|
|
|
+ }
|
|
|
+
|
|
|
+ conn->package_window += STREAMWINDOW_INCREMENT;
|
|
|
+
|
|
|
+
|
|
|
+ * rate limited. */
|
|
|
+ if (CIRCUIT_IS_ORIGIN(circ)) {
|
|
|
+ circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), cell_body_len);
|
|
|
+ }
|
|
|
+
|
|
|
+ log_debug(CIRCUIT_IS_ORIGIN(circ) ? LD_APP : LD_EXIT,
|
|
|
+ "stream-level sendme, package_window now %d.",
|
|
|
+ conn->package_window);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * layer_hint is NULL, this means we are the Exit end point else we are the
|
|
|
+ * Client. Update the deliver window and return its new value. */
|
|
|
+int
|
|
|
+sendme_circuit_data_received(circuit_t *circ, crypt_path_t *layer_hint)
|
|
|
+{
|
|
|
+ int deliver_window, domain;
|
|
|
+
|
|
|
+ if (CIRCUIT_IS_ORIGIN(circ)) {
|
|
|
+ tor_assert(layer_hint);
|
|
|
+ --layer_hint->deliver_window;
|
|
|
+ deliver_window = layer_hint->deliver_window;
|
|
|
+ domain = LD_APP;
|
|
|
+ } else {
|
|
|
+ tor_assert(!layer_hint);
|
|
|
+ --circ->deliver_window;
|
|
|
+ deliver_window = circ->deliver_window;
|
|
|
+ domain = LD_EXIT;
|
|
|
+ }
|
|
|
+
|
|
|
+ log_debug(domain, "Circuit deliver_window now %d.", deliver_window);
|
|
|
+ return deliver_window;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * conn. Update the deliver window and return its new value. */
|
|
|
+int
|
|
|
+sendme_stream_data_received(edge_connection_t *conn)
|
|
|
+{
|
|
|
+ tor_assert(conn);
|
|
|
+ return --conn->deliver_window;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * layer_hint is NULL, this means we are the Exit end point else we are the
|
|
|
+ * Client. Update the package window and return its new value. */
|
|
|
+int
|
|
|
+sendme_note_circuit_data_packaged(circuit_t *circ, crypt_path_t *layer_hint)
|
|
|
+{
|
|
|
+ int package_window, domain;
|
|
|
+
|
|
|
+ tor_assert(circ);
|
|
|
+
|
|
|
+ if (CIRCUIT_IS_ORIGIN(circ)) {
|
|
|
+
|
|
|
+ tor_assert(layer_hint);
|
|
|
+ --layer_hint->package_window;
|
|
|
+ package_window = layer_hint->package_window;
|
|
|
+ domain = LD_APP;
|
|
|
+ } else {
|
|
|
+
|
|
|
+ tor_assert(!layer_hint);
|
|
|
+ --circ->package_window;
|
|
|
+ package_window = circ->package_window;
|
|
|
+ domain = LD_EXIT;
|
|
|
+ }
|
|
|
+
|
|
|
+ log_debug(domain, "Circuit package_window now %d.", package_window);
|
|
|
+ return package_window;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * conn. Update the package window and return its new value. */
|
|
|
+int
|
|
|
+sendme_note_stream_data_packaged(edge_connection_t *conn)
|
|
|
+{
|
|
|
+ tor_assert(conn);
|
|
|
+ return --conn->package_window;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * It is safe to pass a circuit that isn't meant to track those digests. */
|
|
|
+void
|
|
|
+sendme_record_cell_digest(circuit_t *circ)
|
|
|
+{
|
|
|
+ const uint8_t *digest;
|
|
|
+
|
|
|
+ tor_assert(circ);
|
|
|
+
|
|
|
+
|
|
|
+ * this cell is the last one before the client should send a SENDME. */
|
|
|
+ if (CIRCUIT_IS_ORIGIN(circ)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ * package_window reaches a multiple of the increment, after this cell, we
|
|
|
+ * should expect a SENDME. */
|
|
|
+ if (!sendme_circuit_cell_is_next(circ->package_window)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ digest = relay_crypto_get_sendme_digest(&TO_OR_CIRCUIT(circ)->crypto);
|
|
|
+ if (circ->sendme_last_digests == NULL) {
|
|
|
+ circ->sendme_last_digests = smartlist_new();
|
|
|
+ }
|
|
|
+ smartlist_add(circ->sendme_last_digests, tor_memdup(digest, DIGEST_LEN));
|
|
|
+}
|