aboutsummaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
Diffstat (limited to 'src/or')
-rw-r--r--src/or/buffers.c8
-rw-r--r--src/or/channel.c2
-rw-r--r--src/or/channel.h2
-rw-r--r--src/or/channeltls.c4
-rw-r--r--src/or/circuitbuild.c4
-rw-r--r--src/or/circuituse.c9
-rw-r--r--src/or/config.c3
-rw-r--r--src/or/connection.c10
-rw-r--r--src/or/connection_edge.c6
-rw-r--r--src/or/connection_or.c12
-rw-r--r--src/or/control.c173
-rw-r--r--src/or/control.h2
-rw-r--r--src/or/directory.c307
-rw-r--r--src/or/dirserv.c6
-rw-r--r--src/or/dnsserv.c8
-rw-r--r--src/or/ext_orport.c6
-rw-r--r--src/or/hibernate.c51
-rw-r--r--src/or/include.am3
-rw-r--r--src/or/main.c10
-rw-r--r--src/or/networkstatus.c17
-rw-r--r--src/or/networkstatus.h2
-rw-r--r--src/or/onion.c2
-rw-r--r--src/or/or.h25
-rw-r--r--src/or/policies.c2
-rw-r--r--src/or/rendclient.c34
-rw-r--r--src/or/rendcommon.c129
-rw-r--r--src/or/rendcommon.h9
-rw-r--r--src/or/rendmid.c2
-rw-r--r--src/or/rendservice.c86
-rw-r--r--src/or/rendservice.h5
-rw-r--r--src/or/rephist.c4
-rw-r--r--src/or/routerlist.c93
-rw-r--r--src/or/routerlist.h13
-rw-r--r--src/or/routerparse.c31
34 files changed, 735 insertions, 345 deletions
diff --git a/src/or/buffers.c b/src/or/buffers.c
index f93cc48f33..cdc71ab9db 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -107,7 +107,7 @@ chunk_repack(chunk_t *chunk)
/** Keep track of total size of allocated chunks for consistency asserts */
static size_t total_bytes_allocated_in_chunks = 0;
static void
-chunk_free_unchecked(chunk_t *chunk)
+buf_chunk_free_unchecked(chunk_t *chunk)
{
if (!chunk)
return;
@@ -228,7 +228,7 @@ buf_pullup(buf_t *buf, size_t bytes)
dest->next = src->next;
if (buf->tail == src)
buf->tail = dest;
- chunk_free_unchecked(src);
+ buf_chunk_free_unchecked(src);
} else {
memcpy(CHUNK_WRITE_PTR(dest), src->data, n);
dest->datalen += n;
@@ -274,7 +274,7 @@ buf_remove_from_front(buf_t *buf, size_t n)
buf->head = victim->next;
if (buf->tail == victim)
buf->tail = NULL;
- chunk_free_unchecked(victim);
+ buf_chunk_free_unchecked(victim);
}
}
check();
@@ -314,7 +314,7 @@ buf_clear(buf_t *buf)
buf->datalen = 0;
for (chunk = buf->head; chunk; chunk = next) {
next = chunk->next;
- chunk_free_unchecked(chunk);
+ buf_chunk_free_unchecked(chunk);
}
buf->head = buf->tail = NULL;
}
diff --git a/src/or/channel.c b/src/or/channel.c
index 5f69a0864b..f3939399b0 100644
--- a/src/or/channel.c
+++ b/src/or/channel.c
@@ -3510,7 +3510,7 @@ channel_dump_statistics, (channel_t *chan, int severity))
have_remote_addr = channel_get_addr_if_possible(chan, &remote_addr);
if (have_remote_addr) {
char *actual = tor_strdup(channel_get_actual_remote_descr(chan));
- remote_addr_str = tor_dup_addr(&remote_addr);
+ remote_addr_str = tor_addr_to_str_dup(&remote_addr);
tor_log(severity, LD_GENERAL,
" * Channel " U64_FORMAT " says its remote address"
" is %s, and gives a canonical description of \"%s\" and an "
diff --git a/src/or/channel.h b/src/or/channel.h
index 129c0c2013..a8c337e107 100644
--- a/src/or/channel.h
+++ b/src/or/channel.h
@@ -18,7 +18,7 @@ typedef void (*channel_cell_handler_fn_ptr)(channel_t *, cell_t *);
typedef void (*channel_var_cell_handler_fn_ptr)(channel_t *, var_cell_t *);
struct cell_queue_entry_s;
-TOR_SIMPLEQ_HEAD(chan_cell_queue, cell_queue_entry_s) incoming_queue;
+TOR_SIMPLEQ_HEAD(chan_cell_queue, cell_queue_entry_s);
typedef struct chan_cell_queue chan_cell_queue_t;
/**
diff --git a/src/or/channeltls.c b/src/or/channeltls.c
index c65af5d040..2128b0924d 100644
--- a/src/or/channeltls.c
+++ b/src/or/channeltls.c
@@ -554,7 +554,7 @@ channel_tls_get_remote_descr_method(channel_t *chan, int flags)
break;
case GRD_FLAG_ORIGINAL:
/* Actual address with port */
- addr_str = tor_dup_addr(&(tlschan->conn->real_addr));
+ addr_str = tor_addr_to_str_dup(&(tlschan->conn->real_addr));
tor_snprintf(buf, MAX_DESCR_LEN + 1,
"%s:%u", addr_str, conn->port);
tor_free(addr_str);
@@ -567,7 +567,7 @@ channel_tls_get_remote_descr_method(channel_t *chan, int flags)
break;
case GRD_FLAG_ORIGINAL|GRD_FLAG_ADDR_ONLY:
/* Actual address, no port */
- addr_str = tor_dup_addr(&(tlschan->conn->real_addr));
+ addr_str = tor_addr_to_str_dup(&(tlschan->conn->real_addr));
strlcpy(buf, addr_str, sizeof(buf));
tor_free(addr_str);
answer = buf;
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index a5a933e6b0..e6fe3f0c37 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -47,10 +47,6 @@
#include "routerset.h"
#include "crypto.h"
-#ifndef MIN
-#define MIN(a,b) ((a)<(b)?(a):(b))
-#endif
-
static channel_t * channel_connect_for_circuit(const tor_addr_t *addr,
uint16_t port,
const char *id_digest);
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index a4b580104f..246f6c50c9 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -1067,7 +1067,7 @@ circuit_predict_and_launch_new(void)
if (rep_hist_get_predicted_internal(now, &hidserv_needs_uptime,
&hidserv_needs_capacity) &&
((num_uptime_internal<2 && hidserv_needs_uptime) ||
- num_internal<2)
+ num_internal<3)
&& router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN) {
if (hidserv_needs_uptime)
flags |= CIRCLAUNCH_NEED_UPTIME;
@@ -2145,10 +2145,11 @@ optimistic_data_enabled(void)
{
const or_options_t *options = get_options();
if (options->OptimisticData < 0) {
- /* XXX023 consider having auto default to 1 rather than 0 before
- * the 0.2.3 branch goes stable. See bug 3617. -RD */
+ /* Note: this default was 0 before #18815 was merged. We can't take the
+ * parameter out of the consensus until versions before that are all
+ * obsolete. */
const int32_t enabled =
- networkstatus_get_param(NULL, "UseOptimisticData", 0, 0, 1);
+ networkstatus_get_param(NULL, "UseOptimisticData", /*default*/ 1, 0, 1);
return (int)enabled;
}
return options->OptimisticData;
diff --git a/src/or/config.c b/src/or/config.c
index 5d938d101a..2e14ba69dc 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -2796,7 +2796,8 @@ options_validate(or_options_t *old_options, or_options_t *options,
} else {
if (!is_legal_nickname(options->Nickname)) {
tor_asprintf(msg,
- "Nickname '%s' is wrong length or contains illegal characters.",
+ "Nickname '%s', nicknames must be between 1 and 19 characters "
+ "inclusive, and must contain only the characters [a-zA-Z0-9].",
options->Nickname);
return -1;
}
diff --git a/src/or/connection.c b/src/or/connection.c
index 118e239176..1bd1a92e39 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -665,9 +665,7 @@ connection_free,(connection_t *conn))
return;
tor_assert(!connection_is_on_closeable_list(conn));
tor_assert(!connection_in_array(conn));
- if (conn->linked_conn) {
- log_err(LD_BUG, "Called with conn->linked_conn still set.");
- tor_fragile_assert();
+ if (BUG(conn->linked_conn)) {
conn->linked_conn->linked_conn = NULL;
if (! conn->linked_conn->marked_for_close &&
conn->linked_conn->reading_from_linked_conn)
@@ -1564,7 +1562,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
/* remember the remote address */
tor_addr_copy(&newconn->addr, &addr);
newconn->port = port;
- newconn->address = tor_dup_addr(&addr);
+ newconn->address = tor_addr_to_str_dup(&addr);
if (new_type == CONN_TYPE_AP && conn->socket_family != AF_UNIX) {
log_info(LD_NET, "New SOCKS connection opened from %s.",
@@ -2538,7 +2536,7 @@ retry_listener_ports(smartlist_t *old_conns,
real_port,
listensockaddr,
sizeof(struct sockaddr_storage));
- address = tor_dup_addr(&port->addr);
+ address = tor_addr_to_str_dup(&port->addr);
}
if (listensockaddr) {
@@ -3644,7 +3642,7 @@ connection_read_to_buf(connection_t *conn, ssize_t *max_to_read,
* take us over our read allotment, but really we shouldn't be
* believing that SSL bytes are the same as TCP bytes anyway. */
int r2 = read_to_buf_tls(or_conn->tls, pending, conn->inbuf);
- if (r2<0) {
+ if (BUG(r2<0)) {
log_warn(LD_BUG, "apparently, reading pending bytes can fail.");
return -1;
}
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 754e9762ea..e58d32e7a5 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -1691,7 +1691,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
rend_service_authorization_t *client_auth =
rend_client_lookup_service_authorization(socks->address);
- const char *cookie = NULL;
+ const uint8_t *cookie = NULL;
rend_auth_type_t auth_type = REND_NO_AUTH;
if (client_auth) {
log_info(LD_REND, "Using previously configured client authorization "
@@ -1703,7 +1703,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
/* Fill in the rend_data field so we can start doing a connection to
* a hidden service. */
rend_data_t *rend_data = ENTRY_TO_EDGE_CONN(conn)->rend_data =
- rend_data_client_create(socks->address, NULL, cookie, auth_type);
+ rend_data_client_create(socks->address, NULL, (char *) cookie, auth_type);
if (rend_data == NULL) {
return -1;
}
@@ -2433,7 +2433,7 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn)
if (!base_conn->address) {
/* This might be unnecessary. XXXX */
- base_conn->address = tor_dup_addr(&base_conn->addr);
+ base_conn->address = tor_addr_to_str_dup(&base_conn->addr);
}
base_conn->state = AP_CONN_STATE_RESOLVE_WAIT;
log_info(LD_APP,"Address sent for resolve, ap socket "TOR_SOCKET_T_FORMAT
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index ea49bdba77..f8be763792 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -934,7 +934,7 @@ connection_or_init_conn_from_address(or_connection_t *conn,
}
conn->nickname = tor_strdup(node_get_nickname(r));
tor_free(conn->base_.address);
- conn->base_.address = tor_dup_addr(&node_ap.addr);
+ conn->base_.address = tor_addr_to_str_dup(&node_ap.addr);
} else {
conn->nickname = tor_malloc(HEX_DIGEST_LEN+2);
conn->nickname[0] = '$';
@@ -942,7 +942,7 @@ connection_or_init_conn_from_address(or_connection_t *conn,
conn->identity_digest, DIGEST_LEN);
tor_free(conn->base_.address);
- conn->base_.address = tor_dup_addr(addr);
+ conn->base_.address = tor_addr_to_str_dup(addr);
}
/*
@@ -1281,11 +1281,9 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port,
switch (connection_connect(TO_CONN(conn), conn->base_.address,
&addr, port, &socket_error)) {
case -1:
- /* If the connection failed immediately, and we're using
- * a proxy, our proxy is down. Don't blame the Tor server. */
- if (conn->base_.proxy_state == PROXY_INFANT)
- entry_guard_register_connect_status(conn->identity_digest,
- 0, 1, time(NULL));
+ /* We failed to establish a connection probably because of a local
+ * error. No need to blame the guard in this case. Notify the networking
+ * system of this failure. */
connection_or_connect_failed(conn,
errno_to_orconn_end_reason(socket_error),
tor_socket_strerror(socket_error));
diff --git a/src/or/control.c b/src/or/control.c
index e06d7d28a2..862c836e40 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -3788,14 +3788,18 @@ handle_control_add_onion(control_connection_t *conn,
* the other arguments are malformed.
*/
smartlist_t *port_cfgs = smartlist_new();
+ smartlist_t *auth_clients = NULL;
+ smartlist_t *auth_created_clients = NULL;
int discard_pk = 0;
int detach = 0;
int max_streams = 0;
int max_streams_close_circuit = 0;
+ rend_auth_type_t auth_type = REND_NO_AUTH;
for (size_t i = 1; i < arg_len; i++) {
static const char *port_prefix = "Port=";
static const char *flags_prefix = "Flags=";
static const char *max_s_prefix = "MaxStreams=";
+ static const char *auth_prefix = "ClientAuth=";
const char *arg = smartlist_get(args, i);
if (!strcasecmpstart(arg, port_prefix)) {
@@ -3826,10 +3830,12 @@ handle_control_add_onion(control_connection_t *conn,
* connection.
* * 'MaxStreamsCloseCircuit' - Close the circuit if MaxStreams is
* exceeded.
+ * * 'BasicAuth' - Client authorization using the 'basic' method.
*/
static const char *discard_flag = "DiscardPK";
static const char *detach_flag = "Detach";
static const char *max_s_close_flag = "MaxStreamsCloseCircuit";
+ static const char *basicauth_flag = "BasicAuth";
smartlist_t *flags = smartlist_new();
int bad = 0;
@@ -3848,6 +3854,8 @@ handle_control_add_onion(control_connection_t *conn,
detach = 1;
} else if (!strcasecmp(flag, max_s_close_flag)) {
max_streams_close_circuit = 1;
+ } else if (!strcasecmp(flag, basicauth_flag)) {
+ auth_type = REND_BASIC_AUTH;
} else {
connection_printf_to_buf(conn,
"512 Invalid 'Flags' argument: %s\r\n",
@@ -3860,6 +3868,42 @@ handle_control_add_onion(control_connection_t *conn,
smartlist_free(flags);
if (bad)
goto out;
+ } else if (!strcasecmpstart(arg, auth_prefix)) {
+ char *err_msg = NULL;
+ int created = 0;
+ rend_authorized_client_t *client =
+ add_onion_helper_clientauth(arg + strlen(auth_prefix),
+ &created, &err_msg);
+ if (!client) {
+ if (err_msg) {
+ connection_write_str_to_buf(err_msg, conn);
+ tor_free(err_msg);
+ }
+ goto out;
+ }
+
+ if (auth_clients != NULL) {
+ int bad = 0;
+ SMARTLIST_FOREACH_BEGIN(auth_clients, rend_authorized_client_t *, ac) {
+ if (strcmp(ac->client_name, client->client_name) == 0) {
+ bad = 1;
+ break;
+ }
+ } SMARTLIST_FOREACH_END(ac);
+ if (bad) {
+ connection_printf_to_buf(conn,
+ "512 Duplicate name in ClientAuth\r\n");
+ rend_authorized_client_free(client);
+ goto out;
+ }
+ } else {
+ auth_clients = smartlist_new();
+ auth_created_clients = smartlist_new();
+ }
+ smartlist_add(auth_clients, client);
+ if (created) {
+ smartlist_add(auth_created_clients, client);
+ }
} else {
connection_printf_to_buf(conn, "513 Invalid argument\r\n");
goto out;
@@ -3868,6 +3912,18 @@ handle_control_add_onion(control_connection_t *conn,
if (smartlist_len(port_cfgs) == 0) {
connection_printf_to_buf(conn, "512 Missing 'Port' argument\r\n");
goto out;
+ } else if (auth_type == REND_NO_AUTH && auth_clients != NULL) {
+ connection_printf_to_buf(conn, "512 No auth type specified\r\n");
+ goto out;
+ } else if (auth_type != REND_NO_AUTH && auth_clients == NULL) {
+ connection_printf_to_buf(conn, "512 No auth clients specified\r\n");
+ goto out;
+ } else if ((auth_type == REND_BASIC_AUTH &&
+ smartlist_len(auth_clients) > 512) ||
+ (auth_type == REND_STEALTH_AUTH &&
+ smartlist_len(auth_clients) > 16)) {
+ connection_printf_to_buf(conn, "512 Too many auth clients\r\n");
+ goto out;
}
/* Parse the "keytype:keyblob" argument. */
@@ -3888,35 +3944,21 @@ handle_control_add_onion(control_connection_t *conn,
}
tor_assert(!err_msg);
- /* Create the HS, using private key pk, and port config port_cfg.
+ /* Create the HS, using private key pk, client authentication auth_type,
+ * the list of auth_clients, and port config port_cfg.
* rend_service_add_ephemeral() will take ownership of pk and port_cfg,
* regardless of success/failure.
*/
char *service_id = NULL;
int ret = rend_service_add_ephemeral(pk, port_cfgs, max_streams,
max_streams_close_circuit,
+ auth_type, auth_clients,
&service_id);
port_cfgs = NULL; /* port_cfgs is now owned by the rendservice code. */
+ auth_clients = NULL; /* so is auth_clients */
switch (ret) {
case RSAE_OKAY:
{
- char *buf = NULL;
- tor_assert(service_id);
- if (key_new_alg) {
- tor_assert(key_new_blob);
- tor_asprintf(&buf,
- "250-ServiceID=%s\r\n"
- "250-PrivateKey=%s:%s\r\n"
- "250 OK\r\n",
- service_id,
- key_new_alg,
- key_new_blob);
- } else {
- tor_asprintf(&buf,
- "250-ServiceID=%s\r\n"
- "250 OK\r\n",
- service_id);
- }
if (detach) {
if (!detached_onion_services)
detached_onion_services = smartlist_new();
@@ -3927,9 +3969,26 @@ handle_control_add_onion(control_connection_t *conn,
smartlist_add(conn->ephemeral_onion_services, service_id);
}
- connection_write_str_to_buf(buf, conn);
- memwipe(buf, 0, strlen(buf));
- tor_free(buf);
+ tor_assert(service_id);
+ connection_printf_to_buf(conn, "250-ServiceID=%s\r\n", service_id);
+ if (key_new_alg) {
+ tor_assert(key_new_blob);
+ connection_printf_to_buf(conn, "250-PrivateKey=%s:%s\r\n",
+ key_new_alg, key_new_blob);
+ }
+ if (auth_created_clients) {
+ SMARTLIST_FOREACH(auth_created_clients, rend_authorized_client_t *, ac, {
+ char *encoded = rend_auth_encode_cookie(ac->descriptor_cookie,
+ auth_type);
+ tor_assert(encoded);
+ connection_printf_to_buf(conn, "250-ClientAuth=%s:%s\r\n",
+ ac->client_name, encoded);
+ memwipe(encoded, 0, strlen(encoded));
+ tor_free(encoded);
+ });
+ }
+
+ connection_printf_to_buf(conn, "250 OK\r\n");
break;
}
case RSAE_BADPRIVKEY:
@@ -3941,6 +4000,9 @@ handle_control_add_onion(control_connection_t *conn,
case RSAE_BADVIRTPORT:
connection_printf_to_buf(conn, "512 Invalid VIRTPORT/TARGET\r\n");
break;
+ case RSAE_BADAUTH:
+ connection_printf_to_buf(conn, "512 Invalid client authorization\r\n");
+ break;
case RSAE_INTERNAL: /* FALLSTHROUGH */
default:
connection_printf_to_buf(conn, "551 Failed to add Onion Service\r\n");
@@ -3957,6 +4019,16 @@ handle_control_add_onion(control_connection_t *conn,
smartlist_free(port_cfgs);
}
+ if (auth_clients) {
+ SMARTLIST_FOREACH(auth_clients, rend_authorized_client_t *, ac,
+ rend_authorized_client_free(ac));
+ smartlist_free(auth_clients);
+ }
+ if (auth_created_clients) {
+ // Do not free entries; they are the same as auth_clients
+ smartlist_free(auth_created_clients);
+ }
+
SMARTLIST_FOREACH(args, char *, cp, {
memwipe(cp, 0, strlen(cp));
tor_free(cp);
@@ -4065,6 +4137,65 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
return pk;
}
+/** Helper function to handle parsing a ClientAuth argument to the
+ * ADD_ONION command. Return a new rend_authorized_client_t, or NULL
+ * and an optional control protocol error message on failure. The
+ * caller is responsible for freeing the returned auth_client and err_msg.
+ *
+ * If 'created' is specified, it will be set to 1 when a new cookie has
+ * been generated.
+ */
+STATIC rend_authorized_client_t *
+add_onion_helper_clientauth(const char *arg, int *created, char **err_msg)
+{
+ int ok = 0;
+
+ tor_assert(arg);
+ tor_assert(created);
+ tor_assert(err_msg);
+ *err_msg = NULL;
+
+ smartlist_t *auth_args = smartlist_new();
+ rend_authorized_client_t *client =
+ tor_malloc_zero(sizeof(rend_authorized_client_t));
+ smartlist_split_string(auth_args, arg, ":", 0, 0);
+ if (smartlist_len(auth_args) < 1 || smartlist_len(auth_args) > 2) {
+ *err_msg = tor_strdup("512 Invalid ClientAuth syntax\r\n");
+ goto err;
+ }
+ client->client_name = tor_strdup(smartlist_get(auth_args, 0));
+ if (smartlist_len(auth_args) == 2) {
+ char *decode_err_msg = NULL;
+ if (rend_auth_decode_cookie(smartlist_get(auth_args, 1),
+ client->descriptor_cookie,
+ NULL, &decode_err_msg) < 0) {
+ tor_assert(decode_err_msg);
+ tor_asprintf(err_msg, "512 %s\r\n", decode_err_msg);
+ tor_free(decode_err_msg);
+ goto err;
+ }
+ *created = 0;
+ } else {
+ crypto_rand((char *) client->descriptor_cookie, REND_DESC_COOKIE_LEN);
+ *created = 1;
+ }
+
+ if (!rend_valid_client_name(client->client_name)) {
+ *err_msg = tor_strdup("512 Invalid name in ClientAuth\r\n");
+ goto err;
+ }
+
+ ok = 1;
+ err:
+ SMARTLIST_FOREACH(auth_args, char *, arg, tor_free(arg));
+ smartlist_free(auth_args);
+ if (!ok) {
+ rend_authorized_client_free(client);
+ client = NULL;
+ }
+ return client;
+}
+
/** Called when we get a DEL_ONION command; parse the body, and remove
* the existing ephemeral Onion Service. */
static int
diff --git a/src/or/control.h b/src/or/control.h
index 008bfb1c3b..b3902e64bd 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -259,6 +259,8 @@ STATIC crypto_pk_t *add_onion_helper_keyarg(const char *arg, int discard_pk,
const char **key_new_alg_out,
char **key_new_blob_out,
char **err_msg_out);
+STATIC rend_authorized_client_t *
+add_onion_helper_clientauth(const char *arg, int *created, char **err_msg_out);
#endif
#endif
diff --git a/src/or/directory.c b/src/or/directory.c
index 8dc018a662..a3ade8f164 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -1181,7 +1181,7 @@ directory_initiate_command_rend(const tor_addr_port_t *or_addr_port,
/* set up conn so it's got all the data we need to remember */
tor_addr_copy(&conn->base_.addr, &addr);
conn->base_.port = port;
- conn->base_.address = tor_dup_addr(&addr);
+ conn->base_.address = tor_addr_to_str_dup(&addr);
memcpy(conn->identity_digest, digest, DIGEST_LEN);
conn->base_.purpose = dir_purpose;
@@ -2854,18 +2854,84 @@ choose_compression_level(ssize_t n_bytes)
}
}
+/** Information passed to handle a GET request. */
+typedef struct get_handler_args_t {
+ /** True if the client asked for compressed data. */
+ int compressed;
+ /** If nonzero, the time included an if-modified-since header with this
+ * value. */
+ time_t if_modified_since;
+ /** String containing the requested URL or resource. */
+ const char *url;
+ /** String containing the HTTP headers */
+ const char *headers;
+} get_handler_args_t;
+
+/** Entry for handling an HTTP GET request.
+ *
+ * This entry matches a request if "string" is equal to the requested
+ * resource, or if "is_prefix" is true and "string" is a prefix of the
+ * requested resource.
+ *
+ * The 'handler' function is called to handle the request. It receives
+ * an arguments structure, and must return 0 on success or -1 if we should
+ * close the connection.
+ **/
+typedef struct url_table_ent_s {
+ const char *string;
+ int is_prefix;
+ int (*handler)(dir_connection_t *conn, const get_handler_args_t *args);
+} url_table_ent_t;
+
+static int handle_get_frontpage(dir_connection_t *conn,
+ const get_handler_args_t *args);
+static int handle_get_current_consensus(dir_connection_t *conn,
+ const get_handler_args_t *args);
+static int handle_get_status_vote(dir_connection_t *conn,
+ const get_handler_args_t *args);
+static int handle_get_microdesc(dir_connection_t *conn,
+ const get_handler_args_t *args);
+static int handle_get_descriptor(dir_connection_t *conn,
+ const get_handler_args_t *args);
+static int handle_get_keys(dir_connection_t *conn,
+ const get_handler_args_t *args);
+static int handle_get_rendezvous2(dir_connection_t *conn,
+ const get_handler_args_t *args);
+static int handle_get_bytes(dir_connection_t *conn,
+ const get_handler_args_t *args);
+static int handle_get_robots(dir_connection_t *conn,
+ const get_handler_args_t *args);
+static int handle_get_networkstatus_bridges(dir_connection_t *conn,
+ const get_handler_args_t *args);
+
+/** Table for handling GET requests. */
+static const url_table_ent_t url_table[] = {
+ { "/tor/", 0, handle_get_frontpage },
+ { "/tor/status-vote/current/consensus", 1, handle_get_current_consensus },
+ { "/tor/status-vote/current/", 1, handle_get_status_vote },
+ { "/tor/status-vote/next/", 1, handle_get_status_vote },
+ { "/tor/micro/d/", 1, handle_get_microdesc },
+ { "/tor/server/", 1, handle_get_descriptor },
+ { "/tor/extra/", 1, handle_get_descriptor },
+ { "/tor/keys/", 1, handle_get_keys },
+ { "/tor/rendezvous2/", 1, handle_get_rendezvous2 },
+ { "/tor/bytes.txt", 0, handle_get_bytes },
+ { "/tor/robots.txt", 0, handle_get_robots },
+ { "/tor/networkstatus-bridges", 0, handle_get_networkstatus_bridges },
+ { NULL, 0, NULL },
+};
+
/** Helper function: called when a dirserver gets a complete HTTP GET
* request. Look for a request for a directory or for a rendezvous
* service descriptor. On finding one, write a response into
- * conn-\>outbuf. If the request is unrecognized, send a 400.
- * Always return 0. */
+ * conn-\>outbuf. If the request is unrecognized, send a 404.
+ * Return 0 if we handled this successfully, or -1 if we need to close
+ * the connection. */
STATIC int
directory_handle_command_get(dir_connection_t *conn, const char *headers,
const char *req_body, size_t req_body_len)
{
- size_t dlen;
char *url, *url_mem, *header;
- const or_options_t *options = get_options();
time_t if_modified_since = 0;
int compressed;
size_t url_len;
@@ -2905,10 +2971,46 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
url_len -= 2;
}
- if (!strcmp(url,"/tor/")) {
+ get_handler_args_t args;
+ args.url = url;
+ args.headers = headers;
+ args.if_modified_since = if_modified_since;
+ args.compressed = compressed;
+
+ int i, result = -1;
+ for (i = 0; url_table[i].string; ++i) {
+ int match;
+ if (url_table[i].is_prefix) {
+ match = !strcmpstart(url, url_table[i].string);
+ } else {
+ match = !strcmp(url, url_table[i].string);
+ }
+ if (match) {
+ result = url_table[i].handler(conn, &args);
+ goto done;
+ }
+ }
+
+ /* we didn't recognize the url */
+ write_http_status_line(conn, 404, "Not found");
+ result = 0;
+
+ done:
+ tor_free(url_mem);
+ return result;
+}
+
+/** Helper function for GET / or GET /tor/
+ */
+static int
+handle_get_frontpage(dir_connection_t *conn, const get_handler_args_t *args)
+{
+ const char *url = args->url;
+ {
const char *frontpage = get_dirportfrontpage();
if (frontpage) {
+ size_t dlen;
dlen = strlen(frontpage);
/* Let's return a disclaimer page (users shouldn't use V1 anymore,
and caches don't fetch '/', so this is safe). */
@@ -2919,12 +3021,24 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
write_http_response_header_impl(conn, dlen, "text/html", "identity",
NULL, DIRPORTFRONTPAGE_CACHE_LIFETIME);
connection_write_to_buf(frontpage, dlen, TO_CONN(conn));
- goto done;
+ } else {
+ write_http_status_line(conn, 404, "Not found");
}
- /* if no disclaimer file, fall through and continue */
}
+ return 0;
+}
+
+/** Helper function for GET /tor/status-vote/current/consensus
+ */
+static int
+handle_get_current_consensus(dir_connection_t *conn,
+ const get_handler_args_t *args)
+{
+ const char *url = args->url;
+ const int compressed = args->compressed;
+ const time_t if_modified_since = args->if_modified_since;
- if (!strcmpstart(url, "/tor/status-vote/current/consensus")) {
+ {
/* v3 network status fetch. */
smartlist_t *dir_fps = smartlist_new();
const char *request_type = NULL;
@@ -3001,7 +3115,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
goto done;
}
- dlen = dirserv_estimate_data_size(dir_fps, 0, compressed);
+ size_t dlen = dirserv_estimate_data_size(dir_fps, 0, compressed);
if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) {
log_debug(LD_DIRSERV,
"Client asked for network status lists, but we've been "
@@ -3045,11 +3159,18 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
goto done;
}
- if (!strcmpstart(url,"/tor/status-vote/current/") ||
- !strcmpstart(url,"/tor/status-vote/next/")) {
- /* XXXX If-modified-since is only implemented for the current
- * consensus: that's probably fine, since it's the only vote document
- * people fetch much. */
+ done:
+ return 0;
+}
+
+/** Helper function for GET /tor/status-vote/{current,next}/...
+ */
+static int
+handle_get_status_vote(dir_connection_t *conn, const get_handler_args_t *args)
+{
+ const char *url = args->url;
+ const int compressed = args->compressed;
+ {
int current;
ssize_t body_len = 0;
ssize_t estimated_len = 0;
@@ -3145,8 +3266,18 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
smartlist_free(dir_items);
goto done;
}
+ done:
+ return 0;
+}
- if (!strcmpstart(url, "/tor/micro/d/")) {
+/** Helper function for GET /tor/micro/d/...
+ */
+static int
+handle_get_microdesc(dir_connection_t *conn, const get_handler_args_t *args)
+{
+ const char *url = args->url;
+ const int compressed = args->compressed;
+ {
smartlist_t *fps = smartlist_new();
dir_split_resource_into_fingerprints(url+strlen("/tor/micro/d/"),
@@ -3159,7 +3290,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
smartlist_free(fps);
goto done;
}
- dlen = dirserv_estimate_microdesc_size(fps, compressed);
+ size_t dlen = dirserv_estimate_microdesc_size(fps, compressed);
if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) {
log_info(LD_DIRSERV,
"Client asked for server descriptors, but we've been "
@@ -3182,9 +3313,22 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
goto done;
}
+ done:
+ return 0;
+}
+
+/** Helper function for GET /tor/{server,extra}/...
+ */
+static int
+handle_get_descriptor(dir_connection_t *conn, const get_handler_args_t *args)
+{
+ const char *url = args->url;
+ const int compressed = args->compressed;
+ const or_options_t *options = get_options();
if (!strcmpstart(url,"/tor/server/") ||
(!options->BridgeAuthoritativeDir &&
!options->BridgeRelay && !strcmpstart(url,"/tor/extra/"))) {
+ size_t dlen;
int res;
const char *msg;
const char *request_type = NULL;
@@ -3251,8 +3395,19 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
}
goto done;
}
+ done:
+ return 0;
+}
- if (!strcmpstart(url,"/tor/keys/")) {
+/** Helper function for GET /tor/keys/...
+ */
+static int
+handle_get_keys(dir_connection_t *conn, const get_handler_args_t *args)
+{
+ const char *url = args->url;
+ const int compressed = args->compressed;
+ const time_t if_modified_since = args->if_modified_since;
+ {
smartlist_t *certs = smartlist_new();
ssize_t len = -1;
if (!strcmp(url, "/tor/keys/all")) {
@@ -3337,9 +3492,17 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
smartlist_free(certs);
goto done;
}
+ done:
+ return 0;
+}
- if (connection_dir_is_encrypted(conn) &&
- !strcmpstart(url,"/tor/rendezvous2/")) {
+/** Helper function for GET /tor/rendezvous2/
+ */
+static int
+handle_get_rendezvous2(dir_connection_t *conn, const get_handler_args_t *args)
+{
+ const char *url = args->url;
+ if (connection_dir_is_encrypted(conn)) {
/* Handle v2 rendezvous descriptor fetch request. */
const char *descp;
const char *query = url + strlen("/tor/rendezvous2/");
@@ -3362,16 +3525,30 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
write_http_status_line(conn, 400, "Bad request");
}
goto done;
+ } else {
+ /* Not encrypted! */
+ write_http_status_line(conn, 404, "Not found");
}
+ done:
+ return 0;
+}
+
+/** Helper function for GET /tor/networkstatus-bridges
+ */
+static int
+handle_get_networkstatus_bridges(dir_connection_t *conn,
+ const get_handler_args_t *args)
+{
+ const char *headers = args->headers;
+ const or_options_t *options = get_options();
if (options->BridgeAuthoritativeDir &&
options->BridgePassword_AuthDigest_ &&
- connection_dir_is_encrypted(conn) &&
- !strcmp(url,"/tor/networkstatus-bridges")) {
+ connection_dir_is_encrypted(conn)) {
char *status;
char digest[DIGEST256_LEN];
- header = http_get_header(headers, "Authorization: Basic ");
+ char *header = http_get_header(headers, "Authorization: Basic ");
if (header)
crypto_digest256(digest, header, strlen(header), DIGEST_SHA256);
@@ -3387,75 +3564,43 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
/* all happy now. send an answer. */
status = networkstatus_getinfo_by_purpose("bridge", time(NULL));
- dlen = strlen(status);
+ size_t dlen = strlen(status);
write_http_response_header(conn, dlen, 0, 0);
connection_write_to_buf(status, dlen, TO_CONN(conn));
tor_free(status);
goto done;
}
+ done:
+ return 0;
+}
- if (!strcmpstart(url,"/tor/bytes.txt")) {
+/** Helper function for GET /tor/bytes.txt
+ */
+static int
+handle_get_bytes(dir_connection_t *conn, const get_handler_args_t *args)
+{
+ (void)args;
+ {
char *bytes = directory_dump_request_log();
size_t len = strlen(bytes);
write_http_response_header(conn, len, 0, 0);
connection_write_to_buf(bytes, len, TO_CONN(conn));
tor_free(bytes);
- goto done;
}
+ return 0;
+}
- if (!strcmp(url,"/tor/robots.txt")) { /* /robots.txt will have been
- rewritten to /tor/robots.txt */
- char robots[] = "User-agent: *\r\nDisallow: /\r\n";
+/** Helper function for GET robots.txt or /tor/robots.txt */
+static int
+handle_get_robots(dir_connection_t *conn, const get_handler_args_t *args)
+{
+ (void)args;
+ {
+ const char robots[] = "User-agent: *\r\nDisallow: /\r\n";
size_t len = strlen(robots);
write_http_response_header(conn, len, 0, ROBOTS_CACHE_LIFETIME);
connection_write_to_buf(robots, len, TO_CONN(conn));
- goto done;
}
-
-#if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
-#define ADD_MALLINFO_LINE(x) do { \
- smartlist_add_asprintf(lines, "%s %d\n", #x, mi.x); \
- }while(0);
-
- if (!strcmp(url,"/tor/mallinfo.txt") &&
- (tor_addr_eq_ipv4h(&conn->base_.addr, 0x7f000001ul))) {
- char *result;
- size_t len;
- struct mallinfo mi;
- smartlist_t *lines;
-
- memset(&mi, 0, sizeof(mi));
- mi = mallinfo();
- lines = smartlist_new();
-
- ADD_MALLINFO_LINE(arena)
- ADD_MALLINFO_LINE(ordblks)
- ADD_MALLINFO_LINE(smblks)
- ADD_MALLINFO_LINE(hblks)
- ADD_MALLINFO_LINE(hblkhd)
- ADD_MALLINFO_LINE(usmblks)
- ADD_MALLINFO_LINE(fsmblks)
- ADD_MALLINFO_LINE(uordblks)
- ADD_MALLINFO_LINE(fordblks)
- ADD_MALLINFO_LINE(keepcost)
-
- result = smartlist_join_strings(lines, "", 0, NULL);
- SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
- smartlist_free(lines);
-
- len = strlen(result);
- write_http_response_header(conn, len, 0, 0);
- connection_write_to_buf(result, len, TO_CONN(conn));
- tor_free(result);
- goto done;
- }
-#endif
-
- /* we didn't recognize the url */
- write_http_status_line(conn, 404, "Not found");
-
- done:
- tor_free(url_mem);
return 0;
}
@@ -3703,7 +3848,7 @@ connection_dir_would_close_consensus_conn_helper(void)
* consensus, and we are still bootstrapping (that is, we have no usable
* consensus), we don't want to close any until one starts downloading. */
if (!networkstatus_consensus_is_downloading_usable_flavor()
- && networkstatus_consensus_is_boostrapping(time(NULL))) {
+ && networkstatus_consensus_is_bootstrapping(time(NULL))) {
return 0;
}
@@ -3737,7 +3882,7 @@ connection_dir_avoid_extra_connection_for_purpose(unsigned int purpose)
* bootstrapping (that is, we have no usable consensus), we can be sure that
* any further connections would be excess. */
if (networkstatus_consensus_is_downloading_usable_flavor()
- && networkstatus_consensus_is_boostrapping(time(NULL))) {
+ && networkstatus_consensus_is_bootstrapping(time(NULL))) {
return 1;
}
@@ -3778,12 +3923,12 @@ connection_dir_close_consensus_conn_if_extra(dir_connection_t *conn)
return 0;
}
- const int we_are_bootstrapping = networkstatus_consensus_is_boostrapping(
+ const int we_are_bootstrapping = networkstatus_consensus_is_bootstrapping(
time(NULL));
/* We don't want to check other connections to see if they are downloading,
* as this is prone to race-conditions. So leave it for
- * connection_dir_consider_close_extra_consensus_conns() to clean up.
+ * connection_dir_close_extra_consensus_conns(() to clean up.
*
* But if conn has just started connecting, or we have a consensus already,
* we can be sure it's not needed any more. */
@@ -3823,7 +3968,7 @@ connection_dir_close_extra_consensus_conns(void)
return;
}
- int we_are_bootstrapping = networkstatus_consensus_is_boostrapping(
+ int we_are_bootstrapping = networkstatus_consensus_is_bootstrapping(
time(NULL));
const char *usable_resource = networkstatus_get_flavor_name(
@@ -3932,7 +4077,7 @@ find_dl_schedule(download_status_t *dls, const or_options_t *options)
const int dir_server = dir_server_mode(options);
const int multi_d = networkstatus_consensus_can_use_multiple_directories(
options);
- const int we_are_bootstrapping = networkstatus_consensus_is_boostrapping(
+ const int we_are_bootstrapping = networkstatus_consensus_is_bootstrapping(
time(NULL));
const int use_fallbacks = networkstatus_consensus_can_use_extra_fallbacks(
options);
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 3e1f48062c..441e4b5377 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -349,7 +349,7 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname,
if (result & FP_REJECT) {
if (msg)
- *msg = "Fingerprint is marked rejected";
+ *msg = "Fingerprint is marked rejected -- please contact us?";
return FP_REJECT;
} else if (result & FP_INVALID) {
if (msg)
@@ -367,7 +367,7 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname,
log_fn(severity, LD_DIRSERV, "Rejecting '%s' because of address '%s'",
nickname, fmt_addr32(addr));
if (msg)
- *msg = "Authdir is rejecting routers in this range.";
+ *msg = "Suspicious relay address range -- please contact us?";
return FP_REJECT;
}
if (!authdir_policy_valid_address(addr, or_port)) {
@@ -2200,7 +2200,7 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
rs->is_valid = node->is_valid;
- if (node->is_fast &&
+ if (node->is_fast && node->is_stable &&
((options->AuthDirGuardBWGuarantee &&
routerbw_kb >= options->AuthDirGuardBWGuarantee/1000) ||
routerbw_kb >= MIN(guard_bandwidth_including_exits_kb,
diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c
index 74f17ce78c..edca50f6f9 100644
--- a/src/or/dnsserv.c
+++ b/src/or/dnsserv.c
@@ -130,7 +130,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
tor_addr_copy(&TO_CONN(conn)->addr, &tor_addr);
TO_CONN(conn)->port = port;
- TO_CONN(conn)->address = tor_dup_addr(&tor_addr);
+ TO_CONN(conn)->address = tor_addr_to_str_dup(&tor_addr);
if (q->type == EVDNS_TYPE_A || q->type == EVDNS_TYPE_AAAA ||
q->type == EVDNS_QTYPE_ALL) {
@@ -205,7 +205,7 @@ dnsserv_launch_request(const char *name, int reverse,
tor_addr_copy(&TO_CONN(conn)->addr, &control_conn->base_.addr);
#ifdef AF_UNIX
/*
- * The control connection can be AF_UNIX and if so tor_dup_addr will
+ * The control connection can be AF_UNIX and if so tor_addr_to_str_dup will
* unhelpfully say "<unknown address type>"; say "(Tor_internal)"
* instead.
*/
@@ -214,11 +214,11 @@ dnsserv_launch_request(const char *name, int reverse,
TO_CONN(conn)->address = tor_strdup("(Tor_internal)");
} else {
TO_CONN(conn)->port = control_conn->base_.port;
- TO_CONN(conn)->address = tor_dup_addr(&control_conn->base_.addr);
+ TO_CONN(conn)->address = tor_addr_to_str_dup(&control_conn->base_.addr);
}
#else
TO_CONN(conn)->port = control_conn->base_.port;
- TO_CONN(conn)->address = tor_dup_addr(&control_conn->base_.addr);
+ TO_CONN(conn)->address = tor_addr_to_str_dup(&control_conn->base_.addr);
#endif
if (reverse)
diff --git a/src/or/ext_orport.c b/src/or/ext_orport.c
index aa1b3e26fe..8ba3c6afa3 100644
--- a/src/or/ext_orport.c
+++ b/src/or/ext_orport.c
@@ -461,8 +461,8 @@ connection_ext_or_handle_cmd_useraddr(connection_t *conn,
return -1;
{ /* do some logging */
- char *old_address = tor_dup_addr(&conn->addr);
- char *new_address = tor_dup_addr(&addr);
+ char *old_address = tor_addr_to_str_dup(&conn->addr);
+ char *new_address = tor_addr_to_str_dup(&addr);
log_debug(LD_NET, "Received USERADDR."
"We rewrite our address from '%s:%u' to '%s:%u'.",
@@ -478,7 +478,7 @@ connection_ext_or_handle_cmd_useraddr(connection_t *conn,
if (conn->address) {
tor_free(conn->address);
}
- conn->address = tor_dup_addr(&addr);
+ conn->address = tor_addr_to_str_dup(&addr);
return 0;
}
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index 9408925d96..3666abbcf4 100644
--- a/src/or/hibernate.c
+++ b/src/or/hibernate.c
@@ -28,6 +28,7 @@ hibernating, phase 2:
#include "config.h"
#include "connection.h"
#include "connection_edge.h"
+#include "control.h"
#include "hibernate.h"
#include "main.h"
#include "router.h"
@@ -111,11 +112,34 @@ static int cfg_start_day = 0,
cfg_start_min = 0;
/** @} */
+static const char *hibernate_state_to_string(hibernate_state_t state);
static void reset_accounting(time_t now);
static int read_bandwidth_usage(void);
static time_t start_of_accounting_period_after(time_t now);
static time_t start_of_accounting_period_containing(time_t now);
static void accounting_set_wakeup_time(void);
+static void on_hibernate_state_change(hibernate_state_t prev_state);
+
+/**
+ * Return the human-readable name for the hibernation state <b>state</b>
+ */
+static const char *
+hibernate_state_to_string(hibernate_state_t state)
+{
+ static char buf[64];
+ switch (state) {
+ case HIBERNATE_STATE_EXITING: return "EXITING";
+ case HIBERNATE_STATE_LOWBANDWIDTH: return "SOFT";
+ case HIBERNATE_STATE_DORMANT: return "HARD";
+ case HIBERNATE_STATE_INITIAL:
+ case HIBERNATE_STATE_LIVE:
+ return "AWAKE";
+ default:
+ log_warn(LD_BUG, "unknown hibernate state %d", state);
+ tor_snprintf(buf, sizeof(buf), "unknown [%d]", state);
+ return buf;
+ }
+}
/* ************
* Functions for bandwidth accounting.
@@ -935,6 +959,7 @@ consider_hibernation(time_t now)
{
int accounting_enabled = get_options()->AccountingMax != 0;
char buf[ISO_TIME_LEN+1];
+ hibernate_state_t prev_state = hibernate_state;
/* If we're in 'exiting' mode, then we just shut down after the interval
* elapses. */
@@ -990,6 +1015,10 @@ consider_hibernation(time_t now)
hibernate_end_time_elapsed(now);
}
}
+
+ /* Dispatch a controller event if the hibernation state changed. */
+ if (hibernate_state != prev_state)
+ on_hibernate_state_change(prev_state);
}
/** Helper function: called when we get a GETINFO request for an
@@ -1007,12 +1036,8 @@ getinfo_helper_accounting(control_connection_t *conn,
if (!strcmp(question, "accounting/enabled")) {
*answer = tor_strdup(accounting_is_enabled(get_options()) ? "1" : "0");
} else if (!strcmp(question, "accounting/hibernating")) {
- if (hibernate_state == HIBERNATE_STATE_DORMANT)
- *answer = tor_strdup("hard");
- else if (hibernate_state == HIBERNATE_STATE_LOWBANDWIDTH)
- *answer = tor_strdup("soft");
- else
- *answer = tor_strdup("awake");
+ *answer = tor_strdup(hibernate_state_to_string(hibernate_state));
+ tor_strlower(*answer);
} else if (!strcmp(question, "accounting/bytes")) {
tor_asprintf(answer, U64_FORMAT" "U64_FORMAT,
U64_PRINTF_ARG(n_bytes_read_in_interval),
@@ -1062,6 +1087,20 @@ getinfo_helper_accounting(control_connection_t *conn,
return 0;
}
+/**
+ * Helper function: called when the hibernation state changes, and sends a
+ * SERVER_STATUS event to notify interested controllers of the accounting
+ * state change.
+ */
+static void
+on_hibernate_state_change(hibernate_state_t prev_state)
+{
+ (void)prev_state; /* Should we do something with this? */
+ control_event_server_status(LOG_NOTICE,
+ "HIBERNATION_STATUS STATUS=%s",
+ hibernate_state_to_string(hibernate_state));
+}
+
#ifdef TOR_UNIT_TESTS
/**
* Manually change the hibernation state. Private; used only by the unit
diff --git a/src/or/include.am b/src/or/include.am
index 712ae18406..19f1a7fe0a 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -109,7 +109,7 @@ src_or_libtor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_or_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
-src_or_tor_LDADD = src/or/libtor.a src/common/libor.a \
+src_or_tor_LDADD = src/or/libtor.a src/common/libor.a src/common/libor-ctime.a \
src/common/libor-crypto.a $(LIBKECCAK_TINY) $(LIBDONNA) \
src/common/libor-event.a src/trunnel/libor-trunnel.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
@@ -121,6 +121,7 @@ src_or_tor_cov_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_or_tor_cov_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_or_tor_cov_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
src_or_tor_cov_LDADD = src/or/libtor-testing.a src/common/libor-testing.a \
+ src/common/libor-ctime-testing.a \
src/common/libor-crypto-testing.a $(LIBKECCAK_TINY) $(LIBDONNA) \
src/common/libor-event-testing.a src/trunnel/libor-trunnel-testing.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
diff --git a/src/or/main.c b/src/or/main.c
index a2cf5b1101..fba9799a60 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -1643,8 +1643,8 @@ rotate_x509_certificate_callback(time_t now, const or_options_t *options)
* TLS context. */
log_info(LD_GENERAL,"Rotating tls context.");
if (router_initialize_tls_context() < 0) {
- log_warn(LD_BUG, "Error reinitializing TLS context");
- tor_assert(0);
+ log_err(LD_BUG, "Error reinitializing TLS context");
+ tor_assert_unreached();
}
/* We also make sure to rotate the TLS connections themselves if they've
@@ -1917,7 +1917,7 @@ fetch_networkstatus_callback(time_t now, const or_options_t *options)
/* How often do we check whether we should download network status
* documents? */
- const int we_are_bootstrapping = networkstatus_consensus_is_boostrapping(
+ const int we_are_bootstrapping = networkstatus_consensus_is_bootstrapping(
now);
const int prefer_mirrors = !directory_fetches_from_authorities(
get_options());
@@ -2563,9 +2563,7 @@ run_main_loop_once(void)
return -1;
#endif
} else {
- if (ERRNO_IS_EINPROGRESS(e))
- log_warn(LD_BUG,
- "libevent call returned EINPROGRESS? Please report.");
+ tor_assert_nonfatal_once(! ERRNO_IS_EINPROGRESS(e));
log_debug(LD_NET,"libevent call interrupted.");
/* You can't trust the results of this poll(). Go back to the
* top of the big for loop. */
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index 185708a0c1..2975e7ebb4 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -819,7 +819,7 @@ update_consensus_networkstatus_downloads(time_t now)
{
int i;
const or_options_t *options = get_options();
- const int we_are_bootstrapping = networkstatus_consensus_is_boostrapping(
+ const int we_are_bootstrapping = networkstatus_consensus_is_bootstrapping(
now);
const int use_multi_conn =
networkstatus_consensus_can_use_multiple_directories(options);
@@ -875,12 +875,13 @@ update_consensus_networkstatus_downloads(time_t now)
resource,
DIR_CONN_STATE_CONNECTING);
- if (i == usable_consensus_flavor()
- && connect_consens_conn_count < consens_conn_count) {
+ /* If not all connections are "connecting", then some are
+ * downloading. We want to have at most one downloading at a time. */
+ if (connect_consens_conn_count < consens_conn_count) {
continue;
}
- /* Make multiple connections for a bootstrap consensus download */
+ /* Make multiple connections for a bootstrap consensus download. */
update_consensus_bootstrap_multiple_downloads(now, options,
we_are_bootstrapping);
} else {
@@ -954,7 +955,7 @@ update_consensus_bootstrap_attempt_downloads(
* connections.
* Only call when bootstrapping, and when we want to make additional
* connections. Only nodes that satisfy
- * networkstatus_consensus_can_use_multiple_directories make additonal
+ * networkstatus_consensus_can_use_multiple_directories make additional
* connections.
*/
static void
@@ -969,7 +970,7 @@ update_consensus_bootstrap_multiple_downloads(time_t now,
return;
}
- /* If we've managed to validate a usable consensus, don't make additonal
+ /* If we've managed to validate a usable consensus, don't make additional
* connections. */
if (!we_are_bootstrapping) {
return;
@@ -1277,7 +1278,7 @@ networkstatus_get_reasonably_live_consensus(time_t now, int flavor)
* only using the authorities and fallback directory mirrors to download the
* consensus flavour we'll use. */
int
-networkstatus_consensus_is_boostrapping(time_t now)
+networkstatus_consensus_is_bootstrapping(time_t now)
{
/* If we don't have a consensus, we must still be bootstrapping */
return !networkstatus_get_reasonably_live_consensus(
@@ -1327,7 +1328,7 @@ networkstatus_consensus_can_use_extra_fallbacks(const or_options_t *options)
* return value of this function to see if a client could make multiple
* bootstrap connections. Use
* networkstatus_consensus_can_use_multiple_directories()
- * and networkstatus_consensus_is_boostrapping(). */
+ * and networkstatus_consensus_is_bootstrapping(). */
int
networkstatus_consensus_has_excess_connections(void)
{
diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h
index 9bbb9a389e..f2f8af5c6b 100644
--- a/src/or/networkstatus.h
+++ b/src/or/networkstatus.h
@@ -70,7 +70,7 @@ MOCK_DECL(networkstatus_t *,networkstatus_get_latest_consensus_by_flavor,
networkstatus_t *networkstatus_get_live_consensus(time_t now);
networkstatus_t *networkstatus_get_reasonably_live_consensus(time_t now,
int flavor);
-int networkstatus_consensus_is_boostrapping(time_t now);
+int networkstatus_consensus_is_bootstrapping(time_t now);
int networkstatus_consensus_can_use_multiple_directories(
const or_options_t *options);
int networkstatus_consensus_can_use_extra_fallbacks(
diff --git a/src/or/onion.c b/src/or/onion.c
index d6ef3673dd..4bed7ae226 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -527,7 +527,7 @@ onion_skin_server_handshake(int type,
* <b>rend_authenticator_out</b> to the "KH" field that can be used to
* establish introduction points at this hop, and return 0. On failure,
* return -1, and set *msg_out to an error message if this is worth
- * complaining to the usre about. */
+ * complaining to the user about. */
int
onion_skin_client_handshake(int type,
const onion_handshake_state_t *handshake_state,
diff --git a/src/or/or.h b/src/or/or.h
index 6694bb4ece..86664d470d 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -784,7 +784,7 @@ typedef enum rend_auth_type_t {
/** Client-side configuration of authorization for a hidden service. */
typedef struct rend_service_authorization_t {
- char descriptor_cookie[REND_DESC_COOKIE_LEN];
+ uint8_t descriptor_cookie[REND_DESC_COOKIE_LEN];
char onion_address[REND_SERVICE_ADDRESS_LEN+1];
rend_auth_type_t auth_type;
} rend_service_authorization_t;
@@ -1294,21 +1294,26 @@ typedef struct connection_t {
time_t timestamp_created; /**< When was this connection_t created? */
- /* XXXX_IP6 make this IPv6-capable */
int socket_family; /**< Address family of this connection's socket. Usually
- * AF_INET, but it can also be AF_UNIX, or in the future
- * AF_INET6 */
- tor_addr_t addr; /**< IP of the other side of the connection; used to
- * identify routers, along with port. */
- uint16_t port; /**< If non-zero, port on the other end
- * of the connection. */
+ * AF_INET, but it can also be AF_UNIX, or AF_INET6 */
+ tor_addr_t addr; /**< IP that socket "s" is directly connected to;
+ * may be the IP address for a proxy or pluggable transport,
+ * see "address" for the address of the final destination.
+ */
+ uint16_t port; /**< If non-zero, port that socket "s" is directly connected
+ * to; may be the port for a proxy or pluggable transport,
+ * see "address" for the port at the final destination. */
uint16_t marked_for_close; /**< Should we close this conn on the next
* iteration of the main loop? (If true, holds
* the line number where this connection was
* marked.) */
const char *marked_for_close_file; /**< For debugging: in which file were
* we marked for close? */
- char *address; /**< FQDN (or IP) of the other end.
+ char *address; /**< FQDN (or IP) and port of the final destination for this
+ * connection; this is always the remote address, it is
+ * passed to a proxy or pluggable transport if one in use.
+ * See "addr" and "port" for the address that socket "s" is
+ * directly connected to.
* strdup into this, because free_connection() frees it. */
/** Another connection that's connected to this one in lieu of a socket. */
struct connection_t *linked_conn;
@@ -5034,7 +5039,7 @@ typedef enum {
/** Hidden-service side configuration of client authorization. */
typedef struct rend_authorized_client_t {
char *client_name;
- char descriptor_cookie[REND_DESC_COOKIE_LEN];
+ uint8_t descriptor_cookie[REND_DESC_COOKIE_LEN];
crypto_pk_t *client_key;
} rend_authorized_client_t;
diff --git a/src/or/policies.c b/src/or/policies.c
index f9718b6a95..2703d7edef 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -103,7 +103,7 @@ policy_expand_private(smartlist_t **policy)
if (tor_addr_parse_mask_ports(private_nets[i], 0,
&newpolicy.addr,
&newpolicy.maskbits, &port_min, &port_max)<0) {
- tor_assert(0);
+ tor_assert_unreached();
}
smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy));
}
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 609c45c71d..c119d86adf 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -1466,12 +1466,10 @@ rend_parse_service_authorization(const or_options_t *options,
strmap_t *parsed = strmap_new();
smartlist_t *sl = smartlist_new();
rend_service_authorization_t *auth = NULL;
- char descriptor_cookie_tmp[REND_DESC_COOKIE_LEN+2];
- char descriptor_cookie_base64ext[REND_DESC_COOKIE_LEN_BASE64+2+1];
+ char *err_msg = NULL;
for (line = options->HidServAuth; line; line = line->next) {
char *onion_address, *descriptor_cookie;
- int auth_type_val = 0;
auth = NULL;
SMARTLIST_FOREACH(sl, char *, c, tor_free(c););
smartlist_clear(sl);
@@ -1500,31 +1498,13 @@ rend_parse_service_authorization(const or_options_t *options,
}
/* Parse descriptor cookie. */
descriptor_cookie = smartlist_get(sl, 1);
- if (strlen(descriptor_cookie) != REND_DESC_COOKIE_LEN_BASE64) {
- log_warn(LD_CONFIG, "Authorization cookie has wrong length: '%s'",
- descriptor_cookie);
+ if (rend_auth_decode_cookie(descriptor_cookie, auth->descriptor_cookie,
+ &auth->auth_type, &err_msg) < 0) {
+ tor_assert(err_msg);
+ log_warn(LD_CONFIG, "%s", err_msg);
+ tor_free(err_msg);
goto err;
}
- /* Add trailing zero bytes (AA) to make base64-decoding happy. */
- tor_snprintf(descriptor_cookie_base64ext,
- REND_DESC_COOKIE_LEN_BASE64+2+1,
- "%sAA", descriptor_cookie);
- if (base64_decode(descriptor_cookie_tmp, sizeof(descriptor_cookie_tmp),
- descriptor_cookie_base64ext,
- strlen(descriptor_cookie_base64ext)) < 0) {
- log_warn(LD_CONFIG, "Decoding authorization cookie failed: '%s'",
- descriptor_cookie);
- goto err;
- }
- auth_type_val = (((uint8_t)descriptor_cookie_tmp[16]) >> 4) + 1;
- if (auth_type_val < 1 || auth_type_val > 2) {
- log_warn(LD_CONFIG, "Authorization cookie has unknown authorization "
- "type encoded.");
- goto err;
- }
- auth->auth_type = auth_type_val == 1 ? REND_BASIC_AUTH : REND_STEALTH_AUTH;
- memcpy(auth->descriptor_cookie, descriptor_cookie_tmp,
- REND_DESC_COOKIE_LEN);
if (strmap_get(parsed, auth->onion_address)) {
log_warn(LD_CONFIG, "Duplicate authorization for the same hidden "
"service.");
@@ -1547,8 +1527,6 @@ rend_parse_service_authorization(const or_options_t *options,
} else {
strmap_free(parsed, rend_service_authorization_strmap_item_free);
}
- memwipe(descriptor_cookie_tmp, 0, sizeof(descriptor_cookie_tmp));
- memwipe(descriptor_cookie_base64ext, 0, sizeof(descriptor_cookie_base64ext));
return res;
}
diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c
index 438fbc4d9a..56c49fee47 100644
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@ -211,7 +211,7 @@ rend_encode_v2_intro_points(char **encoded, rend_service_descriptor_t *desc)
goto done;
}
/* Assemble everything for this introduction point. */
- address = tor_dup_addr(&info->addr);
+ address = tor_addr_to_str_dup(&info->addr);
res = tor_snprintf(unenc + unenc_written, unenc_len - unenc_written,
"introduction-point %s\n"
"ip-address %s\n"
@@ -720,6 +720,22 @@ rend_valid_descriptor_id(const char *query)
return 0;
}
+/** Return true iff <b>client_name</b> is a syntactically valid name
+ * for rendezvous client authentication. */
+int
+rend_valid_client_name(const char *client_name)
+{
+ size_t len = strlen(client_name);
+ if (len < 1 || len > REND_CLIENTNAME_MAX_LEN) {
+ return 0;
+ }
+ if (strspn(client_name, REND_LEGAL_CLIENTNAME_CHARACTERS) != len) {
+ return 0;
+ }
+
+ return 1;
+}
+
/** Called when we get a rendezvous-related relay cell on circuit
* <b>circ</b>. Dispatch on rendezvous relay command. */
void
@@ -941,3 +957,114 @@ hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,
return smartlist_len(responsible_dirs) ? 0 : -1;
}
+/* Length of the 'extended' auth cookie used to encode auth type before
+ * base64 encoding. */
+#define REND_DESC_COOKIE_LEN_EXT (REND_DESC_COOKIE_LEN + 1)
+/* Length of the zero-padded auth cookie when base64 encoded. These two
+ * padding bytes always (A=) are stripped off of the returned cookie. */
+#define REND_DESC_COOKIE_LEN_EXT_BASE64 (REND_DESC_COOKIE_LEN_BASE64 + 2)
+
+/** Encode a client authorization descriptor cookie.
+ * The result of this function is suitable for use in the HidServAuth
+ * option. The trailing padding characters are removed, and the
+ * auth type is encoded into the cookie.
+ *
+ * Returns a new base64-encoded cookie. This function cannot fail.
+ * The caller is responsible for freeing the returned value.
+ */
+char *
+rend_auth_encode_cookie(const uint8_t *cookie_in, rend_auth_type_t auth_type)
+{
+ uint8_t extended_cookie[REND_DESC_COOKIE_LEN_EXT];
+ char *cookie_out = tor_malloc_zero(REND_DESC_COOKIE_LEN_EXT_BASE64 + 1);
+ int re;
+
+ tor_assert(cookie_in);
+
+ memcpy(extended_cookie, cookie_in, REND_DESC_COOKIE_LEN);
+ extended_cookie[REND_DESC_COOKIE_LEN] = ((int)auth_type - 1) << 4;
+ re = base64_encode(cookie_out, REND_DESC_COOKIE_LEN_EXT_BASE64 + 1,
+ (const char *) extended_cookie, REND_DESC_COOKIE_LEN_EXT,
+ 0);
+ tor_assert(re == REND_DESC_COOKIE_LEN_EXT_BASE64);
+
+ /* Remove the trailing 'A='. Auth type is encoded in the high bits
+ * of the last byte, so the last base64 character will always be zero
+ * (A). This is subtly different behavior from base64_encode_nopad. */
+ cookie_out[REND_DESC_COOKIE_LEN_BASE64] = '\0';
+ memwipe(extended_cookie, 0, sizeof(extended_cookie));
+ return cookie_out;
+}
+
+/** Decode a base64-encoded client authorization descriptor cookie.
+ * The descriptor_cookie can be truncated to REND_DESC_COOKIE_LEN_BASE64
+ * characters (as given to clients), or may include the two padding
+ * characters (as stored by the service).
+ *
+ * The result is stored in REND_DESC_COOKIE_LEN bytes of cookie_out.
+ * The rend_auth_type_t decoded from the cookie is stored in the
+ * optional auth_type_out parameter.
+ *
+ * Return 0 on success, or -1 on error. The caller is responsible for
+ * freeing the returned err_msg.
+ */
+int
+rend_auth_decode_cookie(const char *cookie_in, uint8_t *cookie_out,
+ rend_auth_type_t *auth_type_out, char **err_msg_out)
+{
+ uint8_t descriptor_cookie_decoded[REND_DESC_COOKIE_LEN_EXT + 1] = { 0 };
+ char descriptor_cookie_base64ext[REND_DESC_COOKIE_LEN_EXT_BASE64 + 1];
+ const char *descriptor_cookie = cookie_in;
+ char *err_msg = NULL;
+ int auth_type_val = 0;
+ int res = -1;
+ int decoded_len;
+
+ size_t len = strlen(descriptor_cookie);
+ if (len == REND_DESC_COOKIE_LEN_BASE64) {
+ /* Add a trailing zero byte to make base64-decoding happy. */
+ tor_snprintf(descriptor_cookie_base64ext,
+ sizeof(descriptor_cookie_base64ext),
+ "%sA=", descriptor_cookie);
+ descriptor_cookie = descriptor_cookie_base64ext;
+ } else if (len != REND_DESC_COOKIE_LEN_EXT_BASE64) {
+ tor_asprintf(&err_msg, "Authorization cookie has wrong length: %s",
+ escaped(cookie_in));
+ goto err;
+ }
+
+ decoded_len = base64_decode((char *) descriptor_cookie_decoded,
+ sizeof(descriptor_cookie_decoded),
+ descriptor_cookie,
+ REND_DESC_COOKIE_LEN_EXT_BASE64);
+ if (decoded_len != REND_DESC_COOKIE_LEN &&
+ decoded_len != REND_DESC_COOKIE_LEN_EXT) {
+ tor_asprintf(&err_msg, "Authorization cookie has invalid characters: %s",
+ escaped(cookie_in));
+ goto err;
+ }
+
+ if (auth_type_out) {
+ auth_type_val = (descriptor_cookie_decoded[REND_DESC_COOKIE_LEN] >> 4) + 1;
+ if (auth_type_val < 1 || auth_type_val > 2) {
+ tor_asprintf(&err_msg, "Authorization cookie type is unknown: %s",
+ escaped(cookie_in));
+ goto err;
+ }
+ *auth_type_out = auth_type_val == 1 ? REND_BASIC_AUTH : REND_STEALTH_AUTH;
+ }
+
+ memcpy(cookie_out, descriptor_cookie_decoded, REND_DESC_COOKIE_LEN);
+ res = 0;
+ err:
+ if (err_msg_out) {
+ *err_msg_out = err_msg;
+ } else {
+ tor_free(err_msg);
+ }
+ memwipe(descriptor_cookie_decoded, 0, sizeof(descriptor_cookie_decoded));
+ memwipe(descriptor_cookie_base64ext, 0, sizeof(descriptor_cookie_base64ext));
+ return res;
+}
+
+
diff --git a/src/or/rendcommon.h b/src/or/rendcommon.h
index d67552e405..88cf512f4a 100644
--- a/src/or/rendcommon.h
+++ b/src/or/rendcommon.h
@@ -45,6 +45,7 @@ void rend_intro_point_free(rend_intro_point_t *intro);
int rend_valid_service_id(const char *query);
int rend_valid_descriptor_id(const char *query);
+int rend_valid_client_name(const char *client_name);
int rend_encode_v2_descriptors(smartlist_t *descs_out,
rend_service_descriptor_t *desc, time_t now,
uint8_t period, rend_auth_type_t auth_type,
@@ -68,5 +69,13 @@ rend_data_t *rend_data_service_create(const char *onion_address,
const char *pk_digest,
const uint8_t *cookie,
rend_auth_type_t auth_type);
+
+char *rend_auth_encode_cookie(const uint8_t *cookie_in,
+ rend_auth_type_t auth_type);
+int rend_auth_decode_cookie(const char *cookie_in,
+ uint8_t *cookie_out,
+ rend_auth_type_t *auth_type_out,
+ char **err_msg_out);
+
#endif
diff --git a/src/or/rendmid.c b/src/or/rendmid.c
index a33ad92966..ca0ad7b0d4 100644
--- a/src/or/rendmid.c
+++ b/src/or/rendmid.c
@@ -309,7 +309,7 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request,
goto err;
}
- if (request_len != REND_COOKIE_LEN+DH_KEY_LEN+DIGEST_LEN) {
+ if (request_len < REND_COOKIE_LEN) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Rejecting RENDEZVOUS1 cell with bad length (%d) on circuit %u.",
(int)request_len, (unsigned)circ->p_circ_id);
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index 6f41f3b968..7426d8b35d 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -183,14 +183,15 @@ num_rend_services(void)
}
/** Helper: free storage held by a single service authorized client entry. */
-static void
+void
rend_authorized_client_free(rend_authorized_client_t *client)
{
if (!client)
return;
if (client->client_key)
crypto_pk_free(client->client_key);
- memwipe(client->client_name, 0, strlen(client->client_name));
+ if (client->client_name)
+ memwipe(client->client_name, 0, strlen(client->client_name));
tor_free(client->client_name);
memwipe(client->descriptor_cookie, 0, sizeof(client->descriptor_cookie));
tor_free(client);
@@ -671,27 +672,17 @@ rend_config_services(const or_options_t *options, int validate_only)
SMARTLIST_FOREACH_BEGIN(clients, const char *, client_name)
{
rend_authorized_client_t *client;
- size_t len = strlen(client_name);
- if (len < 1 || len > REND_CLIENTNAME_MAX_LEN) {
+ if (!rend_valid_client_name(client_name)) {
log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains an "
- "illegal client name: '%s'. Length must be "
- "between 1 and %d characters.",
+ "illegal client name: '%s'. Names must be "
+ "between 1 and %d characters and contain "
+ "only [A-Za-z0-9+_-].",
client_name, REND_CLIENTNAME_MAX_LEN);
SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp));
smartlist_free(clients);
rend_service_free(service);
return -1;
}
- if (strspn(client_name, REND_LEGAL_CLIENTNAME_CHARACTERS) != len) {
- log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains an "
- "illegal client name: '%s'. Valid "
- "characters are [A-Za-z0-9+_-].",
- client_name);
- SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp));
- smartlist_free(clients);
- rend_service_free(service);
- return -1;
- }
client = tor_malloc_zero(sizeof(rend_authorized_client_t));
client->client_name = tor_strdup(client_name);
smartlist_add(service->clients, client);
@@ -827,14 +818,17 @@ rend_config_services(const or_options_t *options, int validate_only)
return 0;
}
-/** Add the ephemeral service <b>pk</b>/<b>ports</b> if possible, with
+/** Add the ephemeral service <b>pk</b>/<b>ports</b> if possible, using
+ * client authorization <b>auth_type</b> and an optional list of
+ * rend_authorized_client_t in <b>auth_clients</b>, with
* <b>max_streams_per_circuit</b> streams allowed per rendezvous circuit,
* and circuit closure on max streams being exceeded set by
* <b>max_streams_close_circuit</b>.
*
- * Regardless of sucess/failure, callers should not touch pk/ports after
- * calling this routine, and may assume that correct cleanup has been done
- * on failure.
+ * Ownership of pk, ports, and auth_clients is passed to this routine.
+ * Regardless of success/failure, callers should not touch these values
+ * after calling this routine, and may assume that correct cleanup has
+ * been done on failure.
*
* Return an appropriate rend_service_add_ephemeral_status_t.
*/
@@ -843,6 +837,8 @@ rend_service_add_ephemeral(crypto_pk_t *pk,
smartlist_t *ports,
int max_streams_per_circuit,
int max_streams_close_circuit,
+ rend_auth_type_t auth_type,
+ smartlist_t *auth_clients,
char **service_id_out)
{
*service_id_out = NULL;
@@ -852,7 +848,8 @@ rend_service_add_ephemeral(crypto_pk_t *pk,
rend_service_t *s = tor_malloc_zero(sizeof(rend_service_t));
s->directory = NULL; /* This indicates the service is ephemeral. */
s->private_key = pk;
- s->auth_type = REND_NO_AUTH;
+ s->auth_type = auth_type;
+ s->clients = auth_clients;
s->ports = ports;
s->intro_period_started = time(NULL);
s->n_intro_points_wanted = NUM_INTRO_POINTS_DEFAULT;
@@ -868,6 +865,12 @@ rend_service_add_ephemeral(crypto_pk_t *pk,
rend_service_free(s);
return RSAE_BADVIRTPORT;
}
+ if (s->auth_type != REND_NO_AUTH &&
+ (!s->clients || smartlist_len(s->clients) == 0)) {
+ log_warn(LD_CONFIG, "At least one authorized client must be specified.");
+ rend_service_free(s);
+ return RSAE_BADAUTH;
+ }
/* Enforcing pk/id uniqueness should be done by rend_service_load_keys(), but
* it's not, see #14828.
@@ -1156,7 +1159,6 @@ rend_service_load_auth_keys(rend_service_t *s, const char *hfname)
strmap_t *parsed_clients = strmap_new();
FILE *cfile, *hfile;
open_file_t *open_cfile = NULL, *open_hfile = NULL;
- char extended_desc_cookie[REND_DESC_COOKIE_LEN+1];
char desc_cook_out[3*REND_DESC_COOKIE_LEN_BASE64+1];
char service_id[16+1];
char buf[1500];
@@ -1208,10 +1210,12 @@ rend_service_load_auth_keys(rend_service_t *s, const char *hfname)
memcpy(client->descriptor_cookie, parsed->descriptor_cookie,
REND_DESC_COOKIE_LEN);
} else {
- crypto_rand(client->descriptor_cookie, REND_DESC_COOKIE_LEN);
+ crypto_rand((char *) client->descriptor_cookie, REND_DESC_COOKIE_LEN);
}
+ /* For compatibility with older tor clients, this does not
+ * truncate the padding characters, unlike rend_auth_encode_cookie. */
if (base64_encode(desc_cook_out, 3*REND_DESC_COOKIE_LEN_BASE64+1,
- client->descriptor_cookie,
+ (char *) client->descriptor_cookie,
REND_DESC_COOKIE_LEN, 0) < 0) {
log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
goto err;
@@ -1272,6 +1276,8 @@ rend_service_load_auth_keys(rend_service_t *s, const char *hfname)
log_warn(LD_BUG, "Could not write client entry.");
goto err;
}
+ } else {
+ strlcpy(service_id, s->service_id, sizeof(service_id));
}
if (fputs(buf, cfile) < 0) {
@@ -1280,27 +1286,18 @@ rend_service_load_auth_keys(rend_service_t *s, const char *hfname)
goto err;
}
- /* Add line to hostname file. */
- if (s->auth_type == REND_BASIC_AUTH) {
- /* Remove == signs (newline has been removed above). */
- desc_cook_out[strlen(desc_cook_out)-2] = '\0';
- tor_snprintf(buf, sizeof(buf),"%s.onion %s # client: %s\n",
- s->service_id, desc_cook_out, client->client_name);
- } else {
- memcpy(extended_desc_cookie, client->descriptor_cookie,
- REND_DESC_COOKIE_LEN);
- extended_desc_cookie[REND_DESC_COOKIE_LEN] =
- ((int)s->auth_type - 1) << 4;
- if (base64_encode(desc_cook_out, 3*REND_DESC_COOKIE_LEN_BASE64+1,
- extended_desc_cookie,
- REND_DESC_COOKIE_LEN+1, 0) < 0) {
- log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
- goto err;
- }
- desc_cook_out[strlen(desc_cook_out)-2] = '\0'; /* Remove A=. */
- tor_snprintf(buf, sizeof(buf),"%s.onion %s # client: %s\n",
- service_id, desc_cook_out, client->client_name);
+ /* Add line to hostname file. This is not the same encoding as in
+ * client_keys. */
+ char *encoded_cookie = rend_auth_encode_cookie(client->descriptor_cookie,
+ s->auth_type);
+ if (!encoded_cookie) {
+ log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
+ goto err;
}
+ tor_snprintf(buf, sizeof(buf), "%s.onion %s # client: %s\n",
+ service_id, encoded_cookie, client->client_name);
+ memwipe(encoded_cookie, 0, strlen(encoded_cookie));
+ tor_free(encoded_cookie);
if (fputs(buf, hfile)<0) {
log_warn(LD_FS, "Could not append host entry to file: %s",
@@ -1332,7 +1329,6 @@ rend_service_load_auth_keys(rend_service_t *s, const char *hfname)
memwipe(buf, 0, sizeof(buf));
memwipe(desc_cook_out, 0, sizeof(desc_cook_out));
memwipe(service_id, 0, sizeof(service_id));
- memwipe(extended_desc_cookie, 0, sizeof(extended_desc_cookie));
return r;
}
diff --git a/src/or/rendservice.h b/src/or/rendservice.h
index 101b37e18d..4966cb0302 100644
--- a/src/or/rendservice.h
+++ b/src/or/rendservice.h
@@ -106,8 +106,11 @@ rend_service_port_config_t *rend_service_parse_port_config(const char *string,
char **err_msg_out);
void rend_service_port_config_free(rend_service_port_config_t *p);
+void rend_authorized_client_free(rend_authorized_client_t *client);
+
/** Return value from rend_service_add_ephemeral. */
typedef enum {
+ RSAE_BADAUTH = -5, /**< Invalid auth_type/auth_clients */
RSAE_BADVIRTPORT = -4, /**< Invalid VIRTPORT/TARGET(s) */
RSAE_ADDREXISTS = -3, /**< Onion address collision */
RSAE_BADPRIVKEY = -2, /**< Invalid public key */
@@ -118,6 +121,8 @@ rend_service_add_ephemeral_status_t rend_service_add_ephemeral(crypto_pk_t *pk,
smartlist_t *ports,
int max_streams_per_circuit,
int max_streams_close_circuit,
+ rend_auth_type_t auth_type,
+ smartlist_t *auth_clients,
char **service_id_out);
int rend_service_del_ephemeral(const char *service_id);
diff --git a/src/or/rephist.c b/src/or/rephist.c
index fe0ca91c25..b94ad29650 100644
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@ -3214,7 +3214,7 @@ rep_hist_free_all(void)
rep_hist_desc_stats_term();
total_descriptor_downloads = 0;
- tor_assert(rephist_total_alloc == 0);
- tor_assert(rephist_total_num == 0);
+ tor_assert_nonfatal(rephist_total_alloc == 0);
+ tor_assert_nonfatal_once(rephist_total_num == 0);
}
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index d40d704a1d..dcf80a3aa8 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -67,7 +67,7 @@ typedef struct cert_list_t cert_list_t;
/* static function prototypes */
static int compute_weighted_bandwidths(const smartlist_t *sl,
bandwidth_weight_rule_t rule,
- u64_dbl_t **bandwidths_out);
+ double **bandwidths_out);
static const routerstatus_t *router_pick_trusteddirserver_impl(
const smartlist_t *sourcelist, dirinfo_type_t auth,
int flags, int *n_busy_out);
@@ -1815,20 +1815,23 @@ dirserver_choose_by_weight(const smartlist_t *servers, double authority_weight)
{
int n = smartlist_len(servers);
int i;
- u64_dbl_t *weights;
+ double *weights_dbl;
+ uint64_t *weights_u64;
const dir_server_t *ds;
- weights = tor_calloc(n, sizeof(u64_dbl_t));
+ weights_dbl = tor_calloc(n, sizeof(double));
+ weights_u64 = tor_calloc(n, sizeof(uint64_t));
for (i = 0; i < n; ++i) {
ds = smartlist_get(servers, i);
- weights[i].dbl = ds->weight;
+ weights_dbl[i] = ds->weight;
if (ds->is_authority)
- weights[i].dbl *= authority_weight;
+ weights_dbl[i] *= authority_weight;
}
- scale_array_elements_to_u64(weights, n, NULL);
- i = choose_array_element_by_weight(weights, n);
- tor_free(weights);
+ scale_array_elements_to_u64(weights_u64, weights_dbl, n, NULL);
+ i = choose_array_element_by_weight(weights_u64, n);
+ tor_free(weights_dbl);
+ tor_free(weights_u64);
return (i < 0) ? NULL : smartlist_get(servers, i);
}
@@ -2090,7 +2093,8 @@ router_get_advertised_bandwidth_capped(const routerinfo_t *router)
* much of the range of uint64_t. If <b>total_out</b> is provided, set it to
* the sum of all elements in the array _before_ scaling. */
STATIC void
-scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
+scale_array_elements_to_u64(uint64_t *entries_out, const double *entries_in,
+ int n_entries,
uint64_t *total_out)
{
double total = 0.0;
@@ -2100,13 +2104,13 @@ scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
#define SCALE_TO_U64_MAX ((int64_t) (INT64_MAX / 4))
for (i = 0; i < n_entries; ++i)
- total += entries[i].dbl;
+ total += entries_in[i];
if (total > 0.0)
scale_factor = SCALE_TO_U64_MAX / total;
for (i = 0; i < n_entries; ++i)
- entries[i].u64 = tor_llround(entries[i].dbl * scale_factor);
+ entries_out[i] = tor_llround(entries_in[i] * scale_factor);
if (total_out)
*total_out = (uint64_t) total;
@@ -2114,35 +2118,20 @@ scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
#undef SCALE_TO_U64_MAX
}
-/** Time-invariant 64-bit greater-than; works on two integers in the range
- * (0,INT64_MAX). */
-#if SIZEOF_VOID_P == 8
-#define gt_i64_timei(a,b) ((a) > (b))
-#else
-static inline int
-gt_i64_timei(uint64_t a, uint64_t b)
-{
- int64_t diff = (int64_t) (b - a);
- int res = diff >> 63;
- return res & 1;
-}
-#endif
-
/** Pick a random element of <b>n_entries</b>-element array <b>entries</b>,
* choosing each element with a probability proportional to its (uint64_t)
* value, and return the index of that element. If all elements are 0, choose
* an index at random. Return -1 on error.
*/
STATIC int
-choose_array_element_by_weight(const u64_dbl_t *entries, int n_entries)
+choose_array_element_by_weight(const uint64_t *entries, int n_entries)
{
- int i, i_chosen=-1, n_chosen=0;
- uint64_t total_so_far = 0;
+ int i;
uint64_t rand_val;
uint64_t total = 0;
for (i = 0; i < n_entries; ++i)
- total += entries[i].u64;
+ total += entries[i];
if (n_entries < 1)
return -1;
@@ -2154,22 +2143,8 @@ choose_array_element_by_weight(const u64_dbl_t *entries, int n_entries)
rand_val = crypto_rand_uint64(total);
- for (i = 0; i < n_entries; ++i) {
- total_so_far += entries[i].u64;
- if (gt_i64_timei(total_so_far, rand_val)) {
- i_chosen = i;
- n_chosen++;
- /* Set rand_val to INT64_MAX rather than stopping the loop. This way,
- * the time we spend in the loop does not leak which element we chose. */
- rand_val = INT64_MAX;
- }
- }
- tor_assert(total_so_far == total);
- tor_assert(n_chosen == 1);
- tor_assert(i_chosen >= 0);
- tor_assert(i_chosen < n_entries);
-
- return i_chosen;
+ return select_array_member_cumulative_timei(
+ entries, n_entries, total, rand_val);
}
/** When weighting bridges, enforce these values as lower and upper
@@ -2221,17 +2196,21 @@ static const node_t *
smartlist_choose_node_by_bandwidth_weights(const smartlist_t *sl,
bandwidth_weight_rule_t rule)
{
- u64_dbl_t *bandwidths=NULL;
+ double *bandwidths_dbl=NULL;
+ uint64_t *bandwidths_u64=NULL;
- if (compute_weighted_bandwidths(sl, rule, &bandwidths) < 0)
+ if (compute_weighted_bandwidths(sl, rule, &bandwidths_dbl) < 0)
return NULL;
- scale_array_elements_to_u64(bandwidths, smartlist_len(sl), NULL);
+ bandwidths_u64 = tor_calloc(smartlist_len(sl), sizeof(uint64_t));
+ scale_array_elements_to_u64(bandwidths_u64, bandwidths_dbl,
+ smartlist_len(sl), NULL);
{
- int idx = choose_array_element_by_weight(bandwidths,
+ int idx = choose_array_element_by_weight(bandwidths_u64,
smartlist_len(sl));
- tor_free(bandwidths);
+ tor_free(bandwidths_dbl);
+ tor_free(bandwidths_u64);
return idx < 0 ? NULL : smartlist_get(sl, idx);
}
}
@@ -2244,14 +2223,14 @@ smartlist_choose_node_by_bandwidth_weights(const smartlist_t *sl,
static int
compute_weighted_bandwidths(const smartlist_t *sl,
bandwidth_weight_rule_t rule,
- u64_dbl_t **bandwidths_out)
+ double **bandwidths_out)
{
int64_t weight_scale;
double Wg = -1, Wm = -1, We = -1, Wd = -1;
double Wgb = -1, Wmb = -1, Web = -1, Wdb = -1;
uint64_t weighted_bw = 0;
guardfraction_bandwidth_t guardfraction_bw;
- u64_dbl_t *bandwidths;
+ double *bandwidths;
/* Can't choose exit and guard at same time */
tor_assert(rule == NO_WEIGHTING ||
@@ -2333,7 +2312,7 @@ compute_weighted_bandwidths(const smartlist_t *sl,
Web /= weight_scale;
Wdb /= weight_scale;
- bandwidths = tor_calloc(smartlist_len(sl), sizeof(u64_dbl_t));
+ bandwidths = tor_calloc(smartlist_len(sl), sizeof(double));
// Cycle through smartlist and total the bandwidth.
static int warned_missing_bw = 0;
@@ -2420,7 +2399,7 @@ compute_weighted_bandwidths(const smartlist_t *sl,
final_weight = weight*this_bw;
}
- bandwidths[node_sl_idx].dbl = final_weight + 0.5;
+ bandwidths[node_sl_idx] = final_weight + 0.5;
} SMARTLIST_FOREACH_END(node);
log_debug(LD_CIRC, "Generated weighted bandwidths for rule %s based "
@@ -2441,7 +2420,7 @@ double
frac_nodes_with_descriptors(const smartlist_t *sl,
bandwidth_weight_rule_t rule)
{
- u64_dbl_t *bandwidths = NULL;
+ double *bandwidths = NULL;
double total, present;
if (smartlist_len(sl) == 0)
@@ -2458,7 +2437,7 @@ frac_nodes_with_descriptors(const smartlist_t *sl,
total = present = 0.0;
SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
- const double bw = bandwidths[node_sl_idx].dbl;
+ const double bw = bandwidths[node_sl_idx];
total += bw;
if (node_has_descriptor(node))
present += bw;
@@ -4295,7 +4274,7 @@ dir_server_new(int is_authority,
return NULL;
if (!hostname)
- hostname_ = tor_dup_addr(addr);
+ hostname_ = tor_addr_to_str_dup(addr);
else
hostname_ = tor_strdup(hostname);
diff --git a/src/or/routerlist.h b/src/or/routerlist.h
index bc48c2087c..2166cf5114 100644
--- a/src/or/routerlist.h
+++ b/src/or/routerlist.h
@@ -217,17 +217,10 @@ int hex_digest_nickname_matches(const char *hexdigest,
const char *nickname, int is_named);
#ifdef ROUTERLIST_PRIVATE
-/** Helper type for choosing routers by bandwidth: contains a union of
- * double and uint64_t. Before we call scale_array_elements_to_u64, it holds
- * a double; after, it holds a uint64_t. */
-typedef union u64_dbl_t {
- uint64_t u64;
- double dbl;
-} u64_dbl_t;
-
-STATIC int choose_array_element_by_weight(const u64_dbl_t *entries,
+STATIC int choose_array_element_by_weight(const uint64_t *entries,
int n_entries);
-STATIC void scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
+STATIC void scale_array_elements_to_u64(uint64_t *entries_out,
+ const double *entries_in, int n_entries,
uint64_t *total_out);
STATIC const routerstatus_t *router_pick_directory_server_impl(
dirinfo_type_t auth, int flags,
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index cec10c8f24..600d55294f 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -5371,6 +5371,7 @@ rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr)
directory_token_t *tok;
const char *current_entry = NULL;
memarea_t *area = NULL;
+ char *err_msg = NULL;
if (!ckstr || strlen(ckstr) == 0)
return -1;
tokens = smartlist_new();
@@ -5380,8 +5381,6 @@ rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr)
current_entry = eat_whitespace(ckstr);
while (!strcmpstart(current_entry, "client-name ")) {
rend_authorized_client_t *parsed_entry;
- size_t len;
- char descriptor_cookie_tmp[REND_DESC_COOKIE_LEN+2];
/* Determine end of string. */
const char *eos = strstr(current_entry, "\nclient-name ");
if (!eos)
@@ -5410,12 +5409,10 @@ rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr)
tor_assert(tok == smartlist_get(tokens, 0));
tor_assert(tok->n_args == 1);
- len = strlen(tok->args[0]);
- if (len < 1 || len > 19 ||
- strspn(tok->args[0], REND_LEGAL_CLIENTNAME_CHARACTERS) != len) {
+ if (!rend_valid_client_name(tok->args[0])) {
log_warn(LD_CONFIG, "Illegal client name: %s. (Length must be "
- "between 1 and 19, and valid characters are "
- "[A-Za-z0-9+-_].)", tok->args[0]);
+ "between 1 and %d, and valid characters are "
+ "[A-Za-z0-9+-_].)", tok->args[0], REND_CLIENTNAME_MAX_LEN);
goto err;
}
/* Check if client name is duplicate. */
@@ -5437,23 +5434,13 @@ rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr)
/* Parse descriptor cookie. */
tok = find_by_keyword(tokens, C_DESCRIPTOR_COOKIE);
tor_assert(tok->n_args == 1);
- if (strlen(tok->args[0]) != REND_DESC_COOKIE_LEN_BASE64 + 2) {
- log_warn(LD_REND, "Descriptor cookie has illegal length: %s",
- escaped(tok->args[0]));
- goto err;
- }
- /* The size of descriptor_cookie_tmp needs to be REND_DESC_COOKIE_LEN+2,
- * because a base64 encoding of length 24 does not fit into 16 bytes in all
- * cases. */
- if (base64_decode(descriptor_cookie_tmp, sizeof(descriptor_cookie_tmp),
- tok->args[0], strlen(tok->args[0]))
- != REND_DESC_COOKIE_LEN) {
- log_warn(LD_REND, "Descriptor cookie contains illegal characters: "
- "%s", escaped(tok->args[0]));
+ if (rend_auth_decode_cookie(tok->args[0], parsed_entry->descriptor_cookie,
+ NULL, &err_msg) < 0) {
+ tor_assert(err_msg);
+ log_warn(LD_REND, "%s", err_msg);
+ tor_free(err_msg);
goto err;
}
- memcpy(parsed_entry->descriptor_cookie, descriptor_cookie_tmp,
- REND_DESC_COOKIE_LEN);
}
result = strmap_size(parsed_clients);
goto done;