Tor 0.4.9.0-alpha-dev
Macros | Functions
hs_circuit.c File Reference
#include "core/or/or.h"
#include "app/config/config.h"
#include "core/crypto/hs_ntor.h"
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/policies.h"
#include "core/or/relay.h"
#include "core/or/crypt_path.h"
#include "core/or/extendinfo.h"
#include "core/or/congestion_control_common.h"
#include "core/crypto/onion_crypto.h"
#include "feature/client/circpathbias.h"
#include "feature/hs/hs_cell.h"
#include "feature/hs/hs_circuit.h"
#include "feature/hs/hs_common.h"
#include "feature/hs/hs_ob.h"
#include "feature/hs/hs_circuitmap.h"
#include "feature/hs/hs_client.h"
#include "feature/hs/hs_ident.h"
#include "feature/hs/hs_metrics.h"
#include "feature/hs/hs_service.h"
#include "feature/nodelist/describe.h"
#include "feature/nodelist/nodelist.h"
#include "feature/stats/rephist.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/time/compat_time.h"
#include "trunnel/ed25519_cert.h"
#include "trunnel/hs/cell_establish_intro.h"
#include "core/or/congestion_control_st.h"
#include "core/or/cpath_build_state_st.h"
#include "core/or/crypt_path_st.h"
#include "feature/nodelist/node_st.h"
#include "core/or/origin_circuit_st.h"

Go to the source code of this file.

Macros

#define HS_CIRCUIT_PRIVATE
 
#define MAX_CHEAP_REND_CIRCUITS_IN_PROGRESS   16
 

Functions

static void free_pending_rend (pending_rend_t *req)
 
static int circuit_purpose_is_correct_for_rend (unsigned int circ_purpose, int is_service_side)
 
static crypt_path_tcreate_rend_cpath (const uint8_t *ntor_key_seed, size_t seed_len, int is_service_side)
 
static void finalize_rend_circuit (origin_circuit_t *circ, crypt_path_t *hop, int is_service_side)
 
static void register_intro_circ (const hs_service_intro_point_t *ip, origin_circuit_t *circ)
 
static unsigned int count_opened_desc_intro_point_circuits (const hs_service_t *service, const hs_service_descriptor_t *desc)
 
STATIC hs_ident_circuit_tcreate_rp_circuit_identifier (const hs_service_t *service, const uint8_t *rendezvous_cookie, const curve25519_public_key_t *server_pk, const hs_ntor_rend_cell_keys_t *keys)
 
static hs_ident_circuit_tcreate_intro_circuit_identifier (const hs_service_t *service, const hs_service_intro_point_t *ip)
 
static void send_establish_intro (const hs_service_t *service, hs_service_intro_point_t *ip, origin_circuit_t *circ)
 
static const char * get_service_anonymity_string (const hs_service_t *service)
 
STATIC void launch_rendezvous_point_circuit (const hs_service_t *service, const ed25519_public_key_t *ip_auth_pubkey, const curve25519_keypair_t *ip_enc_key_kp, const hs_cell_intro_rdv_data_t *rdv_data, time_t now)
 
static int can_relaunch_service_rendezvous_point (const origin_circuit_t *circ)
 
static void retry_service_rendezvous_point (const origin_circuit_t *circ)
 
static int setup_introduce1_data (const hs_desc_intro_point_t *ip, const node_t *rp_node, const hs_subcredential_t *subcredential, hs_cell_introduce1_data_t *intro1_data)
 
static void cleanup_on_close_client_circ (circuit_t *circ)
 
static void cleanup_on_free_client_circ (circuit_t *circ)
 
static int compare_rend_request_by_effort_ (const void *_a, const void *_b)
 
static int queued_rend_request_is_too_old (pending_rend_t *req, time_t now)
 
static void trim_rend_pqueue (hs_pow_service_state_t *pow_state, time_t now)
 
static int count_service_rp_circuits_pending (hs_service_t *service)
 
int top_of_rend_pqueue_is_worthwhile (hs_pow_service_state_t *pow_state)
 
void rend_pqueue_clear (hs_pow_service_state_t *pow_state)
 
static void handle_rend_pqueue_cb (mainloop_event_t *ev, void *arg)
 
static int enqueue_rend_request (const hs_service_t *service, hs_service_intro_point_t *ip, hs_cell_introduce2_data_t *data, time_t now)
 
void hs_circ_setup_congestion_control (origin_circuit_t *origin_circ, uint8_t sendme_inc, bool is_single_onion)
 
origin_circuit_ths_circ_service_get_intro_circ (const hs_service_intro_point_t *ip)
 
origin_circuit_ths_circ_service_get_established_intro_circ (const hs_service_intro_point_t *ip)
 
void hs_circ_retry_service_rendezvous_point (const origin_circuit_t *circ)
 
int hs_circ_launch_intro_point (hs_service_t *service, const hs_service_intro_point_t *ip, extend_info_t *ei, bool direct_conn)
 
int hs_circ_service_intro_has_opened (hs_service_t *service, hs_service_intro_point_t *ip, const hs_service_descriptor_t *desc, origin_circuit_t *circ)
 
void hs_circ_service_rp_has_opened (const hs_service_t *service, origin_circuit_t *circ)
 
int hs_circ_handle_intro_established (const hs_service_t *service, const hs_service_intro_point_t *ip, origin_circuit_t *circ, const uint8_t *payload, size_t payload_len)
 
static int get_subcredential_for_handling_intro2_cell (const hs_service_t *service, hs_cell_introduce2_data_t *data, const hs_subcredential_t *desc_subcred)
 
int hs_circ_handle_introduce2 (const hs_service_t *service, const origin_circuit_t *circ, hs_service_intro_point_t *ip, const hs_subcredential_t *subcredential, const uint8_t *payload, size_t payload_len)
 
int hs_circuit_setup_e2e_rend_circ (origin_circuit_t *circ, const uint8_t *ntor_key_seed, size_t seed_len, int is_service_side)
 
int hs_circ_send_introduce1 (origin_circuit_t *intro_circ, origin_circuit_t *rend_circ, const hs_desc_intro_point_t *ip, const hs_subcredential_t *subcredential, const hs_pow_solution_t *pow_solution)
 
int hs_circ_send_establish_rendezvous (origin_circuit_t *circ)
 
void hs_circ_cleanup_on_close (circuit_t *circ)
 
void hs_circ_cleanup_on_free (circuit_t *circ)
 
void hs_circ_cleanup_on_repurpose (circuit_t *circ)
 
bool hs_circ_is_rend_sent_in_intro1 (const origin_circuit_t *circ)
 

Macro Definition Documentation

◆ HS_CIRCUIT_PRIVATE

#define HS_CIRCUIT_PRIVATE

Definition at line 8 of file hs_circuit.c.

◆ MAX_CHEAP_REND_CIRCUITS_IN_PROGRESS

#define MAX_CHEAP_REND_CIRCUITS_IN_PROGRESS   16

What is the threshold of in-progress (CIRCUIT_PURPOSE_S_CONNECT_REND) rendezvous responses above which we won't launch new low-effort rendezvous responses? (Intro2 cells with suitable PoW effort are not affected by this threshold.)

Definition at line 761 of file hs_circuit.c.

Function Documentation

◆ can_relaunch_service_rendezvous_point()

static int can_relaunch_service_rendezvous_point ( const origin_circuit_t circ)
static

Return true iff the given service rendezvous circuit circ is allowed for a relaunch to the rendezvous point.

Definition at line 453 of file hs_circuit.c.

Referenced by hs_circ_retry_service_rendezvous_point().

◆ circuit_purpose_is_correct_for_rend()

static int circuit_purpose_is_correct_for_rend ( unsigned int  circ_purpose,
int  is_service_side 
)
static

A circuit is about to become an e2e rendezvous circuit. Check circ_purpose and ensure that it's properly set. Return true iff circuit purpose is properly set, otherwise return false.

Definition at line 66 of file hs_circuit.c.

◆ cleanup_on_close_client_circ()

static void cleanup_on_close_client_circ ( circuit_t circ)
static

Helper: cleanup function for client circuit. This is for every HS version. It is called from hs_circ_cleanup_on_close() entry point.

Definition at line 602 of file hs_circuit.c.

Referenced by hs_circ_cleanup_on_close().

◆ cleanup_on_free_client_circ()

static void cleanup_on_free_client_circ ( circuit_t circ)
static

Helper: cleanup function for client circuit. This is for every HS version. It is called from hs_circ_cleanup_on_free() entry point.

Definition at line 616 of file hs_circuit.c.

Referenced by hs_circ_cleanup_on_free().

◆ compare_rend_request_by_effort_()

static int compare_rend_request_by_effort_ ( const void *  _a,
const void *  _b 
)
static

Return less than 0 if a precedes b, 0 if a equals b and greater than 0 if b precedes a. Note that higher effort is earlier in the pqueue.

Definition at line 630 of file hs_circuit.c.

◆ count_opened_desc_intro_point_circuits()

static unsigned int count_opened_desc_intro_point_circuits ( const hs_service_t service,
const hs_service_descriptor_t desc 
)
static

Return the number of opened introduction circuit for the given circuit that is matching its identity key.

Definition at line 174 of file hs_circuit.c.

Referenced by hs_circ_service_intro_has_opened().

◆ count_service_rp_circuits_pending()

static int count_service_rp_circuits_pending ( hs_service_t service)
static

Count up how many pending outgoing (CIRCUIT_PURPOSE_S_CONNECT_REND) circuits there are for this service. Used in the PoW rate limiting world to decide whether it's time to launch any new ones.

Definition at line 711 of file hs_circuit.c.

◆ create_intro_circuit_identifier()

static hs_ident_circuit_t * create_intro_circuit_identifier ( const hs_service_t service,
const hs_service_intro_point_t ip 
)
static

From a given service and service intro point, create an introduction point circuit identifier. This can't fail.

Definition at line 245 of file hs_circuit.c.

◆ create_rend_cpath()

static crypt_path_t * create_rend_cpath ( const uint8_t *  ntor_key_seed,
size_t  seed_len,
int  is_service_side 
)
static

Create and return a crypt path for the final hop of a v3 prop224 rendezvous circuit. Initialize the crypt path crypto using the output material from the ntor key exchange at ntor_key_seed.

If is_service_side is set, we are the hidden service and the final hop of the rendezvous circuit is the client on the other side.

Definition at line 96 of file hs_circuit.c.

◆ create_rp_circuit_identifier()

STATIC hs_ident_circuit_t * create_rp_circuit_identifier ( const hs_service_t service,
const uint8_t *  rendezvous_cookie,
const curve25519_public_key_t server_pk,
const hs_ntor_rend_cell_keys_t keys 
)

From a given service, rendezvous cookie and handshake info, create a rendezvous point circuit identifier. This can't fail.

Definition at line 206 of file hs_circuit.c.

◆ enqueue_rend_request()

static int enqueue_rend_request ( const hs_service_t service,
hs_service_intro_point_t ip,
hs_cell_introduce2_data_t data,
time_t  now 
)
static

Given the information needed to launch a rendezvous circuit and an effort value, enqueue the rendezvous request in the service's PoW priority queue with the effort being the priority.

Return 0 if we successfully enqueued the request else -1.

Definition at line 861 of file hs_circuit.c.

◆ finalize_rend_circuit()

static void finalize_rend_circuit ( origin_circuit_t circ,
crypt_path_t hop,
int  is_service_side 
)
static

Append the final hop to the cpath of the rend circ, and mark circ ready for use to transfer HS relay cells.

Definition at line 126 of file hs_circuit.c.

◆ free_pending_rend()

static void free_pending_rend ( pending_rend_t req)
inlinestatic

Helper: Free a pending rend object.

Definition at line 52 of file hs_circuit.c.

◆ get_service_anonymity_string()

static const char * get_service_anonymity_string ( const hs_service_t service)
static

Return a string constant describing the anonymity of service.

Definition at line 312 of file hs_circuit.c.

◆ get_subcredential_for_handling_intro2_cell()

static int get_subcredential_for_handling_intro2_cell ( const hs_service_t service,
hs_cell_introduce2_data_t data,
const hs_subcredential_t desc_subcred 
)
static

Go into data and add the right subcredential to be able to handle this incoming cell.

desc_subcred is the subcredential of the descriptor that corresponds to the intro point that received this intro request. This subcredential should be used if we are not an onionbalance instance.

Return 0 if everything went well, or -1 in case of internal error.

Definition at line 1272 of file hs_circuit.c.

Referenced by hs_circ_handle_introduce2().

◆ handle_rend_pqueue_cb()

static void handle_rend_pqueue_cb ( mainloop_event_t ev,
void *  arg 
)
static

Definition at line 764 of file hs_circuit.c.

◆ hs_circ_cleanup_on_close()

void hs_circ_cleanup_on_close ( circuit_t circ)

Circuit cleanup strategy:

What follows is a series of functions that notifies the HS subsystem of 3 different circuit cleanup phase: close, free and repurpose.

Tor can call any of those in any orders so they have to be safe between each other. In other words, the free should never depend on close to be called before.

The "on_close()" is called from circuit_mark_for_close() which is considered the tor fast path and thus as little work as possible should done in that function. Currently, we only remove the circuit from the HS circuit map and move on.

The "on_free()" is called from circuit circuit_free_() and it is very important that at the end of the function, no state or objects related to this circuit remains alive.

The "on_repurpose()" is called from circuit_change_purpose() for which we simply remove it from the HS circuit map. We do not have other cleanup requirements after that.

NOTE: The onion service code, specifically the service code, cleans up lingering objects or state if any of its circuit disappear which is why our cleanup strategy doesn't involve any service specific actions. As long as the circuit is removed from the HS circuit map, it won't be used. We are about to close this circ. Clean it up from any related HS data structures. This function can be called multiple times safely for the same circuit.

Definition at line 1605 of file hs_circuit.c.

◆ hs_circ_cleanup_on_free()

void hs_circ_cleanup_on_free ( circuit_t circ)

We are about to free this circ. Clean it up from any related HS data structures. This function can be called multiple times safely for the same circuit.

Definition at line 1631 of file hs_circuit.c.

Referenced by circuit_free_().

◆ hs_circ_cleanup_on_repurpose()

void hs_circ_cleanup_on_repurpose ( circuit_t circ)

We are about to repurpose this circ. Clean it up from any related HS data structures. This function can be called multiple times safely for the same circuit.

Definition at line 1652 of file hs_circuit.c.

◆ hs_circ_handle_intro_established()

int hs_circ_handle_intro_established ( const hs_service_t service,
const hs_service_intro_point_t ip,
origin_circuit_t circ,
const uint8_t *  payload,
size_t  payload_len 
)

Circ has been expecting an INTRO_ESTABLISHED cell that just arrived. Handle the INTRO_ESTABLISHED cell payload of length payload_len arriving on the given introduction circuit circ. The service is only used for logging purposes. Return 0 on success else a negative value.

Definition at line 1223 of file hs_circuit.c.

◆ hs_circ_handle_introduce2()

int hs_circ_handle_introduce2 ( const hs_service_t service,
const origin_circuit_t circ,
hs_service_intro_point_t ip,
const hs_subcredential_t subcredential,
const uint8_t *  payload,
size_t  payload_len 
)

We just received an INTRODUCE2 cell on the established introduction circuit circ. Handle the INTRODUCE2 payload of size payload_len for the given circuit and service. This cell is associated with the intro point object ip and the subcredential. Return 0 on success else a negative value.

Definition at line 1302 of file hs_circuit.c.

◆ hs_circ_is_rend_sent_in_intro1()

bool hs_circ_is_rend_sent_in_intro1 ( const origin_circuit_t circ)

Return true iff the given established client rendezvous circuit was sent into the INTRODUCE1 cell. This is called so we can take a decision on expiring or not the circuit.

The caller MUST make sure the circuit is an established client rendezvous circuit (purpose: CIRCUIT_PURPOSE_C_REND_READY).

This function supports all onion service versions.

Definition at line 1685 of file hs_circuit.c.

◆ hs_circ_launch_intro_point()

int hs_circ_launch_intro_point ( hs_service_t service,
const hs_service_intro_point_t ip,
extend_info_t ei,
bool  direct_conn 
)

For a given service and a service intro point, launch a circuit to the extend info ei. If the service is a single onion, and direct_conn is true, a one-hop circuit will be requested.

Return 0 if the circuit was successfully launched and tagged with the correct identifier. On error, a negative value is returned.

Definition at line 1025 of file hs_circuit.c.

◆ hs_circ_retry_service_rendezvous_point()

void hs_circ_retry_service_rendezvous_point ( const origin_circuit_t circ)

Called when we fail building a rendezvous circuit at some point other than the last hop: launches a new circuit to the same rendezvous point.

We currently relaunch connections to rendezvous points if:

  • A rendezvous circuit timed out before connecting to RP.
  • The rendezvous circuit failed to connect to the RP.

We avoid relaunching a connection to this rendezvous point if:

  • We have already tried MAX_REND_FAILURES times to connect to this RP,
  • We've been trying to connect to this RP for more than MAX_REND_TIMEOUT seconds, or
  • We've already retried this specific rendezvous circuit.

Definition at line 999 of file hs_circuit.c.

Referenced by hs_circ_cleanup_on_repurpose().

◆ hs_circ_send_establish_rendezvous()

int hs_circ_send_establish_rendezvous ( origin_circuit_t circ)

Send an ESTABLISH_RENDEZVOUS cell along the rendezvous circuit circ. On success, 0 is returned else -1 and the circuit is marked for close.

Definition at line 1525 of file hs_circuit.c.

◆ hs_circ_send_introduce1()

int hs_circ_send_introduce1 ( origin_circuit_t intro_circ,
origin_circuit_t rend_circ,
const hs_desc_intro_point_t ip,
const hs_subcredential_t subcredential,
const hs_pow_solution_t pow_solution 
)

Given the introduction circuit intro_circ, the rendezvous circuit rend_circ, a descriptor intro point object ip and the service's subcredential, send an INTRODUCE1 cell on intro_circ.

This will also setup the circuit identifier on rend_circ containing the key material for the handshake and e2e encryption. Return 0 on success else negative value. Because relay_send_command_from_edge() closes the circuit on error, it is possible that intro_circ is closed on error.

Definition at line 1436 of file hs_circuit.c.

Referenced by send_introduce1().

◆ hs_circ_service_get_established_intro_circ()

origin_circuit_t * hs_circ_service_get_established_intro_circ ( const hs_service_intro_point_t ip)

Return an introduction point established circuit matching the given intro point object. The circuit purpose has to be CIRCUIT_PURPOSE_S_INTRO. NULL is returned is no such circuit can be found.

Definition at line 972 of file hs_circuit.c.

◆ hs_circ_service_get_intro_circ()

origin_circuit_t * hs_circ_service_get_intro_circ ( const hs_service_intro_point_t ip)

Return an introduction point circuit matching the given intro point object. NULL is returned is no such circuit can be found.

Definition at line 961 of file hs_circuit.c.

Referenced by should_remove_intro_point().

◆ hs_circ_service_intro_has_opened()

int hs_circ_service_intro_has_opened ( hs_service_t service,
hs_service_intro_point_t ip,
const hs_service_descriptor_t desc,
origin_circuit_t circ 
)

Called when a service introduction point circuit is done building. Given the service and intro point object, this function will send the ESTABLISH_INTRO cell on the circuit. Return 0 on success. Return 1 if the circuit has been repurposed to General because we already have too many opened.

Definition at line 1083 of file hs_circuit.c.

◆ hs_circ_service_rp_has_opened()

void hs_circ_service_rp_has_opened ( const hs_service_t service,
origin_circuit_t circ 
)

Called when a service rendezvous point circuit is done building. Given the service and the circuit, this function will send a RENDEZVOUS1 cell on the circuit using the information in the circuit identifier. If the cell can't be sent, the circuit is closed.

Definition at line 1151 of file hs_circuit.c.

◆ hs_circ_setup_congestion_control()

void hs_circ_setup_congestion_control ( origin_circuit_t origin_circ,
uint8_t  sendme_inc,
bool  is_single_onion 
)

Setup on the given circuit congestion control with the given parameters.

This function assumes that congestion control is enabled on the network and so it is the caller responsability to make sure of it.

Definition at line 928 of file hs_circuit.c.

Referenced by setup_rendezvous_circ_congestion_control().

