|
@@ -12,6 +12,7 @@
|
|
|
#define CIRCUITLIST_PRIVATE
|
|
|
#include "or.h"
|
|
|
#include "channel.h"
|
|
|
+#include "channeltls.h"
|
|
|
#include "circpathbias.h"
|
|
|
#include "circuitbuild.h"
|
|
|
#include "circuitlist.h"
|
|
@@ -1680,6 +1681,61 @@ circuit_mark_all_dirty_circs_as_unusable(void)
|
|
|
SMARTLIST_FOREACH_END(circ);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * Report any queued cells on or_circuits as written in our bandwidth
|
|
|
+ * totals, for the specified channel direction.
|
|
|
+ *
|
|
|
+ * When we close a circuit or clear its cell queues, we've read
|
|
|
+ * data and recorded those bytes in our read statistics, but we're
|
|
|
+ * not going to write it. This discrepancy can be used by an adversary
|
|
|
+ * to infer information from our public relay statistics and perform
|
|
|
+ * attacks such as guard discovery.
|
|
|
+ *
|
|
|
+ * This function is in the critical path of circuit_mark_for_close().
|
|
|
+ * It must be (and is) O(1)!
|
|
|
+ *
|
|
|
+ * See https://trac.torproject.org/projects/tor/ticket/23512.
|
|
|
+ */
|
|
|
+void
|
|
|
+circuit_synchronize_written_or_bandwidth(const circuit_t *c,
|
|
|
+ circuit_channel_direction_t dir)
|
|
|
+{
|
|
|
+ uint64_t cells;
|
|
|
+ uint64_t cell_size;
|
|
|
+ uint64_t written_sync;
|
|
|
+ const channel_t *chan = NULL;
|
|
|
+ const or_circuit_t *or_circ;
|
|
|
+
|
|
|
+ if (!CIRCUIT_IS_ORCIRC(c))
|
|
|
+ return;
|
|
|
+
|
|
|
+ or_circ = CONST_TO_OR_CIRCUIT(c);
|
|
|
+
|
|
|
+ if (dir == CIRCUIT_N_CHAN) {
|
|
|
+ chan = c->n_chan;
|
|
|
+ cells = c->n_chan_cells.n;
|
|
|
+ } else {
|
|
|
+ chan = or_circ->p_chan;
|
|
|
+ cells = or_circ->p_chan_cells.n;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* If we still know the chan, determine real cell size. Otherwise,
|
|
|
+ * assume it's a wide circid channel */
|
|
|
+ if (chan)
|
|
|
+ cell_size = get_cell_network_size(chan->wide_circ_ids);
|
|
|
+ else
|
|
|
+ cell_size = CELL_MAX_NETWORK_SIZE;
|
|
|
+
|
|
|
+ /* The missing written bytes are the cell counts times their cell
|
|
|
+ * size plus TLS per cell overhead */
|
|
|
+ written_sync = cells*(cell_size+TLS_PER_CELL_OVERHEAD);
|
|
|
+
|
|
|
+ /* Report the missing bytes as written, to avoid asymmetry.
|
|
|
+ * We must use time() for consistency with rephist, even though on
|
|
|
+ * some very old rare platforms, approx_time() may be faster. */
|
|
|
+ rep_hist_note_bytes_written(written_sync, time(NULL));
|
|
|
+}
|
|
|
+
|
|
|
/** Mark <b>circ</b> to be closed next time we call
|
|
|
* circuit_close_all_marked(). Do any cleanup needed:
|
|
|
* - If state is onionskin_pending, remove circ from the onion_pending
|
|
@@ -1732,6 +1788,9 @@ circuit_mark_for_close_, (circuit_t *circ, int reason, int line,
|
|
|
reason = END_CIRC_REASON_NONE;
|
|
|
}
|
|
|
|
|
|
+ circuit_synchronize_written_or_bandwidth(circ, CIRCUIT_N_CHAN);
|
|
|
+ circuit_synchronize_written_or_bandwidth(circ, CIRCUIT_P_CHAN);
|
|
|
+
|
|
|
if (reason & END_CIRC_REASON_FLAG_REMOTE)
|
|
|
reason &= ~END_CIRC_REASON_FLAG_REMOTE;
|
|
|
|