123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710 |
- /* Copyright (c) 2019, The Tor Project, Inc. */
- /* See LICENSE for licensing information */
- /**
- * \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/crypt_path.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_cell.h"
- /* Return the minimum version given by the consensus (if any) that should be
- * 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);
- }
- /* Return the minimum version given by the consensus (if any) that should be
- * 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);
- }
- /* Pop the first cell digset on the given circuit from the SENDME last digests
- * list. NULL is returned if the list is uninitialized or empty.
- *
- * The caller gets ownership of the returned digest thus is responsible for
- * freeing the memory. */
- static uint8_t *
- pop_first_cell_digest(const circuit_t *circ)
- {
- uint8_t *circ_digest;
- tor_assert(circ);
- if (circ->sendme_last_digests == NULL ||
- smartlist_len(circ->sendme_last_digests) == 0) {
- return NULL;
- }
- /* More cell digest than the SENDME window is never suppose to happen. The
- * cell should have been rejected before reaching this point due to its
- * package_window down to 0 leading to a circuit close. Scream loudly but
- * still pop the element so we don't memory leak. */
- tor_assert_nonfatal(smartlist_len(circ->sendme_last_digests) <=
- CIRCWINDOW_START_MAX / CIRCWINDOW_INCREMENT);
- circ_digest = smartlist_get(circ->sendme_last_digests, 0);
- smartlist_del_keeporder(circ->sendme_last_digests, 0);
- return circ_digest;
- }
- /* Return true iff the given cell digest matches the first digest in the
- * circuit sendme list. */
- static bool
- v1_digest_matches(const uint8_t *circ_digest, const uint8_t *cell_digest)
- {
- tor_assert(circ_digest);
- tor_assert(cell_digest);
- /* Compare the digest with the one in the SENDME. This cell is invalid
- * 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.");
- return false;
- }
- /* Digests matches! */
- return true;
- }
- /* Return true iff the given decoded SENDME version 1 cell is valid and
- * 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 uint8_t *circ_digest)
- {
- tor_assert(cell);
- tor_assert(circ_digest);
- const uint8_t *cell_digest = sendme_cell_getconstarray_data_v1_digest(cell);
- return v1_digest_matches(circ_digest, cell_digest);
- }
- /* Return true iff the given cell version can be handled or if the minimum
- * accepted version from the consensus is known to us. */
- STATIC bool
- cell_version_can_be_handled(uint8_t cell_version)
- {
- int accept_version = get_accept_min_version();
- /* We will first check if the consensus minimum accepted version can be
- * handled by us and if not, regardless of the cell version we got, we can't
- * continue. */
- 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 <= %u. Probably your tor is too old?",
- accept_version, SENDME_MAX_SUPPORTED_VERSION);
- goto invalid;
- }
- /* Then, is this version below the accepted version from the consensus? If
- * yes, we must not handle it. */
- if (cell_version < accept_version) {
- log_info(LD_PROTOCOL, "Unacceptable SENDME version %u. Only "
- "accepting %u (from consensus). Closing circuit.",
- cell_version, accept_version);
- goto invalid;
- }
- /* Is this cell version supported by us? */
- if (cell_version > SENDME_MAX_SUPPORTED_VERSION) {
- log_info(LD_PROTOCOL, "SENDME cell version %u is not supported by us. "
- "We only support <= %u",
- cell_version, SENDME_MAX_SUPPORTED_VERSION);
- goto invalid;
- }
- return true;
- invalid:
- return false;
- }
- /* Return true iff the encoded SENDME cell in cell_payload of length
- * 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 marked for close by the caller. */
- STATIC bool
- sendme_is_valid(const circuit_t *circ, const uint8_t *cell_payload,
- size_t cell_payload_len)
- {
- uint8_t cell_version;
- uint8_t *circ_digest = NULL;
- sendme_cell_t *cell = NULL;
- tor_assert(circ);
- tor_assert(cell_payload);
- /* An empty payload means version 0 so skip trunnel parsing. We won't be
- * able to parse a 0 length buffer into a valid SENDME cell. */
- if (cell_payload_len == 0) {
- cell_version = 0;
- } else {
- /* First we'll decode the cell so we can get the version. */
- 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);
- }
- /* Validate that we can handle this cell version. */
- if (!cell_version_can_be_handled(cell_version)) {
- goto invalid;
- }
- /* Pop the first element that was added (FIFO). We do that regardless of the
- * version so we don't accumulate on the circuit if v0 is used by the other
- * end point. */
- circ_digest = pop_first_cell_digest(circ);
- if (circ_digest == NULL) {
- /* We shouldn't have received a SENDME if we have no digests. Log at
- * protocol warning because it can be tricked by sending many SENDMEs
- * without prior data cell. */
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "We received a SENDME but we have no cell digests to match. "
- "Closing circuit.");
- goto invalid;
- }
- /* Validate depending on the version now. */
- switch (cell_version) {
- case 0x01:
- if (!cell_v1_is_valid(cell, circ_digest)) {
- goto invalid;
- }
- break;
- case 0x00:
- /* Version 0, there is no work to be done on the payload so it is
- * necessarily valid if we pass the version validation. */
- break;
- default:
- log_warn(LD_PROTOCOL, "Unknown SENDME cell version %d received.",
- cell_version);
- tor_assert_nonfatal_unreached();
- break;
- }
- /* Valid cell. */
- sendme_cell_free(cell);
- tor_free(circ_digest);
- return true;
- invalid:
- sendme_cell_free(cell);
- tor_free(circ_digest);
- return false;
- }
- /* Build and encode a version 1 SENDME cell into payload, which must be at
- * 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();
- /* Building a payload for version 1. */
- sendme_cell_set_version(cell, 0x01);
- /* Set the data length field for v1. */
- sendme_cell_set_data_len(cell, TRUNNEL_SENDME_V1_DIGEST_LEN);
- /* Copy the digest into the data payload. */
- memcpy(sendme_cell_getarray_data_v1_digest(cell), cell_digest,
- sendme_cell_get_data_len(cell));
- /* Finally, encode the cell into the payload. */
- len = sendme_cell_encode(payload, RELAY_PAYLOAD_SIZE, cell);
- sendme_cell_free(cell);
- return len;
- }
- /* Send a circuit-level SENDME on the given circuit using the layer_hint if
- * 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)) {
- /* Unable to encode the cell, abort. We can recover from this by closing
- * the circuit but in theory it should never happen. */
- return -1;
- }
- log_debug(LD_PROTOCOL, "Emitting SENDME version 1 cell.");
- break;
- case 0x00:
- /* Fallthrough because default is to use v0. */
- default:
- /* Unknown version, fallback to version 0 meaning no payload. */
- payload_len = 0;
- log_debug(LD_PROTOCOL, "Emitting SENDME version 0 cell. "
- "Consensus emit version is %d", emit_version);
- 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; /* the circuit's closed, don't continue */
- }
- return 0;
- }
- /* Record the cell digest only if the next cell is expected to be a SENDME. */
- static void
- record_cell_digest_on_circ(circuit_t *circ, const uint8_t *sendme_digest)
- {
- tor_assert(circ);
- tor_assert(sendme_digest);
- /* Add the digest to the last seen list in the circuit. */
- if (circ->sendme_last_digests == NULL) {
- circ->sendme_last_digests = smartlist_new();
- }
- smartlist_add(circ->sendme_last_digests,
- tor_memdup(sendme_digest, DIGEST_LEN));
- }
- /*
- * Public API
- */
- /** Return true iff the next cell for the given cell window is expected to be
- * 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. */
- static bool
- circuit_sendme_cell_is_next(int window)
- {
- /* At the start of the window, no SENDME will be expected. */
- if (window == CIRCWINDOW_START) {
- return false;
- }
- /* Are we at the limit of the increment and if not, we don't expect next
- * cell is a SENDME.
- *
- * We test against the window minus 1 because when we are looking if the
- * next cell is a SENDME, the window (either package or deliver) hasn't been
- * decremented just yet so when this is called, we are currently processing
- * the "window - 1" cell.
- *
- * This function is used when recording a cell digest and this is done quite
- * low in the stack when decrypting or encrypting a cell. The window is only
- * updated once the cell is actually put in the outbuf. */
- if (((window - 1) % CIRCWINDOW_INCREMENT) != 0) {
- return false;
- }
- /* Next cell is expected to be a SENDME. */
- return true;
- }
- /** Called when we've just received a relay data cell, when we've just
- * 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;
- /* Don't send it if we still have data to deliver. */
- if (connection_outbuf_too_full(TO_CONN(conn))) {
- goto end;
- }
- if (circuit_get_by_edge_conn(conn) == NULL) {
- /* This can legitimately happen if the destroy has already arrived and
- * 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; /* The circuit's closed, don't continue */
- }
- }
- end:
- return;
- }
- /** Check if the deliver_window for circuit <b>circ</b> (at hop
- * <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)
- {
- bool sent_one_sendme = false;
- 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 = cpath_get_sendme_digest(layer_hint);
- } 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; /* The circuit's closed, don't continue */
- }
- /* Current implementation is not suppose to send multiple SENDME at once
- * because this means we would use the same relay crypto digest for each
- * SENDME leading to a mismatch on the other side and the circuit to
- * collapse. Scream loudly if it ever happens so we can address it. */
- tor_assert_nonfatal(!sent_one_sendme);
- sent_one_sendme = true;
- }
- }
- /* Process a circuit-level SENDME cell that we just received. The layer_hint,
- * 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 (the SENDME is valid and the package window has
- * been updated properly).
- *
- * On error, a negative value is returned, which indicates 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);
- /* Validate the SENDME cell. Depending on the version, different validation
- * can be done. An invalid SENDME requires us to close the circuit. */
- if (!sendme_is_valid(circ, cell_payload, cell_payload_len)) {
- return -END_CIRC_REASON_TORPROTOCOL;
- }
- /* If we are the origin of the circuit, we are the Client so we use the
- * layer hint (the Exit hop) for the package window tracking. */
- if (CIRCUIT_IS_ORIGIN(circ)) {
- /* If we are the origin of the circuit, it is impossible to not have a
- * cpath. Just in case, bug on it and close the circuit. */
- if (BUG(layer_hint == NULL)) {
- return -END_CIRC_REASON_TORPROTOCOL;
- }
- 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);
- /* We count circuit-level sendme's as valid delivered data because they
- * are rate limited. */
- circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), cell_payload_len);
- } else {
- /* We aren't the origin of this circuit so we are the Exit and thus we
- * 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;
- }
- /* Process a stream-level SENDME cell that we just received. The conn is the
- * 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 (the SENDME is valid and the package window has
- * been updated properly).
- *
- * On error, a negative value is returned, which indicates 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);
- /* Don't allow the other endpoint to request more than our maximum (i.e.
- * 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;
- }
- /* At this point, the stream sendme is valid */
- conn->package_window += STREAMWINDOW_INCREMENT;
- /* We count circuit-level sendme's as valid delivered data because they are
- * 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;
- }
- /* Called when a relay DATA cell is received on the given circuit. If
- * 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;
- }
- /* Called when a relay DATA cell is received for the given edge connection
- * 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;
- }
- /* Called when a relay DATA cell is packaged on the given circuit. If
- * 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)) {
- /* Client side. */
- tor_assert(layer_hint);
- --layer_hint->package_window;
- package_window = layer_hint->package_window;
- domain = LD_APP;
- } else {
- /* Exit side. */
- 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;
- }
- /* Called when a relay DATA cell is packaged for the given edge connection
- * conn. Update the package window and return its new value. */
- int
- sendme_note_stream_data_packaged(edge_connection_t *conn)
- {
- tor_assert(conn);
- --conn->package_window;
- log_debug(LD_APP, "Stream package_window now %d.", conn->package_window);
- return conn->package_window;
- }
- /* Record the cell digest into the circuit sendme digest list depending on
- * which edge we are. The digest is recorded only if we expect the next cell
- * that we will receive is a SENDME so we can match the digest. */
- void
- sendme_record_cell_digest_on_circ(circuit_t *circ, crypt_path_t *cpath)
- {
- int package_window;
- uint8_t *sendme_digest;
- tor_assert(circ);
- package_window = circ->package_window;
- if (cpath) {
- package_window = cpath->package_window;
- }
- /* Is this the last cell before a SENDME? The idea is that if the
- * package_window reaches a multiple of the increment, after this cell, we
- * should expect a SENDME. */
- if (!circuit_sendme_cell_is_next(package_window)) {
- return;
- }
- /* Getting the digest is expensive so we only do it once we are certain to
- * record it on the circuit. */
- if (cpath) {
- sendme_digest = cpath_get_sendme_digest(cpath);
- } else {
- sendme_digest =
- relay_crypto_get_sendme_digest(&TO_OR_CIRCUIT(circ)->crypto);
- }
- record_cell_digest_on_circ(circ, sendme_digest);
- }
- /* Called once we decrypted a cell and recognized it. Record the cell digest
- * as the next sendme digest only if the next cell we'll send on the circuit
- * is expected to be a SENDME. */
- void
- sendme_record_received_cell_digest(circuit_t *circ, crypt_path_t *cpath)
- {
- tor_assert(circ);
- /* Only record if the next cell is expected to be a SENDME. */
- if (!circuit_sendme_cell_is_next(cpath ? cpath->deliver_window :
- circ->deliver_window)) {
- return;
- }
- if (cpath) {
- /* Record incoming digest. */
- cpath_sendme_record_cell_digest(cpath, false);
- } else {
- /* Record foward digest. */
- relay_crypto_record_sendme_digest(&TO_OR_CIRCUIT(circ)->crypto, true);
- }
- }
- /* Called once we encrypted a cell. Record the cell digest as the next sendme
- * digest only if the next cell we expect to receive is a SENDME so we can
- * match the digests. */
- void
- sendme_record_sending_cell_digest(circuit_t *circ, crypt_path_t *cpath)
- {
- tor_assert(circ);
- /* Only record if the next cell is expected to be a SENDME. */
- if (!circuit_sendme_cell_is_next(cpath ? cpath->package_window :
- circ->package_window)) {
- goto end;
- }
- if (cpath) {
- /* Record the forward digest. */
- cpath_sendme_record_cell_digest(cpath, true);
- } else {
- /* Record the incoming digest. */
- relay_crypto_record_sendme_digest(&TO_OR_CIRCUIT(circ)->crypto, false);
- }
- end:
- return;
- }
|