Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an optional flag to export circuit id per port #2136

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions doc/man/tor.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3421,7 +3421,7 @@ The next section describes the per service options that can only be set
Number of introduction points the hidden service will have. You can't
have more than 20. (Default: 3)

[[HiddenServicePort]] **HiddenServicePort** __VIRTPORT__ [__TARGET__]::
[[HiddenServicePort]] **HiddenServicePort** __VIRTPORT__ [__TARGET__ [__EXPORT-CIRCUIT-ID-PROTOCOL__]]::
Configure a virtual port VIRTPORT for a hidden service. You may use this
option multiple times; each time applies to the service using the most
recent HiddenServiceDir. By default, this option maps the virtual port to
Expand All @@ -3431,7 +3431,13 @@ The next section describes the per service options that can only be set
paths may be quoted, and may use standard C escapes.)
You may also have multiple lines with the same VIRTPORT: when a user
connects to that VIRTPORT, one of the TARGETs from those lines will be
chosen at random. Note that address-port pairs have to be comma-separated.
chosen at random. Note that address-port pairs have to be
comma-separated. +
+
You also may specify the export circuit id protocol which is similar to
the one specified in **HiddenServiceExportCircuitID** but the procool
will be applied only to this port instead of being applied globally
in the service.

[[HiddenServiceVersion]] **HiddenServiceVersion** **3**::
A list of rendezvous service descriptor versions to publish for the hidden
Expand Down
12 changes: 5 additions & 7 deletions src/core/or/connection_edge.c
Original file line number Diff line number Diff line change
Expand Up @@ -936,7 +936,7 @@ connected_cell_format_payload(uint8_t *payload_out,

/* This is an onion service client connection: Export the client circuit ID
* according to the HAProxy proxy protocol. */
STATIC void
static void
export_hs_client_circuit_id(edge_connection_t *edge_conn,
hs_circuit_id_protocol_t protocol)
{
Expand Down Expand Up @@ -3810,7 +3810,7 @@ begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
* connection, attach it to the circ and connect it. Return 0 on success
* or END_CIRC_AT_ORIGIN if we can't find the requested hidden service port
* where the caller should close the circuit. */
static int
STATIC int
handle_hs_exit_conn(circuit_t *circ, edge_connection_t *conn)
{
int ret;
Expand Down Expand Up @@ -3881,9 +3881,7 @@ handle_hs_exit_conn(circuit_t *circ, edge_connection_t *conn)
/* If it's an onion service connection, we might want to include the proxy
* protocol header: */
if (conn->hs_ident) {
hs_circuit_id_protocol_t circuit_id_protocol =
hs_service_exports_circuit_id(&conn->hs_ident->identity_pk);
export_hs_client_circuit_id(conn, circuit_id_protocol);
export_hs_client_circuit_id(conn, conn->hs_ident->circuit_id_protocol);
}

/* Connect tor to the hidden service destination. */
Expand Down Expand Up @@ -4187,8 +4185,8 @@ network_reentry_is_allowed(void)
* address, but <em>only</em> if it's a general exit stream. (Rendezvous
* streams must not reveal what IP they connected to.)
*/
void
connection_exit_connect(edge_connection_t *edge_conn)
MOCK_IMPL(void,
connection_exit_connect,(edge_connection_t *edge_conn))
{
const tor_addr_t *addr;
uint16_t port;
Expand Down
5 changes: 2 additions & 3 deletions src/core/or/connection_edge.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ void connection_ap_handshake_socks_resolved_addr(entry_connection_t *conn,

int connection_exit_begin_conn(cell_t *cell, circuit_t *circ);
int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ);
void connection_exit_connect(edge_connection_t *conn);
MOCK_DECL(void,connection_exit_connect,(edge_connection_t *conn));
int connection_edge_is_rendezvous_stream(const edge_connection_t *conn);
int connection_ap_can_use_exit(const entry_connection_t *conn,
const node_t *exit);
Expand Down Expand Up @@ -290,8 +290,7 @@ STATIC void connection_ap_handshake_rewrite(entry_connection_t *conn,
rewrite_result_t *out);

STATIC int connection_ap_process_http_connect(entry_connection_t *conn);
STATIC void export_hs_client_circuit_id(edge_connection_t *edge_conn,
hs_circuit_id_protocol_t protocol);
STATIC int handle_hs_exit_conn(circuit_t *circ, edge_connection_t *conn);

struct half_edge_t;
STATIC void connection_half_edge_add(const edge_connection_t *conn,
Expand Down
51 changes: 44 additions & 7 deletions src/feature/hs/hs_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,8 @@ hs_set_conn_addr_port(const smartlist_t *ports, edge_connection_t *conn)
/* There is always a connection identifier at this point. Regardless of a
* Unix or TCP port, note the virtual port. */
conn->hs_ident->orig_virtual_port = chosen_port->virtual_port;
/* Note the export circuit id protocol to the connection. */
conn->hs_ident->circuit_id_protocol = chosen_port->circuit_id_protocol;
}

if (!(chosen_port->is_unix_addr)) {
Expand Down Expand Up @@ -677,7 +679,8 @@ hs_port_config_new(const char *socket_path)
* the provided separator and returns a new hs_port_config_t,
* or NULL and an optional error string on failure.
*
* The format is: VirtualPort SEP (IP|RealPort|IP:RealPort|'socket':path)?
* The format is: VirtualPort SEP ((IP|RealPort|IP:RealPort|'socket':path)
* SEP (ExportCircuitIdProtocol)?)?
*
* IP defaults to 127.0.0.1; RealPort defaults to VirtualPort.
*/
Expand All @@ -691,6 +694,7 @@ hs_parse_port_config(const char *string, const char *sep,
uint16_t p;
tor_addr_t addr;
hs_port_config_t *result = NULL;
hs_circuit_id_protocol_t circuit_id_protocol = HS_CIRCUIT_ID_PROTOCOL_NONE;
unsigned int is_unix_addr = 0;
const char *socket_path = NULL;
char *err_msg = NULL;
Expand Down Expand Up @@ -729,12 +733,6 @@ hs_parse_port_config(const char *string, const char *sep,
goto err;
}

if (rest && strlen(rest)) {
err_msg = tor_strdup("HiddenServicePort parse error: invalid port "
"mapping");
goto err;
}

if (is_unix) {
socket_path = addrport;
is_unix_addr = 1;
Expand All @@ -757,12 +755,24 @@ hs_parse_port_config(const char *string, const char *sep,
}
tor_addr_from_ipv4h(&addr, 0x7F000001u); /* Default to 127.0.0.1 */
}

if (rest && strlen(rest)) {
int ok;
circuit_id_protocol =
hs_parse_circuit_id_protocol(rest, &ok);
if (!ok) {
err_msg = tor_strdup("HiddenServicePort parse error: export circuit "
"id protocol must be 'haproxy' or 'none'.");
goto err;
}
}
}

/* Allow room for unix_addr */
result = hs_port_config_new(socket_path);
result->virtual_port = virtport;
result->is_unix_addr = is_unix_addr;
result->circuit_id_protocol = circuit_id_protocol;
if (!is_unix_addr) {
result->real_port = realport;
tor_addr_copy(&result->real_addr, &addr);
Expand All @@ -782,6 +792,33 @@ hs_parse_port_config(const char *string, const char *sep,
return result;
}

/** Given a configuration string, parse the value as a
* hs_circuit_id_protocol_t. On success, ok is set to 1 and ret is
* the parse value. On error, ok is set to 0 and the "none"
* hs_circuit_id_protocol_t is returned. */
hs_circuit_id_protocol_t
hs_parse_circuit_id_protocol(const char *protocol_str, int *ok)
{
tor_assert(protocol_str);
tor_assert(ok);

hs_circuit_id_protocol_t ret = HS_CIRCUIT_ID_PROTOCOL_NONE;
*ok = 0;

if (! strcasecmp(protocol_str, "haproxy")) {
*ok = 1;
ret = HS_CIRCUIT_ID_PROTOCOL_HAPROXY;
} else if (! strcasecmp(protocol_str, "none")) {
*ok = 1;
ret = HS_CIRCUIT_ID_PROTOCOL_NONE;
} else {
goto err;
}

err:
return ret;
}

/** Release all storage held in a hs_port_config_t. */
void
hs_port_config_free_(hs_port_config_t *p)
Expand Down
13 changes: 13 additions & 0 deletions src/feature/hs/hs_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,15 @@ typedef enum {
RSAE_OKAY = 0 /**< Service added as expected */
} hs_service_add_ephemeral_status_t;

/** Which protocol to use for exporting HS client circuit ID. */
typedef enum {
/** Don't expose the circuit id. */
HS_CIRCUIT_ID_PROTOCOL_NONE,

/** Use the HAProxy proxy protocol. */
HS_CIRCUIT_ID_PROTOCOL_HAPROXY
} hs_circuit_id_protocol_t;

/** Represents the mapping from a virtual port of a rendezvous service to a
* real port on some IP. */
typedef struct hs_port_config_t {
Expand All @@ -156,6 +165,8 @@ typedef struct hs_port_config_t {
uint16_t real_port;
/** The outgoing IPv4 or IPv6 address to use, if !is_unix_addr */
tor_addr_t real_addr;
/** Does this port export the circuit ID of its clients? */
hs_circuit_id_protocol_t circuit_id_protocol;
/** The socket path to connect to, if is_unix_addr */
char unix_addr[FLEXIBLE_ARRAY_MEMBER];
} hs_port_config_t;
Expand Down Expand Up @@ -241,6 +252,8 @@ void hs_purge_last_hid_serv_requests(void);
int hs_set_conn_addr_port(const smartlist_t *ports, edge_connection_t *conn);
hs_port_config_t *hs_parse_port_config(const char *string, const char *sep,
char **err_msg_out);
hs_circuit_id_protocol_t hs_parse_circuit_id_protocol(const char *protocol_str,
int *ok);
void hs_port_config_free_(hs_port_config_t *p);
#define hs_port_config_free(p) \
FREE_AND_NULL(hs_port_config_t, hs_port_config_free_, (p))
Expand Down
34 changes: 3 additions & 31 deletions src/feature/hs/hs_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,34 +177,6 @@ check_value_oob(int i, const char *name, int low, int high)
#define CHECK_OOB(opts, name, low, high) \
check_value_oob((opts)->name, #name, (low), (high))

/** Helper function: Given a configuration option and its value, parse the
* value as a hs_circuit_id_protocol_t. On success, ok is set to 1 and ret is
* the parse value. On error, ok is set to 0 and the "none"
* hs_circuit_id_protocol_t is returned. This function logs on error. */
static hs_circuit_id_protocol_t
helper_parse_circuit_id_protocol(const char *key, const char *value, int *ok)
{
tor_assert(value);
tor_assert(ok);

hs_circuit_id_protocol_t ret = HS_CIRCUIT_ID_PROTOCOL_NONE;
*ok = 0;

if (! strcasecmp(value, "haproxy")) {
*ok = 1;
ret = HS_CIRCUIT_ID_PROTOCOL_HAPROXY;
} else if (! strcasecmp(value, "none")) {
*ok = 1;
ret = HS_CIRCUIT_ID_PROTOCOL_NONE;
} else {
log_warn(LD_CONFIG, "%s must be 'haproxy' or 'none'.", key);
goto err;
}

err:
return ret;
}

/** Return the service version by trying to learn it from the key on disk if
* any. If nothing is found, the current service configured version is
* returned. */
Expand Down Expand Up @@ -351,10 +323,10 @@ config_service_v3(const hs_opts_t *hs_opts,
if (hs_opts->HiddenServiceExportCircuitID) {
int ok;
config->circuit_id_protocol =
helper_parse_circuit_id_protocol("HiddenServcieExportCircuitID",
hs_opts->HiddenServiceExportCircuitID,
&ok);
hs_parse_circuit_id_protocol(hs_opts->HiddenServiceExportCircuitID, &ok);
if (!ok) {
log_warn(LD_CONFIG, "HiddenServiceExportCircuitID must be "
"'haproxy' or 'none'.");
goto err;
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/feature/hs/hs_ident.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ typedef struct hs_ident_edge_conn_t {
* service, regardless of the internal port forwarding that might have
* happened on the service-side. */
uint16_t orig_virtual_port;

/** The export circuit id protocol that is used in this connection. */
hs_circuit_id_protocol_t circuit_id_protocol;
/* XXX: Client authorization. */
} hs_ident_edge_conn_t;

Expand Down
19 changes: 6 additions & 13 deletions src/feature/hs/hs_service.c
Original file line number Diff line number Diff line change
Expand Up @@ -3998,6 +3998,12 @@ hs_service_set_conn_addr_port(const origin_circuit_t *circ,
goto err_no_close;
}

/* If the the export circuit id protocol is none, looks at
* the HiddenServiceExportCircuitID config instead. */
if (conn->hs_ident->circuit_id_protocol == HS_CIRCUIT_ID_PROTOCOL_NONE) {
conn->hs_ident->circuit_id_protocol = service->config.circuit_id_protocol;
}

/* Success. */
return 0;
err_close:
Expand All @@ -4008,19 +4014,6 @@ hs_service_set_conn_addr_port(const origin_circuit_t *circ,
return -1;
}

/** Does the service with identity pubkey <b>pk</b> export the circuit IDs of
* its clients? */
hs_circuit_id_protocol_t
hs_service_exports_circuit_id(const ed25519_public_key_t *pk)
{
hs_service_t *service = find_service(hs_service_map, pk);
if (!service) {
return HS_CIRCUIT_ID_PROTOCOL_NONE;
}

return service->config.circuit_id_protocol;
}

/** Add to file_list every filename used by a configured hidden service, and to
* dir_list every directory path used by a configured hidden service. This is
* used by the sandbox subsystem to allowlist those. */
Expand Down
12 changes: 0 additions & 12 deletions src/feature/hs/hs_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,15 +190,6 @@ typedef struct hs_service_authorized_client_t {
curve25519_public_key_t client_pk;
} hs_service_authorized_client_t;

/** Which protocol to use for exporting HS client circuit ID. */
typedef enum {
/** Don't expose the circuit id. */
HS_CIRCUIT_ID_PROTOCOL_NONE,

/** Use the HAProxy proxy protocol. */
HS_CIRCUIT_ID_PROTOCOL_HAPROXY
} hs_circuit_id_protocol_t;

/** Service configuration. The following are set from the torrc options either
* set by the configuration file or by the control port. Nothing else should
* change those values. */
Expand Down Expand Up @@ -380,9 +371,6 @@ void hs_service_upload_desc_to_dir(const char *encoded_desc,
const ed25519_public_key_t *blinded_pk,
const routerstatus_t *hsdir_rs);

hs_circuit_id_protocol_t
hs_service_exports_circuit_id(const ed25519_public_key_t *pk);

void hs_service_dump_stats(int severity);
void hs_service_circuit_cleanup_on_close(const circuit_t *circ);

Expand Down
Loading