mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-09-20 13:06:20 +02:00
Merge remote-tracking branch 'ahf-github/asn/bugs4700_2'
This commit is contained in:
commit
0e4c42a912
5
changes/bug4700
Normal file
5
changes/bug4700
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
o Minor features (onion services):
|
||||||
|
- Version 3 onion services can now use the per-service
|
||||||
|
HiddenServiceExportCircuitID option to differentiate client circuits by
|
||||||
|
using the HAProxy proxy protocol which assigns IP addresses to inbound client
|
||||||
|
circuits. Closes ticket 4700. Patch by Mahrud Sayrafi.
|
@ -2845,6 +2845,33 @@ The following options are used to configure a hidden service.
|
|||||||
not an authorization mechanism; it is instead meant to be a mild
|
not an authorization mechanism; it is instead meant to be a mild
|
||||||
inconvenience to port-scanners.) (Default: 0)
|
inconvenience to port-scanners.) (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. (Default: none) +
|
||||||
|
+
|
||||||
|
The haproxy option works in the following way: when the feature is
|
||||||
|
enabled, the Tor process will write a header line when a client is connecting
|
||||||
|
to the onion service. The header will look like this: +
|
||||||
|
+
|
||||||
|
"PROXY TCP6 fc00:dead:beef:4dad::ffff:ffff ::1 65535 42\r\n" +
|
||||||
|
+
|
||||||
|
We encode the "global circuit identifier" as the last 32-bits of the first
|
||||||
|
IPv6 address. All other values in the header can safely be ignored. You can
|
||||||
|
compute the global circuit identifier using the following formula given the
|
||||||
|
IPv6 address "fc00:dead:beef:4dad::AABB:CCDD": +
|
||||||
|
+
|
||||||
|
global_circuit_id = (0xAA << 24) + (0xBB << 16) + (0xCC << 8) + 0xDD; +
|
||||||
|
+
|
||||||
|
In the case above, where the last 32-bit is 0xffffffff, the global circuit
|
||||||
|
identifier would be 4294967295. You can use this value together with Tor's
|
||||||
|
control port where it is possible to terminate a circuit given the global
|
||||||
|
circuit identifier. For more information about this see controls-spec.txt. +
|
||||||
|
+
|
||||||
|
The HAProxy version 1 proxy protocol is described in detail at
|
||||||
|
https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
|
||||||
|
|
||||||
[[HiddenServiceMaxStreams]] **HiddenServiceMaxStreams** __N__::
|
[[HiddenServiceMaxStreams]] **HiddenServiceMaxStreams** __N__::
|
||||||
The maximum number of simultaneous streams (connections) per rendezvous
|
The maximum number of simultaneous streams (connections) per rendezvous
|
||||||
circuit. The maximum value allowed is 65535. (Setting this to 0 will allow
|
circuit. The maximum value allowed is 65535. (Setting this to 0 will allow
|
||||||
|
@ -460,6 +460,7 @@ static config_var_t option_vars_[] = {
|
|||||||
VAR("HiddenServiceMaxStreams",LINELIST_S, RendConfigLines, NULL),
|
VAR("HiddenServiceMaxStreams",LINELIST_S, RendConfigLines, NULL),
|
||||||
VAR("HiddenServiceMaxStreamsCloseCircuit",LINELIST_S, RendConfigLines, NULL),
|
VAR("HiddenServiceMaxStreamsCloseCircuit",LINELIST_S, RendConfigLines, NULL),
|
||||||
VAR("HiddenServiceNumIntroductionPoints", LINELIST_S, RendConfigLines, NULL),
|
VAR("HiddenServiceNumIntroductionPoints", LINELIST_S, RendConfigLines, NULL),
|
||||||
|
VAR("HiddenServiceExportCircuitID", LINELIST_S, RendConfigLines, NULL),
|
||||||
VAR("HiddenServiceStatistics", BOOL, HiddenServiceStatistics_option, "1"),
|
VAR("HiddenServiceStatistics", BOOL, HiddenServiceStatistics_option, "1"),
|
||||||
V(HidServAuth, LINELIST, NULL),
|
V(HidServAuth, LINELIST, NULL),
|
||||||
V(ClientOnionAuthDir, FILENAME, NULL),
|
V(ClientOnionAuthDir, FILENAME, NULL),
|
||||||
|
@ -839,6 +839,46 @@ connected_cell_format_payload(uint8_t *payload_out,
|
|||||||
return connected_payload_len;
|
return connected_payload_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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(edge_connection_t *edge_conn,
|
||||||
|
hs_circuit_id_protocol_t protocol)
|
||||||
|
{
|
||||||
|
/* 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:";
|
||||||
|
uint16_t dst_port = 0;
|
||||||
|
uint16_t src_port = 1; /* default value */
|
||||||
|
uint32_t gid = 0; /* default value */
|
||||||
|
|
||||||
|
/* Generate a GID and source port for this client */
|
||||||
|
if (edge_conn->on_circuit != NULL) {
|
||||||
|
gid = TO_ORIGIN_CIRCUIT(edge_conn->on_circuit)->global_identifier;
|
||||||
|
src_port = gid & 0x0000ffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grab the original dest port from the hs ident */
|
||||||
|
if (edge_conn->hs_ident) {
|
||||||
|
dst_port = edge_conn->hs_ident->orig_virtual_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build the string */
|
||||||
|
tor_asprintf(&buf, "PROXY TCP6 %s:%x:%x %s %d %d\r\n",
|
||||||
|
src_ipv6_prefix,
|
||||||
|
gid >> 16, gid & 0x0000ffff,
|
||||||
|
dst_ipv6, src_port, dst_port);
|
||||||
|
|
||||||
|
connection_buf_add(buf, strlen(buf), TO_CONN(edge_conn));
|
||||||
|
|
||||||
|
tor_free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
/** Connected handler for exit connections: start writing pending
|
/** Connected handler for exit connections: start writing pending
|
||||||
* data, deliver 'CONNECTED' relay cells as appropriate, and check
|
* data, deliver 'CONNECTED' relay cells as appropriate, and check
|
||||||
* any pending data that may have been received. */
|
* any pending data that may have been received. */
|
||||||
@ -859,6 +899,7 @@ connection_edge_finished_connecting(edge_connection_t *edge_conn)
|
|||||||
rep_hist_note_exit_stream_opened(conn->port);
|
rep_hist_note_exit_stream_opened(conn->port);
|
||||||
|
|
||||||
conn->state = EXIT_CONN_STATE_OPEN;
|
conn->state = EXIT_CONN_STATE_OPEN;
|
||||||
|
|
||||||
connection_watch_events(conn, READ_EVENT); /* stop writing, keep reading */
|
connection_watch_events(conn, READ_EVENT); /* stop writing, keep reading */
|
||||||
if (connection_get_outbuf_len(conn)) /* in case there are any queued relay
|
if (connection_get_outbuf_len(conn)) /* in case there are any queued relay
|
||||||
* cells */
|
* cells */
|
||||||
@ -3652,6 +3693,14 @@ handle_hs_exit_conn(circuit_t *circ, edge_connection_t *conn)
|
|||||||
|
|
||||||
hs_inc_rdv_stream_counter(origin_circ);
|
hs_inc_rdv_stream_counter(origin_circ);
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
/* Connect tor to the hidden service destination. */
|
/* Connect tor to the hidden service destination. */
|
||||||
connection_exit_connect(conn);
|
connection_exit_connect(conn);
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
#include "lib/testsupport/testsupport.h"
|
#include "lib/testsupport/testsupport.h"
|
||||||
|
|
||||||
|
#include "feature/hs/hs_service.h"
|
||||||
|
|
||||||
edge_connection_t *TO_EDGE_CONN(connection_t *);
|
edge_connection_t *TO_EDGE_CONN(connection_t *);
|
||||||
entry_connection_t *TO_ENTRY_CONN(connection_t *);
|
entry_connection_t *TO_ENTRY_CONN(connection_t *);
|
||||||
entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *);
|
entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *);
|
||||||
@ -260,6 +262,10 @@ STATIC void connection_ap_handshake_rewrite(entry_connection_t *conn,
|
|||||||
rewrite_result_t *out);
|
rewrite_result_t *out);
|
||||||
|
|
||||||
STATIC int connection_ap_process_http_connect(entry_connection_t *conn);
|
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);
|
||||||
|
|
||||||
#endif /* defined(CONNECTION_EDGE_PRIVATE) */
|
#endif /* defined(CONNECTION_EDGE_PRIVATE) */
|
||||||
|
|
||||||
#endif /* !defined(TOR_CONNECTION_EDGE_H) */
|
#endif /* !defined(TOR_CONNECTION_EDGE_H) */
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "lib/cc/compat_compiler.h"
|
#include "lib/cc/compat_compiler.h"
|
||||||
#include "lib/cc/torint.h"
|
#include "lib/cc/torint.h"
|
||||||
#include "lib/container/map.h"
|
#include "lib/container/map.h"
|
||||||
|
#include "lib/container/buffers.h"
|
||||||
#include "lib/container/smartlist.h"
|
#include "lib/container/smartlist.h"
|
||||||
#include "lib/crypt_ops/crypto_cipher.h"
|
#include "lib/crypt_ops/crypto_cipher.h"
|
||||||
#include "lib/crypt_ops/crypto_rsa.h"
|
#include "lib/crypt_ops/crypto_rsa.h"
|
||||||
|
@ -882,6 +882,11 @@ hs_set_conn_addr_port(const smartlist_t *ports, edge_connection_t *conn)
|
|||||||
smartlist_free(matching_ports);
|
smartlist_free(matching_ports);
|
||||||
if (chosen_port) {
|
if (chosen_port) {
|
||||||
if (!(chosen_port->is_unix_addr)) {
|
if (!(chosen_port->is_unix_addr)) {
|
||||||
|
/* save the original destination before we overwrite it */
|
||||||
|
if (conn->hs_ident) {
|
||||||
|
conn->hs_ident->orig_virtual_port = TO_CONN(conn)->port;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get a non-AF_UNIX connection ready for connection_exit_connect() */
|
/* Get a non-AF_UNIX connection ready for connection_exit_connect() */
|
||||||
tor_addr_copy(&TO_CONN(conn)->addr, &chosen_port->real_addr);
|
tor_addr_copy(&TO_CONN(conn)->addr, &chosen_port->real_addr);
|
||||||
TO_CONN(conn)->port = chosen_port->real_port;
|
TO_CONN(conn)->port = chosen_port->real_port;
|
||||||
|
@ -145,6 +145,34 @@ helper_parse_uint64(const char *opt, const char *value, uint64_t min,
|
|||||||
return ret;
|
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 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
|
/* 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
|
* any. If nothing is found, the current service configured version is
|
||||||
* returned. */
|
* returned. */
|
||||||
@ -188,6 +216,11 @@ config_has_invalid_options(const config_line_t *line_,
|
|||||||
NULL /* End marker. */
|
NULL /* End marker. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char *opts_exclude_v2[] = {
|
||||||
|
"HiddenServiceExportCircuitID",
|
||||||
|
NULL /* End marker. */
|
||||||
|
};
|
||||||
|
|
||||||
/* Defining the size explicitly allows us to take advantage of the compiler
|
/* Defining the size explicitly allows us to take advantage of the compiler
|
||||||
* which warns us if we ever bump the max version but forget to grow this
|
* which warns us if we ever bump the max version but forget to grow this
|
||||||
* array. The plus one is because we have a version 0 :). */
|
* array. The plus one is because we have a version 0 :). */
|
||||||
@ -196,7 +229,7 @@ config_has_invalid_options(const config_line_t *line_,
|
|||||||
} exclude_lists[HS_VERSION_MAX + 1] = {
|
} exclude_lists[HS_VERSION_MAX + 1] = {
|
||||||
{ NULL }, /* v0. */
|
{ NULL }, /* v0. */
|
||||||
{ NULL }, /* v1. */
|
{ NULL }, /* v1. */
|
||||||
{ NULL }, /* v2 */
|
{ opts_exclude_v2 }, /* v2 */
|
||||||
{ opts_exclude_v3 }, /* v3. */
|
{ opts_exclude_v3 }, /* v3. */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -262,6 +295,7 @@ config_service_v3(const config_line_t *line_,
|
|||||||
hs_service_config_t *config)
|
hs_service_config_t *config)
|
||||||
{
|
{
|
||||||
int have_num_ip = 0;
|
int have_num_ip = 0;
|
||||||
|
bool export_circuit_id = false; /* just to detect duplicate options */
|
||||||
const char *dup_opt_seen = NULL;
|
const char *dup_opt_seen = NULL;
|
||||||
const config_line_t *line;
|
const config_line_t *line;
|
||||||
|
|
||||||
@ -288,6 +322,18 @@ config_service_v3(const config_line_t *line_,
|
|||||||
have_num_ip = 1;
|
have_num_ip = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!strcasecmp(line->key, "HiddenServiceExportCircuitID")) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
export_circuit_id = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We do not load the key material for the service at this stage. This is
|
/* We do not load the key material for the service at this stage. This is
|
||||||
|
@ -111,6 +111,10 @@ typedef struct hs_ident_edge_conn_t {
|
|||||||
* in the onion address. */
|
* in the onion address. */
|
||||||
ed25519_public_key_t identity_pk;
|
ed25519_public_key_t identity_pk;
|
||||||
|
|
||||||
|
/* The original virtual port that was used by the client to access the onion
|
||||||
|
* service, regardless of the internal port forwarding that might have
|
||||||
|
* happened on the service-side. */
|
||||||
|
uint16_t orig_virtual_port;
|
||||||
/* XXX: Client authorization. */
|
/* XXX: Client authorization. */
|
||||||
} hs_ident_edge_conn_t;
|
} hs_ident_edge_conn_t;
|
||||||
|
|
||||||
|
@ -3767,6 +3767,19 @@ hs_service_set_conn_addr_port(const origin_circuit_t *circ,
|
|||||||
return -1;
|
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
|
/* 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
|
* dir_list every directory path used by a configured hidden service. This is
|
||||||
* used by the sandbox subsystem to whitelist those. */
|
* used by the sandbox subsystem to whitelist those. */
|
||||||
|
@ -161,6 +161,15 @@ typedef struct hs_service_authorized_client_t {
|
|||||||
curve25519_public_key_t client_pk;
|
curve25519_public_key_t client_pk;
|
||||||
} hs_service_authorized_client_t;
|
} 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
|
/* Service configuration. The following are set from the torrc options either
|
||||||
* set by the configuration file or by the control port. Nothing else should
|
* set by the configuration file or by the control port. Nothing else should
|
||||||
* change those values. */
|
* change those values. */
|
||||||
@ -210,6 +219,9 @@ typedef struct hs_service_config_t {
|
|||||||
|
|
||||||
/* Is this service ephemeral? */
|
/* Is this service ephemeral? */
|
||||||
unsigned int is_ephemeral : 1;
|
unsigned int is_ephemeral : 1;
|
||||||
|
|
||||||
|
/* Does this service export the circuit ID of its clients? */
|
||||||
|
hs_circuit_id_protocol_t circuit_id_protocol;
|
||||||
} hs_service_config_t;
|
} hs_service_config_t;
|
||||||
|
|
||||||
/* Service state. */
|
/* Service state. */
|
||||||
@ -316,6 +328,9 @@ void hs_service_upload_desc_to_dir(const char *encoded_desc,
|
|||||||
const ed25519_public_key_t *blinded_pk,
|
const ed25519_public_key_t *blinded_pk,
|
||||||
const routerstatus_t *hsdir_rs);
|
const routerstatus_t *hsdir_rs);
|
||||||
|
|
||||||
|
hs_circuit_id_protocol_t
|
||||||
|
hs_service_exports_circuit_id(const ed25519_public_key_t *pk);
|
||||||
|
|
||||||
#ifdef HS_SERVICE_PRIVATE
|
#ifdef HS_SERVICE_PRIVATE
|
||||||
|
|
||||||
#ifdef TOR_UNIT_TESTS
|
#ifdef TOR_UNIT_TESTS
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "core/or/or_connection_st.h"
|
#include "core/or/or_connection_st.h"
|
||||||
|
|
||||||
#include "test/test.h"
|
#include "test/test.h"
|
||||||
|
#include "test/test_helpers.h"
|
||||||
|
|
||||||
#ifdef HAVE_SYS_STAT_H
|
#ifdef HAVE_SYS_STAT_H
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@ -89,22 +90,6 @@ connection_write_to_buf_impl_replacement(const char *string, size_t len,
|
|||||||
buf_add(conn->outbuf, string, len);
|
buf_add(conn->outbuf, string, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
|
||||||
buf_get_contents(buf_t *buf, size_t *sz_out)
|
|
||||||
{
|
|
||||||
char *out;
|
|
||||||
*sz_out = buf_datalen(buf);
|
|
||||||
if (*sz_out >= ULONG_MAX)
|
|
||||||
return NULL; /* C'mon, really? */
|
|
||||||
out = tor_malloc(*sz_out + 1);
|
|
||||||
if (buf_get_bytes(buf, out, (unsigned long)*sz_out) != 0) {
|
|
||||||
tor_free(out);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
out[*sz_out] = '\0'; /* Hopefully gratuitous. */
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_ext_or_write_command(void *arg)
|
test_ext_or_write_command(void *arg)
|
||||||
{
|
{
|
||||||
|
@ -125,6 +125,25 @@ connection_write_to_buf_mock(const char *string, size_t len,
|
|||||||
buf_add(conn->outbuf, string, len);
|
buf_add(conn->outbuf, string, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
buf_get_contents(buf_t *buf, size_t *sz_out)
|
||||||
|
{
|
||||||
|
tor_assert(buf);
|
||||||
|
tor_assert(sz_out);
|
||||||
|
|
||||||
|
char *out;
|
||||||
|
*sz_out = buf_datalen(buf);
|
||||||
|
if (*sz_out >= ULONG_MAX)
|
||||||
|
return NULL; /* C'mon, really? */
|
||||||
|
out = tor_malloc(*sz_out + 1);
|
||||||
|
if (buf_get_bytes(buf, out, (unsigned long)*sz_out) != 0) {
|
||||||
|
tor_free(out);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
out[*sz_out] = '\0'; /* Hopefully gratuitous. */
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set up a fake origin circuit with the specified number of cells,
|
/* Set up a fake origin circuit with the specified number of cells,
|
||||||
* Return a pointer to the newly-created dummy circuit */
|
* Return a pointer to the newly-created dummy circuit */
|
||||||
circuit_t *
|
circuit_t *
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
#ifndef TOR_TEST_HELPERS_H
|
#ifndef TOR_TEST_HELPERS_H
|
||||||
#define TOR_TEST_HELPERS_H
|
#define TOR_TEST_HELPERS_H
|
||||||
|
|
||||||
|
#define BUFFERS_PRIVATE
|
||||||
|
|
||||||
#include "core/or/or.h"
|
#include "core/or/or.h"
|
||||||
|
|
||||||
const char *get_yesterday_date_str(void);
|
const char *get_yesterday_date_str(void);
|
||||||
@ -18,6 +20,7 @@ void helper_setup_fake_routerlist(void);
|
|||||||
#define GET(path) "GET " path " HTTP/1.0\r\n\r\n"
|
#define GET(path) "GET " path " HTTP/1.0\r\n\r\n"
|
||||||
void connection_write_to_buf_mock(const char *string, size_t len,
|
void connection_write_to_buf_mock(const char *string, size_t len,
|
||||||
connection_t *conn, int compressed);
|
connection_t *conn, int compressed);
|
||||||
|
char *buf_get_contents(buf_t *buf, size_t *sz_out);
|
||||||
|
|
||||||
int mock_tor_addr_lookup__fail_on_bad_addrs(const char *name,
|
int mock_tor_addr_lookup__fail_on_bad_addrs(const char *name,
|
||||||
uint16_t family, tor_addr_t *out);
|
uint16_t family, tor_addr_t *out);
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#define CIRCUITLIST_PRIVATE
|
#define CIRCUITLIST_PRIVATE
|
||||||
#define CONFIG_PRIVATE
|
#define CONFIG_PRIVATE
|
||||||
#define CONNECTION_PRIVATE
|
#define CONNECTION_PRIVATE
|
||||||
|
#define CONNECTION_EDGE_PRIVATE
|
||||||
#define CRYPTO_PRIVATE
|
#define CRYPTO_PRIVATE
|
||||||
#define HS_COMMON_PRIVATE
|
#define HS_COMMON_PRIVATE
|
||||||
#define HS_SERVICE_PRIVATE
|
#define HS_SERVICE_PRIVATE
|
||||||
@ -33,6 +34,9 @@
|
|||||||
#include "core/or/circuitbuild.h"
|
#include "core/or/circuitbuild.h"
|
||||||
#include "core/or/circuitlist.h"
|
#include "core/or/circuitlist.h"
|
||||||
#include "core/or/circuituse.h"
|
#include "core/or/circuituse.h"
|
||||||
|
#include "core/mainloop/connection.h"
|
||||||
|
#include "core/or/connection_edge.h"
|
||||||
|
#include "core/or/edge_connection_st.h"
|
||||||
#include "lib/crypt_ops/crypto_rand.h"
|
#include "lib/crypt_ops/crypto_rand.h"
|
||||||
#include "lib/fs/dir.h"
|
#include "lib/fs/dir.h"
|
||||||
#include "feature/dirauth/dirvote.h"
|
#include "feature/dirauth/dirvote.h"
|
||||||
@ -2003,6 +2007,96 @@ test_authorized_client_config_equal(void *arg)
|
|||||||
tor_free(config2);
|
tor_free(config2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Test that client circuit ID gets correctly exported */
|
||||||
|
static void
|
||||||
|
test_export_client_circuit_id(void *arg)
|
||||||
|
{
|
||||||
|
origin_circuit_t *or_circ = NULL;
|
||||||
|
size_t sz;
|
||||||
|
char *cp1=NULL, *cp2=NULL;
|
||||||
|
connection_t *conn = NULL;
|
||||||
|
|
||||||
|
(void) arg;
|
||||||
|
|
||||||
|
MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
|
||||||
|
|
||||||
|
hs_service_init();
|
||||||
|
|
||||||
|
/* Create service */
|
||||||
|
hs_service_t *service = helper_create_service();
|
||||||
|
/* Check that export circuit ID detection works */
|
||||||
|
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.circuit_id_protocol = HS_CIRCUIT_ID_PROTOCOL_HAPROXY;
|
||||||
|
tt_int_op(1, OP_EQ,
|
||||||
|
hs_service_exports_circuit_id(&service->keys.identity_pk));
|
||||||
|
|
||||||
|
/* Create client connection */
|
||||||
|
conn = test_conn_get_connection(AP_CONN_STATE_CIRCUIT_WAIT, CONN_TYPE_AP, 0);
|
||||||
|
|
||||||
|
/* Create client edge conn hs_ident */
|
||||||
|
edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
|
||||||
|
edge_conn->hs_ident = hs_ident_edge_conn_new(&service->keys.identity_pk);
|
||||||
|
edge_conn->hs_ident->orig_virtual_port = 42;
|
||||||
|
|
||||||
|
/* Create rend circuit */
|
||||||
|
or_circ = origin_circuit_new();
|
||||||
|
or_circ->base_.purpose = CIRCUIT_PURPOSE_C_REND_JOINED;
|
||||||
|
edge_conn->on_circuit = TO_CIRCUIT(or_circ);
|
||||||
|
or_circ->global_identifier = 666;
|
||||||
|
|
||||||
|
/* Export circuit ID */
|
||||||
|
export_hs_client_circuit_id(edge_conn, service->config.circuit_id_protocol);
|
||||||
|
|
||||||
|
/* Check contents */
|
||||||
|
cp1 = buf_get_contents(conn->outbuf, &sz);
|
||||||
|
tt_str_op(cp1, OP_EQ,
|
||||||
|
"PROXY TCP6 fc00:dead:beef:4dad::0:29a ::1 666 42\r\n");
|
||||||
|
|
||||||
|
/* Change circ GID and see that the reported circuit ID also changes */
|
||||||
|
or_circ->global_identifier = 22;
|
||||||
|
|
||||||
|
/* check changes */
|
||||||
|
export_hs_client_circuit_id(edge_conn, service->config.circuit_id_protocol);
|
||||||
|
cp2 = buf_get_contents(conn->outbuf, &sz);
|
||||||
|
tt_str_op(cp1, OP_NE, cp2);
|
||||||
|
tor_free(cp1);
|
||||||
|
|
||||||
|
/* Check that GID with UINT32_MAX works. */
|
||||||
|
or_circ->global_identifier = UINT32_MAX;
|
||||||
|
|
||||||
|
export_hs_client_circuit_id(edge_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");
|
||||||
|
tor_free(cp1);
|
||||||
|
|
||||||
|
/* Check that GID with UINT16_MAX works. */
|
||||||
|
or_circ->global_identifier = UINT16_MAX;
|
||||||
|
|
||||||
|
export_hs_client_circuit_id(edge_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");
|
||||||
|
tor_free(cp1);
|
||||||
|
|
||||||
|
/* Check that GID with UINT16_MAX + 7 works. */
|
||||||
|
or_circ->global_identifier = UINT16_MAX + 7;
|
||||||
|
|
||||||
|
export_hs_client_circuit_id(edge_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");
|
||||||
|
|
||||||
|
done:
|
||||||
|
UNMOCK(connection_write_to_buf_impl_);
|
||||||
|
circuit_free_(TO_CIRCUIT(or_circ));
|
||||||
|
connection_free_minimal(conn);
|
||||||
|
hs_service_free(service);
|
||||||
|
tor_free(cp1);
|
||||||
|
tor_free(cp2);
|
||||||
|
}
|
||||||
|
|
||||||
struct testcase_t hs_service_tests[] = {
|
struct testcase_t hs_service_tests[] = {
|
||||||
{ "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup, TT_FORK,
|
{ "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup, TT_FORK,
|
||||||
NULL, NULL },
|
NULL, NULL },
|
||||||
@ -2044,6 +2138,8 @@ struct testcase_t hs_service_tests[] = {
|
|||||||
NULL, NULL },
|
NULL, NULL },
|
||||||
{ "authorized_client_config_equal", test_authorized_client_config_equal,
|
{ "authorized_client_config_equal", test_authorized_client_config_equal,
|
||||||
TT_FORK, NULL, NULL },
|
TT_FORK, NULL, NULL },
|
||||||
|
{ "export_client_circuit_id", test_export_client_circuit_id, TT_FORK,
|
||||||
|
NULL, NULL },
|
||||||
|
|
||||||
END_OF_TESTCASES
|
END_OF_TESTCASES
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user