diff options
Diffstat (limited to 'src/core/or/connection_edge.c')
-rw-r--r-- | src/core/or/connection_edge.c | 110 |
1 files changed, 109 insertions, 1 deletions
diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c index f21779a80c..b36d0d9013 100644 --- a/src/core/or/connection_edge.c +++ b/src/core/or/connection_edge.c @@ -73,6 +73,7 @@ #include "core/or/conflux_util.h" #include "core/or/circuitstats.h" #include "core/or/connection_or.h" +#include "core/or/dos.h" #include "core/or/extendinfo.h" #include "core/or/policies.h" #include "core/or/reasons.h" @@ -105,6 +106,7 @@ #include "lib/buf/buffers.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" +#include "lib/encoding/confline.h" #include "core/or/cell_st.h" #include "core/or/cpath_build_state_st.h" @@ -3989,6 +3991,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) begin_cell_t bcell; int rv; uint8_t end_reason=0; + dos_stream_defense_type_t dos_defense_type; assert_circuit_ok(circ); if (!CIRCUIT_IS_ORIGIN(circ)) { @@ -4147,6 +4150,24 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) log_debug(LD_EXIT,"about to start the dns_resolve()."); + // in the future we may want to have a similar defense for BEGIN_DIR and + // BEGIN sent to OS. + dos_defense_type = dos_stream_new_begin_or_resolve_cell(or_circ); + switch (dos_defense_type) { + case DOS_STREAM_DEFENSE_NONE: + break; + case DOS_STREAM_DEFENSE_REFUSE_STREAM: + // we don't use END_STREAM_REASON_RESOURCELIMIT because it would make a + // client mark us as non-functional until they get a new consensus. + relay_send_end_cell_from_edge(rh.stream_id, circ, END_STREAM_REASON_MISC, + layer_hint); + connection_free_(TO_CONN(n_stream)); + return 0; + case DOS_STREAM_DEFENSE_CLOSE_CIRCUIT: + connection_free_(TO_CONN(n_stream)); + return -END_CIRC_REASON_RESOURCELIMIT; + } + /* send it off to the gethostbyname farm */ switch (dns_resolve(n_stream)) { case 1: /* resolve worked; now n_stream is attached to circ. */ @@ -4170,17 +4191,21 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) * Called when we receive a RELAY_COMMAND_RESOLVE cell 'cell' along the * circuit <b>circ</b>; * begin resolving the hostname, and (eventually) reply with a RESOLVED cell. + * + * Return -(some circuit end reason) if we want to tear down <b>circ</b>. + * Else return 0. */ int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ) { edge_connection_t *dummy_conn; relay_header_t rh; + dos_stream_defense_type_t dos_defense_type; assert_circuit_ok(TO_CIRCUIT(circ)); relay_header_unpack(&rh, cell->payload); if (rh.length > RELAY_PAYLOAD_SIZE) - return -1; + return 0; /* Note the RESOLVE stream as seen. */ rep_hist_note_exit_stream(RELAY_COMMAND_RESOLVE); @@ -4203,6 +4228,19 @@ connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ) dummy_conn->on_circuit = TO_CIRCUIT(circ); + dos_defense_type = dos_stream_new_begin_or_resolve_cell(circ); + switch (dos_defense_type) { + case DOS_STREAM_DEFENSE_NONE: + break; + case DOS_STREAM_DEFENSE_REFUSE_STREAM: + dns_send_resolved_error_cell(dummy_conn, RESOLVED_TYPE_ERROR_TRANSIENT); + connection_free_(TO_CONN(dummy_conn)); + return 0; + case DOS_STREAM_DEFENSE_CLOSE_CIRCUIT: + connection_free_(TO_CONN(dummy_conn)); + return -END_CIRC_REASON_RESOURCELIMIT; + } + /* send it off to the gethostbyname farm */ switch (dns_resolve(dummy_conn)) { case -1: /* Impossible to resolve; a resolved cell was sent. */ @@ -4237,6 +4275,76 @@ my_exit_policy_rejects(const tor_addr_t *addr, return 0; } +/* Reapply exit policy to existing connections, possibly terminating + * connections + * no longer allowed by the policy. + */ +void +connection_reapply_exit_policy(config_line_t *changes) +{ + int marked_for_close = 0; + smartlist_t *conn_list = NULL; + smartlist_t *policy = NULL; + int config_change_relevant = 0; + + if (get_options()->ReevaluateExitPolicy == 0) { + return; + } + + for (const config_line_t *line = changes; + line && !config_change_relevant; + line = line->next) { + const char* exit_policy_options[] = { + "ExitRelay", + "ExitPolicy", + "ReducedExitPolicy", + "ReevaluateExitPolicy", + "IPv6Exit", + NULL + }; + for (unsigned int i = 0; exit_policy_options[i] != NULL; ++i) { + if (strcmp(line->key, exit_policy_options[i]) == 0) { + config_change_relevant = 1; + break; + } + } + } + + if (!config_change_relevant) { + /* Policy did not change: no need to iterate over connections */ + return; + } + + // we can't use router_compare_to_my_exit_policy as it depend on the + // descriptor, which is regenerated asynchronously, so we have to parse the + // policy ourselves. + // We don't verify for our own IP, it's not part of the configuration. + if (BUG(policies_parse_exit_policy_from_options(get_options(), NULL, NULL, + &policy) != 0)) { + return; + } + + conn_list = connection_list_by_type_purpose(CONN_TYPE_EXIT, + EXIT_PURPOSE_CONNECT); + + SMARTLIST_FOREACH_BEGIN(conn_list, connection_t *, conn) { + addr_policy_result_t verdict = compare_tor_addr_to_addr_policy(&conn->addr, + conn->port, + policy); + if (verdict != ADDR_POLICY_ACCEPTED) { + connection_edge_end(TO_EDGE_CONN(conn), END_STREAM_REASON_EXITPOLICY); + connection_mark_for_close(conn); + ++marked_for_close; + } + } SMARTLIST_FOREACH_END(conn); + + smartlist_free(conn_list); + smartlist_free(policy); + + log_info(LD_GENERAL, "Marked %d connections to be closed as no longer " + "allowed per ExitPolicy", marked_for_close); +} + /** Return true iff the consensus allows network reentry. The default value is * false if the parameter is not found. */ static bool |