tor
master
|
Handle edge streams. More...
#include "or.h"
#include "backtrace.h"
#include "addressmap.h"
#include "buffers.h"
#include "channel.h"
#include "circpathbias.h"
#include "circuitlist.h"
#include "circuituse.h"
#include "config.h"
#include "connection.h"
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
#include "crypto_util.h"
#include "dns.h"
#include "dnsserv.h"
#include "directory.h"
#include "dirserv.h"
#include "hibernate.h"
#include "hs_common.h"
#include "hs_cache.h"
#include "hs_client.h"
#include "hs_circuit.h"
#include "main.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "policies.h"
#include "proto_http.h"
#include "proto_socks.h"
#include "reasons.h"
#include "relay.h"
#include "rendclient.h"
#include "rendcommon.h"
#include "rendservice.h"
#include "rephist.h"
#include "router.h"
#include "routerlist.h"
#include "routerset.h"
#include "circuitbuild.h"
Macros | |
#define | CONNECTION_EDGE_PRIVATE |
#define | SOCKS4_GRANTED 90 |
#define | SOCKS4_REJECT 91 |
#define | WARN_FAILED_HS_CONNECTION 300 |
#define | MAX_CONNECTED_CELL_PAYLOAD_LEN 25 |
#define | UNMARK() |
#define | TRACKHOSTEXITS_RETRIES 5 |
#define | WARN_INTRVL_LOOP 300 |
#define | WARN_INTRVL_PRIV 300 |
Handle edge streams.
An edge_connection_t is a subtype of a connection_t, and represents two critical concepts in Tor: a stream, and an edge connection. From the Tor protocol's point of view, a stream is a bi-directional channel that is multiplexed on a single circuit. Each stream on a circuit is identified with a separate 16-bit stream ID, local to the (circuit,exit) pair. Streams are created in response to client requests.
An edge connection is one thing that can implement a stream: it is either a TCP application socket that has arrived via (e.g.) a SOCKS request, or an exit connection.
Not every instance of edge_connection_t truly represents an edge connction, however. (Sorry!) We also create edge_connection_t objects for streams that we will not be handling with TCP. The types of these streams are:
This module handles general-purpose functionality having to do with edge_connection_t. On the client side, it accepts various types of application requests on SocksPorts, TransPorts, and NATDPorts, and creates streams appropriately.
This module is also responsible for implementing stream isolation: ensuring that streams that should not be linkable to one another are kept to different circuits.
On the exit side, this module handles the various stream-creating type of RELAY cells by launching appropriate outgoing connections, DNS requests, or directory connection objects.
And for all edge connections, this module is responsible for handling incoming and outdoing data as it arrives or leaves in the relay.c module. (Outgoing data will be packaged in connection_edge_process_inbuf() as it calls connection_edge_package_raw_inbuf(); incoming data from RELAY_DATA cells is applied in connection_edge_process_relay_cell().)
#define MAX_CONNECTED_CELL_PAYLOAD_LEN 25 |
Longest size for the relay payload of a RELAY_CONNECTED cell that we're able to generate.
#define TRACKHOSTEXITS_RETRIES 5 |
How many times do we try connecting with an exit configured via TrackHostExits before concluding that it won't work any more and trying a different one?
#define UNMARK | ( | ) |
STATIC int begin_cell_parse | ( | const cell_t * | cell, |
begin_cell_t * | bcell, | ||
uint8_t * | end_reason_out | ||
) |
Read a RELAY_BEGIN or RELAY_BEGIN_DIR cell from cell, decode it, and place the result in bcell. On success return 0; on failure return <0 and set *end_reason_out to the end reason we should send back to the client.
Return -1 in the case where we want to send a RELAY_END cell, and < -1 when we don't.
void circuit_clear_isolation | ( | origin_circuit_t * | circ | ) |
Clear the isolation settings on circ.
This only works on an open circuit that has never had a stream attached to it, and whose isolation settings are hypothetical. (We set hypothetical isolation settings on circuits as we're launching them, so that we know whether they can handle more streams or whether we need to launch even more circuits. Once the circuit is open, if it turns out that we no longer have any streams to attach to it, we clear the isolation flags and data so that other streams can have a chance.)
void circuit_discard_optional_exit_enclaves | ( | extend_info_t * | info | ) |
A circuit failed to finish on its last hop info. If there are any streams waiting with this exit node in mind, but they don't absolutely require it, make them give up on it.
STATIC int connected_cell_format_payload | ( | uint8_t * | payload_out, |
const tor_addr_t * | addr, | ||
uint32_t | ttl | ||
) |
Set the buffer at payload_out – which must have at least MAX_CONNECTED_CELL_PAYLOAD_LEN bytes available – to the body of a RELAY_CONNECTED cell indicating that we have connected to addr, and that the name resolution that led us to addr will be valid for ttl seconds. Return -1 on error, or the number of bytes used on success.
void connection_ap_about_to_close | ( | entry_connection_t * | entry_conn | ) |
Called when we're about to finally unlink and free an AP (client) connection: perform necessary accounting and cleanup
void connection_ap_attach_pending | ( | int | retry | ) |
Tell any AP streams that are listed as waiting for a new circuit to try again. If there is an available circuit for a stream, attach it. Otherwise, launch a new circuit.
If retry is false, only check the list if it contains at least one streams that we have not yet tried to attach to a circuit.
int connection_ap_can_use_exit | ( | const entry_connection_t * | conn, |
const node_t * | exit_node | ||
) |
Return 1 if router exit_node is likely to allow stream conn to exit from it, or 0 if it probably will not allow it. (We might be uncertain if conn's destination address has not yet been resolved.)
int connection_ap_detach_retriable | ( | entry_connection_t * | conn, |
origin_circuit_t * | circ, | ||
int | reason | ||
) |
The AP connection conn has just failed while attaching or sending a BEGIN or resolving on circ, but another circuit might work. Detach the circuit, and either reattach it, launch a new circuit, tell the controller, or give up as appropriate.
Returns -1 on err, 1 on success, 0 on not-yet-sure.
void connection_ap_expire_beginning | ( | void | ) |
Find all general-purpose AP streams waiting for a response that sent their begin/resolve cell too long ago. Detach from their current circuit, and mark their current circuit as unsuitable for new streams. Then call connection_ap_handshake_attach_circuit() to attach to a new circuit (if available) or launch a new one.
For rendezvous streams, simply give up after SocksTimeout seconds (with no retry attempt).
void connection_ap_fail_onehop | ( | const char * | failed_digest, |
cpath_build_state_t * | build_state | ||
) |
Tell any AP streams that are waiting for a one-hop tunnel to failed_digest that they are going to fail.
int connection_ap_handshake_rewrite_and_attach | ( | entry_connection_t * | conn, |
origin_circuit_t * | circ, | ||
crypt_path_t * | cpath | ||
) |
Connection conn just finished its socks handshake, or the controller asked us to take care of it. If circ is defined, then that's where we'll want to attach it. Otherwise we have to figure it out ourselves.
First, parse whether it's a .exit address, remap it, and so on. Then if it's for a general circuit, try to attach it to a circuit (or launch one as needed), else if it's for a rendezvous circuit, fetch a rendezvous descriptor first (or attach/launch a circuit if the rendezvous descriptor is already here and fresh enough).
The stream will exit from the hop indicated by cpath, or from the last hop in circ's cpath if cpath is NULL.
int connection_ap_handshake_send_resolve | ( | entry_connection_t * | ap_conn | ) |
Write a relay resolve cell, using destaddr and destport from ap_conn's socks_request field, and send it down circ.
If ap_conn is broken, mark it for close and return -1. Else return 0.
void connection_ap_handshake_socks_reply | ( | entry_connection_t * | conn, |
char * | reply, | ||
size_t | replylen, | ||
int | endreason | ||
) |
Send a socks reply to stream conn, using the appropriate socks version, etc, and mark conn as completed with SOCKS handshaking.
If reply is defined, then write replylen bytes of it to conn and return, else reply based on endreason (one of END_STREAM_REASON_*). If reply is undefined, endreason can't be 0 or REASON_DONE. Send endreason to the controller, if appropriate.
void connection_ap_handshake_socks_resolved_addr | ( | entry_connection_t * | conn, |
const tor_addr_t * | answer, | ||
int | ttl, | ||
time_t | expires | ||
) |
As connection_ap_handshake_socks_resolved, but take a tor_addr_t to send as the answer.
entry_connection_t* connection_ap_make_link | ( | connection_t * | partner, |
char * | address, | ||
uint16_t | port, | ||
const char * | digest, | ||
int | session_group, | ||
int | isolation_flags, | ||
int | use_begindir, | ||
int | want_onehop | ||
) |
Make an AP connection_t linked to the connection_t partner. make a new linked connection pair, and attach one side to the conn, connection_add it, initialize it to circuit_wait, and call connection_ap_handshake_attach_circuit(conn) on it.
Return the newly created end of the linked connection pair, or -1 if error.
void connection_ap_mark_as_non_pending_circuit | ( | entry_connection_t * | entry_conn | ) |
Mark entry_conn as no longer waiting for a circuit.
void connection_ap_mark_as_pending_circuit_ | ( | entry_connection_t * | entry_conn, |
const char * | fname, | ||
int | lineno | ||
) |
Mark entry_conn as needing to get attached to a circuit.
And entry_conn must be in AP_CONN_STATE_CIRCUIT_WAIT, should not already be pending a circuit. The circuit will get launched or the connection will get attached the next time we call connection_ap_attach_pending().
STATIC int connection_ap_process_http_connect | ( | entry_connection_t * | conn | ) |
Called on an HTTP CONNECT entry connection when some bytes have arrived, but we have not yet received a full HTTP CONNECT request. Try to parse an HTTP CONNECT request from the connection's inbuf. On success, set up the connection's socks_request field and try to attach the connection. On failure, send an HTTP reply, and mark the connection.
int connection_ap_process_transparent | ( | entry_connection_t * | conn | ) |
connection_init_accepted_conn() found a new trans AP conn. Get the original destination and send it to connection_ap_handshake_rewrite_and_attach().
Return -1 if an unexpected error with conn (and it should be marked for close), else return 0.
void connection_ap_rescan_and_attach_pending | ( | void | ) |
As connection_ap_attach_pending, but first scans the entire connection array to see if any elements are missing.
int connection_edge_compatible_with_circuit | ( | const entry_connection_t * | conn, |
const origin_circuit_t * | circ | ||
) |
Return true iff none of the isolation flags and fields in conn should prevent it from being attached to circ.
int connection_edge_destroy | ( | circid_t | circ_id, |
edge_connection_t * | conn | ||
) |
This edge needs to be closed, because its circuit has closed. Mark it for close and return 0.
int connection_edge_end | ( | edge_connection_t * | conn, |
uint8_t | reason | ||
) |
Send a relay end cell from stream conn down conn's circuit, and remember that we've done so. If this is not a client connection, set the relay end cell's reason for closing as reason.
Return -1 if this function has already been called on this conn, else return 0.
int connection_edge_end_errno | ( | edge_connection_t * | conn | ) |
An error has just occurred on an operation on an edge connection conn. Extract the errno; convert it to an end reason, and send an appropriate relay end cell to the other end of the connection's circuit.
int connection_edge_finished_connecting | ( | edge_connection_t * | edge_conn | ) |
Connected handler for exit connections: start writing pending data, deliver 'CONNECTED' relay cells as appropriate, and check any pending data that may have been received.
int connection_edge_finished_flushing | ( | edge_connection_t * | conn | ) |
Connection conn has finished writing and has no bytes left on its outbuf.
If it's in state 'open', stop writing, consider responding with a sendme, and return. Otherwise, stop writing and return.
If conn is broken, mark it for close and return -1, else return 0.
int connection_edge_flushed_some | ( | edge_connection_t * | conn | ) |
We just wrote some data to conn; act appropriately.
(That is, if it's open, consider sending a stream-level sendme cell if we have just flushed enough.)
void connection_edge_free_all | ( | void | ) |
Free all storage held in module-scoped variables for connection_edge.c
int connection_edge_is_rendezvous_stream | ( | const edge_connection_t * | conn | ) |
Return 1 if conn is a rendezvous stream, or 0 if it is a general stream.
int connection_edge_process_inbuf | ( | edge_connection_t * | conn, |
int | package_partial | ||
) |
Handle new bytes on conn->inbuf based on state:
Mark and return -1 if there was an unexpected error with the conn, else return 0.
int connection_edge_reached_eof | ( | edge_connection_t * | conn | ) |
There was an EOF. Send an end and mark the connection for close.
int connection_edge_update_circuit_isolation | ( | const entry_connection_t * | conn, |
origin_circuit_t * | circ, | ||
int | dry_run | ||
) |
If dry_run is false, update circ's isolation flags and fields to reflect having had conn attached to it, and return 0. Otherwise, if dry_run is true, then make no changes to circ, and return a bitfield of isolation flags that we would have to set in isolation_flags_mixed to add conn to circ, or -1 if circ has had no streams attached to it.
void connection_exit_about_to_close | ( | edge_connection_t * | edge_conn | ) |
Called when we're about to finally unlink and free an exit connection: perform necessary accounting and cleanup
A relay 'begin' or 'begin_dir' cell has arrived, and either we are an exit hop for the circuit, or we are the origin and it is a rendezvous begin.
Launch a new exit connection and initialize things appropriately.
If it's a rendezvous stream, call connection_exit_connect() on it.
For general streams, call dns_resolve() on it first, and only call connection_exit_connect() if the dns answer is already known.
Note that we don't call connection_add() on the new stream! We wait for connection_exit_connect() to do that.
Return -(some circuit end reason) if we want to tear down circ. Else return 0.
int connection_exit_begin_resolve | ( | cell_t * | cell, |
or_circuit_t * | circ | ||
) |
Called when we receive a RELAY_COMMAND_RESOLVE cell 'cell' along the circuit circ; begin resolving the hostname, and (eventually) reply with a RESOLVED cell.
void connection_exit_connect | ( | edge_connection_t * | edge_conn | ) |
Connect to conn's specified addr and port. If it worked, conn has now been added to the connection_array.
Send back a connected cell. Include the resolved IP of the destination address, but only if it's a general exit stream. (Rendezvous streams must not reveal what IP they connected to.)
streamid_t get_unique_stream_id_by_circ | ( | origin_circuit_t * | circ | ) |
Iterate over the two bytes of stream_id until we get one that is not already in use; return it. Return 0 if can't get a unique stream_id.
MOCK_IMPL | ( | void | , |
connection_mark_unattached_ap_ | , | ||
(entry_connection_t *conn, int endreason, int line, const char *file) | |||
) |
An AP stream has failed/finished. If it hasn't already sent back a socks reply, send one now (based on endreason). Also set has_sent_end to 1, and mark the conn.
MOCK_IMPL | ( | int | , |
connection_ap_rewrite_and_attach_if_allowed | , | ||
(entry_connection_t *conn, origin_circuit_t *circ, crypt_path_t *cpath) | |||
) |
Call connection_ap_handshake_rewrite_and_attach() unless a controller asked us to leave streams unattached. Return 0 in that case.
See connection_ap_handshake_rewrite_and_attach()'s documentation for arguments and return value.
MOCK_IMPL | ( | int | , |
connection_ap_handshake_send_begin | , | ||
(entry_connection_t *ap_conn) | |||
) |
Write a relay begin cell, using destaddr and destport from ap_conn's socks_request field, and send it down circ.
If ap_conn is broken, mark it for close and return -1. Else return 0.
MOCK_IMPL | ( | void | , |
connection_ap_handshake_socks_resolved | , | ||
(entry_connection_t *conn, int answer_type, size_t answer_len, const uint8_t *answer, int ttl, time_t expires) | |||
) |
Send an answer to an AP connection that has requested a DNS lookup via SOCKS. The type should be one of RESOLVED_TYPE_(IPV4|IPV6|HOSTNAME) or -1 for unreachable; the answer should be in the format specified in the socks extensions document. ttl is the ttl for the answer, or -1 on certain errors or for values that didn't come via DNS. expires is a time when the answer expires, or -1 or TIME_MAX if there's a good TTL.
hostname_type_t parse_extended_hostname | ( | char * | address | ) |
If address is of the form "y.onion" with a well-formed handle y: Put a NUL after y, lower-case it, and return ONION_V2_HOSTNAME or ONION_V3_HOSTNAME depending on the HS version.
If address is of the form "x.y.onion" with a well-formed handle x: Drop "x.", put a NUL after y, lower-case it, and return ONION_V2_HOSTNAME or ONION_V3_HOSTNAME depending on the HS version.
If address is of the form "y.onion" with a badly-formed handle y: Return BAD_HOSTNAME and log a message.
If address is of the form "y.exit": Put a NUL after y and return EXIT_HOSTNAME.
Otherwise: Return NORMAL_HOSTNAME and change nothing.