Commit b169c8c1 authored by Nick Mathewson's avatar Nick Mathewson 🐛
Browse files

Merge remote-tracking branch 'asn-github/adaptive_padding-final'

parents 691dec5d b269ab5a
......@@ -1021,6 +1021,26 @@ The following options are useful only for clients (that is, if
The .exit address notation, if enabled via MapAddress, overrides
this option.
[[MiddleNodes]] **MiddleNodes** __node__,__node__,__...__::
A list of identity fingerprints and country codes of nodes
to use for "middle" hops in your normal circuits.
Normal circuits include all circuits except for direct connections
to directory servers. Middle hops are all hops other than exit and entry. +
+
This is an **experimental** feature that is meant to be used by researchers
and developers to test new features in the Tor network safely. Using it
without care will strongly influence your anonymity. This feature might get
removed in the future.
+
The HSLayer2Node and HSLayer3Node options override this option for onion
service circuits, if they are set. The vanguards addon will read this
option, and if set, it will set HSLayer2Nodes and HSLayer3Nodes to nodes
from this set.
+
The ExcludeNodes option overrides this option: any node listed in both
MiddleNodes and ExcludeNodes is treated as excluded. See
the **ExcludeNodes** option for more information on how to specify nodes.
[[EntryNodes]] **EntryNodes** __node__,__node__,__...__::
A list of identity fingerprints and country codes of nodes
to use for the first hop in your normal circuits.
......@@ -1037,13 +1057,14 @@ The following options are useful only for clients (that is, if
If StrictNodes is set to 1, Tor will treat solely the ExcludeNodes option
as a requirement to follow for all the circuits you generate, even if
doing so will break functionality for you (StrictNodes applies to neither
ExcludeExitNodes nor to ExitNodes). If StrictNodes is set to 0, Tor will
still try to avoid nodes in the ExcludeNodes list, but it will err on the
side of avoiding unexpected errors. Specifically, StrictNodes 0 tells Tor
that it is okay to use an excluded node when it is *necessary* to perform
relay reachability self-tests, connect to a hidden service, provide a
hidden service to a client, fulfill a .exit request, upload directory
information, or download directory information. (Default: 0)
ExcludeExitNodes nor to ExitNodes, nor to MiddleNodes). If StrictNodes
is set to 0, Tor will still try to avoid nodes in the ExcludeNodes list,
but it will err on the side of avoiding unexpected errors.
Specifically, StrictNodes 0 tells Tor that it is okay to use an excluded
node when it is *necessary* to perform relay reachability self-tests,
connect to a hidden service, provide a hidden service to a client,
fulfill a .exit request, upload directory information, or download
directory information. (Default: 0)
[[FascistFirewall]] **FascistFirewall** **0**|**1**::
If 1, Tor will only create outgoing connections to ORs running on ports
......
......@@ -421,6 +421,10 @@ static config_var_t option_vars_[] = {
V(ExcludeExitNodes, ROUTERSET, NULL),
OBSOLETE("ExcludeSingleHopRelays"),
V(ExitNodes, ROUTERSET, NULL),
/* Researchers need a way to tell their clients to use specific
* middles that they also control, to allow safe live-network
* experimentation with new padding machines. */
V(MiddleNodes, ROUTERSET, NULL),
V(ExitPolicy, LINELIST, NULL),
V(ExitPolicyRejectPrivate, BOOL, "1"),
V(ExitPolicyRejectLocalInterfaces, BOOL, "0"),
......@@ -1693,6 +1697,7 @@ options_need_geoip_info(const or_options_t *options, const char **reason_out)
int routerset_usage =
routerset_needs_geoip(options->EntryNodes) ||
routerset_needs_geoip(options->ExitNodes) ||
routerset_needs_geoip(options->MiddleNodes) ||
routerset_needs_geoip(options->ExcludeExitNodes) ||
routerset_needs_geoip(options->ExcludeNodes) ||
routerset_needs_geoip(options->HSLayer2Nodes) ||
......@@ -2132,6 +2137,7 @@ options_act(const or_options_t *old_options)
options->HSLayer2Nodes) ||
!routerset_equal(old_options->HSLayer3Nodes,
options->HSLayer3Nodes) ||
!routerset_equal(old_options->MiddleNodes, options->MiddleNodes) ||
options->StrictNodes != old_options->StrictNodes) {
log_info(LD_CIRC,
"Changed to using entry guards or bridges, or changed "
......
......@@ -72,6 +72,9 @@ struct or_options_t {
routerset_t *ExitNodes; /**< Structure containing nicknames, digests,
* country codes and IP address patterns of ORs to
* consider as exits. */
routerset_t *MiddleNodes; /**< Structure containing nicknames, digests,
* country codes and IP address patterns of ORs to
* consider as middles. */
routerset_t *EntryNodes;/**< Structure containing nicknames, digests,
* country codes and IP address patterns of ORs to
* consider as entry points. */
......
......@@ -22,6 +22,7 @@
#include "core/mainloop/netstatus.h"
#include "core/or/channel.h"
#include "core/or/channelpadding.h"
#include "core/or/circuitpadding.h"
#include "core/or/channeltls.h"
#include "core/or/circuitlist.h"
#include "core/or/circuitmux_ewma.h"
......@@ -645,9 +646,13 @@ tor_init(int argc, char *argv[])
/* The options are now initialised */
const or_options_t *options = get_options();
/* Initialize channelpadding parameters to defaults until we get
* a consensus */
/* Initialize channelpadding and circpad parameters to defaults
* until we get a consensus */
channelpadding_new_consensus_params(NULL);
circpad_new_consensus_params(NULL);
/* Initialize circuit padding to defaults+torrc until we get a consensus */
circpad_machines_init();
/* Initialize predicted ports list after loading options */
predicted_ports_init();
......@@ -766,6 +771,7 @@ tor_free_all(int postfork)
dns_free_all();
clear_pending_onions();
circuit_free_all();
circpad_machines_free();
entry_guards_free_all();
pt_free_all();
channel_tls_free_all();
......
......@@ -32,6 +32,7 @@ LIBTOR_APP_A_SOURCES = \
src/core/or/circuitlist.c \
src/core/or/circuitmux.c \
src/core/or/circuitmux_ewma.c \
src/core/or/circuitpadding.c \
src/core/or/circuitstats.c \
src/core/or/circuituse.c \
src/core/or/command.c \
......@@ -227,6 +228,7 @@ noinst_HEADERS += \
src/core/or/circuitmux.h \
src/core/or/circuitmux_ewma.h \
src/core/or/circuitstats.h \
src/core/or/circuitpadding.h \
src/core/or/circuituse.h \
src/core/or/command.h \
src/core/or/connection_edge.h \
......
......@@ -12,6 +12,11 @@
#include "core/or/cell_queue_st.h"
struct hs_token_t;
struct circpad_machine_spec_t;
struct circpad_machine_state_t;
/** Number of padding state machines on a circuit. */
#define CIRCPAD_MAX_MACHINES (2)
/** "magic" value for an origin_circuit_t */
#define ORIGIN_CIRCUIT_MAGIC 0x35315243u
......@@ -177,6 +182,27 @@ struct circuit_t {
/** Hashtable node: used to look up the circuit by its HS token using the HS
circuitmap. */
HT_ENTRY(circuit_t) hs_circuitmap_node;
/** Adaptive Padding state machines: these are immutable. The state machines
* that come from the consensus are saved to a global structure, to avoid
* per-circuit allocations. This merely points to the global copy in
* origin_padding_machines or relay_padding_machines that should never
* change or get deallocated.
*
* Each element of this array corresponds to a different padding machine,
* and we can have up to CIRCPAD_MAX_MACHINES such machines. */
const struct circpad_machine_spec_t *padding_machine[CIRCPAD_MAX_MACHINES];
/** Adaptive Padding machine info for above machines. This is the
* per-circuit mutable information, such as the current state and
* histogram token counts. Some of it is optional (aka NULL).
* If a machine is being shut down, these indexes can be NULL
* without the corresponding padding_machine being NULL, while we
* wait for the other end to respond to our shutdown request.
*
* Each element of this array corresponds to a different padding machine,
* and we can have up to CIRCPAD_MAX_MACHINES such machines. */
struct circpad_machine_state_t *padding_info[CIRCPAD_MAX_MACHINES];
};
#endif
......@@ -43,6 +43,7 @@
#include "core/or/circuitlist.h"
#include "core/or/circuitstats.h"
#include "core/or/circuituse.h"
#include "core/or/circuitpadding.h"
#include "core/or/command.h"
#include "core/or/connection_edge.h"
#include "core/or/connection_or.h"
......@@ -950,12 +951,15 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
crypt_path_t *hop = onion_next_hop_in_cpath(circ->cpath);
circuit_build_times_handle_completed_hop(circ);
circpad_machine_event_circ_added_hop(circ);
if (hop) {
/* Case two: we're on a hop after the first. */
return circuit_send_intermediate_onion_skin(circ, hop);
}
/* Case three: the circuit is finished. Do housekeeping tasks on it. */
circpad_machine_event_circ_built(circ);
return circuit_build_no_more_hops(circ);
}
......@@ -2606,7 +2610,24 @@ choose_good_middle_server(uint8_t purpose,
return choice;
}
choice = router_choose_random_node(excluded, options->ExcludeNodes, flags);
if (options->MiddleNodes) {
smartlist_t *sl = smartlist_new();
routerset_get_all_nodes(sl, options->MiddleNodes,
options->ExcludeNodes, 1);
smartlist_subtract(sl, excluded);
choice = node_sl_choose_by_bandwidth(sl, WEIGHT_FOR_MID);
smartlist_free(sl);
if (choice) {
log_fn(LOG_INFO, LD_CIRC, "Chose fixed middle node: %s",
hex_str(choice->identity, DIGEST_LEN));
} else {
log_fn(LOG_NOTICE, LD_CIRC, "Restricted middle not available");
}
} else {
choice = router_choose_random_node(excluded, options->ExcludeNodes, flags);
}
smartlist_free(excluded);
return choice;
}
......
......@@ -62,6 +62,7 @@
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/circuitstats.h"
#include "core/or/circuitpadding.h"
#include "core/mainloop/connection.h"
#include "app/config/config.h"
#include "core/or/connection_edge.h"
......@@ -1231,6 +1232,9 @@ circuit_free_(circuit_t *circ)
CIRCUIT_IS_ORIGIN(circ) ?
TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0);
/* Free any circuit padding structures */
circpad_circuit_free_all_machineinfos(circ);
if (should_free) {
memwipe(mem, 0xAA, memlen); /* poison memory */
tor_free(mem);
......
This diff is collapsed.
This diff is collapsed.
......@@ -35,6 +35,7 @@
#include "core/or/circuitlist.h"
#include "core/or/circuitstats.h"
#include "core/or/circuituse.h"
#include "core/or/circuitpadding.h"
#include "core/or/connection_edge.h"
#include "core/or/policies.h"
#include "feature/client/addressmap.h"
......@@ -1419,6 +1420,11 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn)
if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) {
hs_dec_rdv_stream_counter(origin_circ);
}
/* If there are no more streams on this circ, tell circpad */
if (!origin_circ->p_streams)
circpad_machine_event_circ_has_no_streams(origin_circ);
return;
}
} else {
......@@ -2586,6 +2592,12 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ,
/* add it into the linked list of streams on this circuit */
log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %u.",
(unsigned)circ->base_.n_circ_id);
/* If this is the first stream on this circuit, tell circpad
* that streams are attached */
if (!circ->p_streams)
circpad_machine_event_circ_has_streams(circ);
/* reset it, so we can measure circ timeouts */
ENTRY_TO_CONN(apconn)->timestamp_last_read_allowed = time(NULL);
ENTRY_TO_EDGE_CONN(apconn)->next_stream = circ->p_streams;
......@@ -3064,6 +3076,8 @@ circuit_change_purpose(circuit_t *circ, uint8_t new_purpose)
if (CIRCUIT_IS_ORIGIN(circ)) {
control_event_circuit_purpose_changed(TO_ORIGIN_CIRCUIT(circ),
old_purpose);
circpad_machine_event_circ_purpose_changed(TO_ORIGIN_CIRCUIT(circ));
}
}
......
......@@ -67,6 +67,7 @@
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/circuitpadding.h"
#include "core/or/connection_edge.h"
#include "core/or/connection_or.h"
#include "core/or/policies.h"
......@@ -3712,6 +3713,10 @@ handle_hs_exit_conn(circuit_t *circ, edge_connection_t *conn)
/* Link the circuit and the connection crypt path. */
conn->cpath_layer = origin_circ->cpath->prev;
/* If this is the first stream on this circuit, tell circpad */
if (!origin_circ->p_streams)
circpad_machine_event_circ_has_streams(origin_circ);
/* Add it into the linked list of p_streams on this circuit */
conn->next_stream = origin_circ->p_streams;
origin_circ->p_streams = conn;
......
......@@ -207,6 +207,9 @@ struct curve25519_public_key_t;
#define RELAY_COMMAND_RENDEZVOUS_ESTABLISHED 39
#define RELAY_COMMAND_INTRODUCE_ACK 40
#define RELAY_COMMAND_PADDING_NEGOTIATE 41
#define RELAY_COMMAND_PADDING_NEGOTIATED 42
/* Reasons why an OR connection is closed. */
#define END_OR_CONN_REASON_DONE 1
#define END_OR_CONN_REASON_REFUSED 2 /* connection refused */
......@@ -836,6 +839,10 @@ typedef struct protover_summary_flags_t {
* service rendezvous point supporting version 3 as seen in proposal 224.
* This requires HSRend=2. */
unsigned int supports_v3_rendezvous_point: 1;
/** True iff this router has a protocol list that allows clients to
* negotiate link-level padding. Requires Padding>=1. */
unsigned int supports_padding : 1;
} protover_summary_flags_t;
typedef struct routerinfo_t routerinfo_t;
......
......@@ -161,6 +161,10 @@ struct origin_circuit_t {
* connections to this circuit. */
unsigned int unusable_for_new_conns : 1;
/* If this flag is set (due to padding negotiation failure), we should
* not try to negotiate further circuit padding. */
unsigned padding_negotiation_failed : 1;
/**
* Tristate variable to guard against pathbias miscounting
* due to circuit purpose transitions changing the decision
......
......@@ -39,6 +39,9 @@ static int protocol_list_contains(const smartlist_t *protos,
static const struct {
protocol_type_t protover_type;
const char *name;
/* If you add a new protocol here, you probably also want to add
* parsing for it in routerstatus_parse_entry_from_string() so that
* it is set in routerstatus_t */
} PROTOCOL_NAMES[] = {
{ PRT_LINK, "Link" },
{ PRT_LINKAUTH, "LinkAuth" },
......@@ -49,6 +52,7 @@ static const struct {
{ PRT_HSREND, "HSRend" },
{ PRT_DESC, "Desc" },
{ PRT_MICRODESC, "Microdesc"},
{ PRT_PADDING, "Padding"},
{ PRT_CONS, "Cons" }
};
......@@ -396,7 +400,8 @@ protover_get_supported_protocols(void)
"LinkAuth=3 "
#endif
"Microdesc=1-2 "
"Relay=1-2";
"Relay=1-2 "
"Padding=1";
}
/** The protocols from protover_get_supported_protocols(), as parsed into a
......
......@@ -43,6 +43,7 @@ typedef enum protocol_type_t {
PRT_DESC,
PRT_MICRODESC,
PRT_CONS,
PRT_PADDING,
} protocol_type_t;
bool protover_contains_long_protocol_names(const char *s);
......
......@@ -55,6 +55,7 @@
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/circuitpadding.h"
#include "lib/compress/compress.h"
#include "app/config/config.h"
#include "core/mainloop/connection.h"
......@@ -80,7 +81,6 @@
#include "feature/nodelist/describe.h"
#include "feature/nodelist/routerlist.h"
#include "core/or/scheduler.h"
#include "feature/stats/rephist.h"
#include "core/or/cell_st.h"
#include "core/or/cell_queue_st.h"
......@@ -293,7 +293,9 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
return 0;
}
/* not recognized. pass it on. */
/* not recognized. inform circpad and pass it on. */
circpad_deliver_unrecognized_cell_events(circ, cell_direction);
if (cell_direction == CELL_DIRECTION_OUT) {
cell->circ_id = circ->n_circ_id; /* switch it */
chan = circ->n_chan;
......@@ -353,11 +355,11 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
* - Encrypt it to the right layer
* - Append it to the appropriate cell_queue on <b>circ</b>.
*/
static int
circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
MOCK_IMPL(int,
circuit_package_relay_cell, (cell_t *cell, circuit_t *circ,
cell_direction_t cell_direction,
crypt_path_t *layer_hint, streamid_t on_stream,
const char *filename, int lineno)
const char *filename, int lineno))
{
channel_t *chan; /* where to send the cell */
......@@ -524,6 +526,8 @@ relay_command_to_string(uint8_t command)
case RELAY_COMMAND_INTRODUCE_ACK: return "INTRODUCE_ACK";
case RELAY_COMMAND_EXTEND2: return "EXTEND2";
case RELAY_COMMAND_EXTENDED2: return "EXTENDED2";
case RELAY_COMMAND_PADDING_NEGOTIATE: return "PADDING_NEGOTIATE";
case RELAY_COMMAND_PADDING_NEGOTIATED: return "PADDING_NEGOTIATED";
default:
tor_snprintf(buf, sizeof(buf), "Unrecognized relay command %u",
(unsigned)command);
......@@ -577,8 +581,8 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *circ,
log_debug(LD_OR,"delivering %d cell %s.", relay_command,
cell_direction == CELL_DIRECTION_OUT ? "forward" : "backward");
if (relay_command == RELAY_COMMAND_DROP)
rep_hist_padding_count_write(PADDING_TYPE_DROP);
/* Tell circpad we're sending a relay cell */
circpad_deliver_sent_relay_cell_events(circ, relay_command);
/* If we are sending an END cell and this circuit is used for a tunneled
* directory request, advance its state. */
......@@ -602,7 +606,9 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *circ,
* one of them. Don't worry about the conn protocol version:
* append_cell_to_circuit_queue will fix it up. */
cell.command = CELL_RELAY_EARLY;
--origin_circ->remaining_relay_early_cells;
/* If we're out of relay early cells, tell circpad */
if (--origin_circ->remaining_relay_early_cells == 0)
circpad_machine_event_circ_has_no_relay_early(origin_circ);
log_debug(LD_OR, "Sending a RELAY_EARLY cell; %d remaining.",
(int)origin_circ->remaining_relay_early_cells);
/* Memorize the command that is sent as RELAY_EARLY cell; helps debug
......@@ -1481,9 +1487,11 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
}
}
/* Tell circpad that we've recieved a recognized cell */
circpad_deliver_recognized_relay_cell_events(circ, rh.command, layer_hint);
/* either conn is NULL, in which case we've got a control cell, or else
* conn points to the recognized stream. */
if (conn && !connection_state_is_open(TO_CONN(conn))) {
if (conn->base_.type == CONN_TYPE_EXIT &&
(conn->base_.state == EXIT_CONN_STATE_CONNECTING ||
......@@ -1504,8 +1512,14 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
switch (rh.command) {
case RELAY_COMMAND_DROP:
rep_hist_padding_count_read(PADDING_TYPE_DROP);
// log_info(domain,"Got a relay-level padding cell. Dropping.");
/* Already examined in circpad_deliver_recognized_relay_cell_events */
return 0;
case RELAY_COMMAND_PADDING_NEGOTIATE:
circpad_handle_padding_negotiate(circ, cell);
return 0;
case RELAY_COMMAND_PADDING_NEGOTIATED:
if (circpad_handle_padding_negotiated(circ, cell, layer_hint) == 0)
circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length);
return 0;
case RELAY_COMMAND_BEGIN:
case RELAY_COMMAND_BEGIN_DIR:
......
......@@ -78,6 +78,11 @@ void destroy_cell_queue_append(destroy_cell_queue_t *queue,
void channel_unlink_all_circuits(channel_t *chan, smartlist_t *detached_out);
MOCK_DECL(int, channel_flush_from_first_active_circuit,
(channel_t *chan, int max));
MOCK_DECL(int, circuit_package_relay_cell, (cell_t *cell, circuit_t *circ,
cell_direction_t cell_direction,
crypt_path_t *layer_hint, streamid_t on_stream,
const char *filename, int lineno));
void update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction,
const char *file, int lineno);
#define update_circuit_on_cmux(circ, direction) \
......
......@@ -448,6 +448,8 @@ memoize_protover_summary(protover_summary_flags_t *out,
out->supports_v3_rendezvous_point =
protocol_list_supports_protocol(protocols, PRT_HSREND,
PROTOVER_HS_RENDEZVOUS_POINT_V3);
out->supports_padding =
protocol_list_supports_protocol(protocols, PRT_PADDING, 1);
protover_summary_flags_t *new_cached = tor_memdup(out, sizeof(*out));
cached = strmap_set(protover_summary_map, protocols, new_cached);
......
......@@ -37,6 +37,7 @@ hibernating, phase 2:
#include "core/or/connection_or.h"
#include "feature/control/control.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/defs/time.h"
#include "feature/hibernate/hibernate.h"
#include "core/mainloop/mainloop.h"
#include "feature/relay/router.h"
......@@ -832,8 +833,6 @@ hibernate_soft_limit_reached(void)
return get_accounting_bytes() >= soft_limit;
}
#define TOR_USEC_PER_SEC (1000000)
/** Called when we get a SIGINT, or when bandwidth soft limit is
* reached. Puts us into "loose hibernation": we don't accept new
* connections, but we continue handling old ones. */
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment