Change HiddenServiceExportCircuitID to take a string parameter: the protocol.

This patch changes HiddenServiceExportCircuitID so instead of being a
boolean it takes a string, which is the protocol. Currently only the
'haproxy' protocol is defined.

See: https://bugs.torproject.org/4700
This commit is contained in:
Alexander Færøy 2018-09-15 16:33:31 +03:00 committed by George Kadianakis
parent 8f085841ef
commit 9b511dc5d6
7 changed files with 77 additions and 27 deletions

View File

@ -2835,10 +2835,10 @@ The following options are used to configure a hidden service.
not an authorization mechanism; it is instead meant to be a mild
inconvenience to port-scanners.) (Default: 0)
[[HiddenServiceExportCircuitID]] **HiddenServiceExportCircuitID** **0**|**1**::
If set to 1, then the onion service will use the HAProxy proxy protocol to
assign a unique IPv6 address (in an unused IPv6 range) to each inbound
client circuit. (Default: 0)
[[HiddenServiceExportCircuitID]] **HiddenServiceExportCircuitID** __protocol__::
The onion service will use the given protocol to expose the global circuit
identifier of each inbound client circuit via the selected protocol. The only
protocol supported right now \'haproxy\'. This option is only for v3 services.
[[HiddenServiceMaxStreams]] **HiddenServiceMaxStreams** __N__::
The maximum number of simultaneous streams (connections) per rendezvous

View File

@ -600,10 +600,15 @@ 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
export_hs_client_circuit_id_haproxy(const edge_connection_t *edge_conn,
connection_t *conn)
export_hs_client_circuit_id(const edge_connection_t *edge_conn,
connection_t *conn,
hs_circuit_id_protocol_t protocol)
{
char *buf;
/* We only support HAProxy right now. */
if (protocol != HS_CIRCUIT_ID_PROTOCOL_HAPROXY)
return;
char *buf = NULL;
const char dst_ipv6[] = "::1";
/* See RFC4193 regarding fc00::/7 */
const char src_ipv6_prefix[] = "fc00:dead:beef:4dad:";
@ -655,10 +660,11 @@ connection_edge_finished_connecting(edge_connection_t *edge_conn)
conn->state = EXIT_CONN_STATE_OPEN;
/* If it's an onion service connection, we might want to include the proxy
* protocol header */
if (edge_conn->hs_ident &&
hs_service_exports_circuit_id(&edge_conn->hs_ident->identity_pk)) {
export_hs_client_circuit_id_haproxy(edge_conn, conn);
* protocol header: */
if (edge_conn->hs_ident) {
hs_circuit_id_protocol_t circuit_id_protocol =
hs_service_exports_circuit_id(&edge_conn->hs_ident->identity_pk);
export_hs_client_circuit_id(edge_conn, conn, circuit_id_protocol);
}
connection_watch_events(conn, READ_EVENT); /* stop writing, keep reading */

View File

@ -14,6 +14,8 @@
#include "lib/testsupport/testsupport.h"
#include "feature/hs/hs_service.h"
edge_connection_t *TO_EDGE_CONN(connection_t *);
entry_connection_t *TO_ENTRY_CONN(connection_t *);
entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *);
@ -244,8 +246,10 @@ STATIC void connection_ap_handshake_rewrite(entry_connection_t *conn,
STATIC int connection_ap_process_http_connect(entry_connection_t *conn);
STATIC void
export_hs_client_circuit_id_haproxy(const edge_connection_t *edge_conn,
connection_t *conn);
export_hs_client_circuit_id(const edge_connection_t *edge_conn,
connection_t *conn,
hs_circuit_id_protocol_t protocol);
#endif /* defined(CONNECTION_EDGE_PRIVATE) */
#endif /* !defined(TOR_CONNECTION_EDGE_H) */

View File

@ -145,6 +145,31 @@ helper_parse_uint64(const char *opt, const char *value, uint64_t min,
return ret;
}
/** 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 {
log_warn(LD_CONFIG, "%s must be 'haproxy'.", 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. */
@ -295,8 +320,8 @@ config_service_v3(const config_line_t *line_,
continue;
}
if (!strcasecmp(line->key, "HiddenServiceExportCircuitID")) {
config->export_circuit_id =
(unsigned int) helper_parse_uint64(line->key, line->value, 0, 1, &ok);
config->circuit_id_protocol =
helper_parse_circuit_id_protocol(line->key, line->value, &ok);
if (!ok || export_circuit_id) {
if (export_circuit_id) {
dup_opt_seen = line->key;

View File

@ -3764,15 +3764,15 @@ hs_service_set_conn_addr_port(const origin_circuit_t *circ,
/** Does the service with identity pubkey <b>pk</b> export the circuit IDs of
* its clients? */
bool
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 0;
return HS_CIRCUIT_ID_PROTOCOL_NONE;
}
return service->config.export_circuit_id;
return service->config.circuit_id_protocol;
}
/* Add to file_list every filename used by a configured hidden service, and to

View File

@ -161,6 +161,15 @@ 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. */
@ -212,7 +221,7 @@ typedef struct hs_service_config_t {
unsigned int is_ephemeral : 1;
/* Does this service export the circuit ID of its clients? */
bool export_circuit_id;
hs_circuit_id_protocol_t circuit_id_protocol;
} hs_service_config_t;
/* Service state. */
@ -319,7 +328,8 @@ void hs_service_upload_desc_to_dir(const char *encoded_desc,
const ed25519_public_key_t *blinded_pk,
const routerstatus_t *hsdir_rs);
bool hs_service_exports_circuit_id(const ed25519_public_key_t *pk);
hs_circuit_id_protocol_t
hs_service_exports_circuit_id(const ed25519_public_key_t *pk);
#ifdef HS_SERVICE_PRIVATE

View File

@ -2025,10 +2025,10 @@ test_export_client_circuit_id(void *arg)
/* Create service */
hs_service_t *service = helper_create_service();
/* Check that export circuit ID detection works */
service->config.export_circuit_id = false;
service->config.circuit_id_protocol = HS_CIRCUIT_ID_PROTOCOL_NONE;
tt_int_op(0, OP_EQ,
hs_service_exports_circuit_id(&service->keys.identity_pk));
service->config.export_circuit_id = true;
service->config.circuit_id_protocol = HS_CIRCUIT_ID_PROTOCOL_HAPROXY;
tt_int_op(1, OP_EQ,
hs_service_exports_circuit_id(&service->keys.identity_pk));
@ -2047,7 +2047,8 @@ test_export_client_circuit_id(void *arg)
or_circ->global_identifier = 666;
/* Export circuit ID */
export_hs_client_circuit_id_haproxy(edge_conn, conn);
export_hs_client_circuit_id(edge_conn, conn,
service->config.circuit_id_protocol);
/* Check contents */
cp1 = buf_get_contents(conn->outbuf, &sz);
@ -2058,7 +2059,8 @@ test_export_client_circuit_id(void *arg)
or_circ->global_identifier = 22;
/* check changes */
export_hs_client_circuit_id_haproxy(edge_conn, conn);
export_hs_client_circuit_id(edge_conn, conn,
service->config.circuit_id_protocol);
cp2 = buf_get_contents(conn->outbuf, &sz);
tt_str_op(cp1, OP_NE, cp2);
tor_free(cp1);
@ -2066,7 +2068,8 @@ test_export_client_circuit_id(void *arg)
/* Check that GID with UINT32_MAX works. */
or_circ->global_identifier = UINT32_MAX;
export_hs_client_circuit_id_haproxy(edge_conn, conn);
export_hs_client_circuit_id(edge_conn, conn,
service->config.circuit_id_protocol);
cp1 = buf_get_contents(conn->outbuf, &sz);
tt_str_op(cp1, OP_EQ,
"PROXY TCP6 fc00:dead:beef:4dad::ffff:ffff ::1 65535 42\r\n");
@ -2075,7 +2078,8 @@ test_export_client_circuit_id(void *arg)
/* Check that GID with UINT16_MAX works. */
or_circ->global_identifier = UINT16_MAX;
export_hs_client_circuit_id_haproxy(edge_conn, conn);
export_hs_client_circuit_id(edge_conn, conn,
service->config.circuit_id_protocol);
cp1 = buf_get_contents(conn->outbuf, &sz);
tt_str_op(cp1, OP_EQ,
"PROXY TCP6 fc00:dead:beef:4dad::0:ffff ::1 65535 42\r\n");
@ -2084,7 +2088,8 @@ test_export_client_circuit_id(void *arg)
/* Check that GID with UINT16_MAX + 7 works. */
or_circ->global_identifier = UINT16_MAX + 7;
export_hs_client_circuit_id_haproxy(edge_conn, conn);
export_hs_client_circuit_id(edge_conn, conn,
service->config.circuit_id_protocol);
cp1 = buf_get_contents(conn->outbuf, &sz);
tt_str_op(cp1, OP_EQ, "PROXY TCP6 fc00:dead:beef:4dad::1:6 ::1 6 42\r\n");