◆ hs_circuit_setup_e2e_rend_circ()

int hs_circuit_setup_e2e_rend_circ ( origin_circuit_t circ,
const uint8_t *  ntor_key_seed,
size_t  seed_len,
int  is_service_side 
)

Circuit circ just finished the rend ntor key exchange. Use the key exchange output material at ntor_key_seed and setup circ to serve as a rendezvous end-to-end circuit between the client and the service. If is_service_side is set, then we are the hidden service and the other side is the client.

Return 0 if the operation went well; in case of error return -1.

Definition at line 1405 of file hs_circuit.c.

◆ launch_rendezvous_point_circuit()

STATIC void launch_rendezvous_point_circuit ( const hs_service_t service,
const ed25519_public_key_t ip_auth_pubkey,
const curve25519_keypair_t ip_enc_key_kp,
const hs_cell_intro_rdv_data_t rdv_data,
time_t  now 
)

For a given service, the ntor onion key and a rendezvous cookie, launch a circuit to the rendezvous point specified by the link specifiers. On success, a circuit identifier is attached to the circuit with the needed data. This function will try to open a circuit for a maximum value of MAX_REND_FAILURES then it will give up.

Definition at line 331 of file hs_circuit.c.

◆ queued_rend_request_is_too_old()

static int queued_rend_request_is_too_old ( pending_rend_t req,
time_t  now 
)
static

Return 1 if a request waiting in our service-side pqueue is old enough that we should just discard it rather than trying to respond, or 0 if we still like it. As a heuristic, choose half of the total permitted time interval (so we don't approve trying to respond to requests when we will then give up on them a moment later).

Definition at line 654 of file hs_circuit.c.

◆ register_intro_circ()

static void register_intro_circ ( const hs_service_intro_point_t ip,
origin_circuit_t circ 
)
static

For a given circuit and a service introduction point object, register the intro circuit to the circuitmap.

Definition at line 161 of file hs_circuit.c.

◆ rend_pqueue_clear()

void rend_pqueue_clear ( hs_pow_service_state_t pow_state)

Abandon and free all pending rend requests, leaving the pqueue empty.

Definition at line 748 of file hs_circuit.c.

Referenced by hs_pow_free_service_state().

◆ retry_service_rendezvous_point()

static void retry_service_rendezvous_point ( const origin_circuit_t circ)
static

Retry the rendezvous point of circ by launching a new circuit to it.

Definition at line 489 of file hs_circuit.c.

Referenced by hs_circ_retry_service_rendezvous_point().

◆ send_establish_intro()

static void send_establish_intro ( const hs_service_t service,
hs_service_intro_point_t ip,
origin_circuit_t circ 
)
static

For a given introduction point and an introduction circuit, send the ESTABLISH_INTRO cell. The service object is used for logging. This can fail and if so, the circuit is closed and the intro point object is flagged that the circuit is not established anymore which is important for the retry mechanism.

Definition at line 266 of file hs_circuit.c.

◆ setup_introduce1_data()

static int setup_introduce1_data ( const hs_desc_intro_point_t ip,
const node_t rp_node,
const hs_subcredential_t subcredential,
hs_cell_introduce1_data_t intro1_data 
)
static

Using the given descriptor intro point ip, the node of the rendezvous point rp_node and the service's subcredential, populate the already allocated intro1_data object with the needed key material and link specifiers.

Return 0 on success or a negative value if we couldn't properly filled the introduce1 data from the RP node. In other word, it means the RP node is unusable to use in the introduction.

Definition at line 558 of file hs_circuit.c.

◆ top_of_rend_pqueue_is_worthwhile()

int top_of_rend_pqueue_is_worthwhile ( hs_pow_service_state_t pow_state)

Peek at the top entry on the pending rend pqueue, which must not be empty. If its level of effort is at least what we're suggesting for that service right now, return 1, else return 0.

Definition at line 732 of file hs_circuit.c.

◆ trim_rend_pqueue()

static void trim_rend_pqueue ( hs_pow_service_state_t pow_state,
time_t  now 
)
static

Our rendezvous request priority queue is too full; keep the first pqueue_high_level/2 entries and discard the rest.

Definition at line 665 of file hs_circuit.c.