Merge remote-tracking branch 'tor-github/pr/1864/head'

This commit is contained in:
Nick Mathewson 2020-04-29 19:16:40 -04:00
commit 49800cf539
27 changed files with 805 additions and 138 deletions

3
changes/bug33900 Normal file
View File

@ -0,0 +1,3 @@
o Minor bugfixes (IPv4, relay):
- Check for invalid zero IPv4 addresses and ports, when sending and
receiving extend cells. Fixes bug 33900; bugfix on 0.2.4.8-alpha.

5
changes/bug33917 Normal file
View File

@ -0,0 +1,5 @@
o Minor bugfixes (logging, testing):
- Make all of tor's assertion macros support the ALL_BUGS_ARE_FATAL and
DISABLE_ASSERTS_IN_UNIT_TESTS debugging modes. Implements these modes
for IF_BUG_ONCE(). (It used to log a non-fatal warning, regardless of
the debugging mode.) Fixes bug 33917; bugfix on 0.2.9.1-alpha.

12
changes/ticket33817 Normal file
View File

@ -0,0 +1,12 @@
o Major features (IPv6, relay):
- Relays may extend circuits over IPv6, if the relay has an IPv6 ORPort,
and the client supplies the other relay's IPv6 ORPort in the EXTEND2
cell. IPv6 extends will be used by the relay IPv6 ORPort self-tests in
33222. Closes ticket 33817.
- Consider IPv6-only EXTEND2 cells valid on relays. Log a protocol warning
if the IPv4 or IPv6 address is an internal address, and internal
addresses are not allowed. But continue to use the other address, if it
is valid. Closes ticket 33817.
- If a relay can extend over IPv4 and IPv6, it chooses between them
uniformly at random. Closes ticket 33817.
- Re-use existing IPv6 connections for circuit extends. Closes ticket 33817.

4
changes/ticket33901 Normal file
View File

@ -0,0 +1,4 @@
o Minor features (IPv6, relay):
- Allow clients and relays to send dual-stack and IPv6-only EXTEND2 cells.
Parse dual-stack and IPv6-only EXTEND2 cells on relays.
Closes ticket 33901.

View File

@ -305,7 +305,7 @@ problem function-size /src/lib/encoding/confline.c:parse_config_line_from_str_ve
problem function-size /src/lib/encoding/cstring.c:unescape_string() 108
problem function-size /src/lib/fs/dir.c:check_private_dir() 230
problem function-size /src/lib/math/prob_distr.c:sample_uniform_interval() 145
problem function-size /src/lib/net/address.c:tor_addr_parse_mask_ports() 194
problem function-size /src/lib/net/address.c:tor_addr_parse_mask_ports() 195
problem function-size /src/lib/net/address.c:tor_addr_compare_masked() 110
problem function-size /src/lib/net/inaddr.c:tor_inet_pton() 107
problem function-size /src/lib/net/socketpair.c:tor_ersatz_socketpair() 102

View File

@ -83,6 +83,13 @@
#include "core/or/cell_queue_st.h"
/* Static function prototypes */
static bool channel_matches_target_addr_for_extend(
channel_t *chan,
const tor_addr_t *target_ipv4_addr,
const tor_addr_t *target_ipv6_addr);
/* Global lists of channels */
/* All channel_t instances */
@ -2360,9 +2367,9 @@ channel_is_better(channel_t *a, channel_t *b)
* Get a channel to extend a circuit.
*
* Given the desired relay identity, pick a suitable channel to extend a
* circuit to the target address requsted by the client. Search for an
* existing channel for the requested endpoint. Make sure the channel is
* usable for new circuits, and matches the target address.
* circuit to the target IPv4 or IPv6 address requsted by the client. Search
* for an existing channel for the requested endpoint. Make sure the channel
* is usable for new circuits, and matches one of the target addresses.
*
* Try to return the best channel. But if there is no good channel, set
* *msg_out to a message describing the channel's state and our next action,
@ -2372,7 +2379,8 @@ channel_is_better(channel_t *a, channel_t *b)
MOCK_IMPL(channel_t *,
channel_get_for_extend,(const char *rsa_id_digest,
const ed25519_public_key_t *ed_id,
const tor_addr_t *target_addr,
const tor_addr_t *target_ipv4_addr,
const tor_addr_t *target_ipv6_addr,
const char **msg_out,
int *launch_out))
{
@ -2404,11 +2412,15 @@ channel_get_for_extend,(const char *rsa_id_digest,
continue;
}
const bool matches_target =
channel_matches_target_addr_for_extend(chan,
target_ipv4_addr,
target_ipv6_addr);
/* Never return a non-open connection. */
if (!CHANNEL_IS_OPEN(chan)) {
/* If the address matches, don't launch a new connection for this
* circuit. */
if (channel_matches_target_addr_for_extend(chan, target_addr))
if (matches_target)
++n_inprogress_goodaddr;
continue;
}
@ -2419,22 +2431,21 @@ channel_get_for_extend,(const char *rsa_id_digest,
continue;
}
/* Never return a non-canonical connection using a recent link protocol
* if the address is not what we wanted.
/* If the connection is using a recent link protocol, only return canonical
* connections, when the address is one of the addresses we wanted.
*
* The channel_is_canonical_is_reliable() function asks the lower layer
* if we should trust channel_is_canonical(). The below is from the
* comments of the old circuit_or_get_for_extend() and applies when
* if we should trust channel_is_canonical(). It only applies when
* the lower-layer transport is channel_tls_t.
*
* (For old link protocols, we can't rely on is_canonical getting
* For old link protocols, we can't rely on is_canonical getting
* set properly if we're talking to the right address, since we might
* have an out-of-date descriptor, and we will get no NETINFO cell to
* tell us about the right address.)
* tell us about the right address.
*/
if (!channel_is_canonical(chan) &&
channel_is_canonical_is_reliable(chan) &&
!channel_matches_target_addr_for_extend(chan, target_addr)) {
!matches_target) {
++n_noncanonical;
continue;
}
@ -3297,20 +3308,33 @@ channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info)
}
/**
* Check if a channel matches a given target address; return true iff we do.
* Check if a channel matches the given target IPv4 or IPv6 addresses.
* If either address matches, return true. If neither address matches,
* return false.
*
* Both addresses can't be NULL.
*
* This function calls into the lower layer and asks if this channel thinks
* it matches a given target address for circuit extension purposes.
* it matches the target addresses for circuit extension purposes.
*/
int
static bool
channel_matches_target_addr_for_extend(channel_t *chan,
const tor_addr_t *target)
const tor_addr_t *target_ipv4_addr,
const tor_addr_t *target_ipv6_addr)
{
tor_assert(chan);
tor_assert(chan->matches_target);
tor_assert(target);
return chan->matches_target(chan, target);
IF_BUG_ONCE(!target_ipv4_addr && !target_ipv6_addr)
return false;
if (target_ipv4_addr && chan->matches_target(chan, target_ipv4_addr))
return true;
if (target_ipv6_addr && chan->matches_target(chan, target_ipv6_addr))
return true;
return false;
}
/**

View File

@ -661,7 +661,8 @@ channel_t * channel_connect(const tor_addr_t *addr, uint16_t port,
MOCK_DECL(channel_t *, channel_get_for_extend,(
const char *rsa_id_digest,
const struct ed25519_public_key_t *ed_id,
const tor_addr_t *target_addr,
const tor_addr_t *target_ipv4_addr,
const tor_addr_t *target_ipv6_addr,
const char **msg_out,
int *launch_out));
@ -737,8 +738,6 @@ int channel_is_outgoing(channel_t *chan);
void channel_mark_client(channel_t *chan);
void channel_clear_client(channel_t *chan);
int channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info);
int channel_matches_target_addr_for_extend(channel_t *chan,
const tor_addr_t *target);
unsigned int channel_num_circuits(channel_t *chan);
MOCK_DECL(void,channel_set_circid_type,(channel_t *chan,
crypto_pk_t *identity_rcvd,

View File

@ -1669,7 +1669,7 @@ tor_addr_from_netinfo_addr(tor_addr_t *tor_addr,
} else if (type == NETINFO_ADDR_TYPE_IPV6 && len == 16) {
const uint8_t *ipv6_bytes = netinfo_addr_getconstarray_addr_ipv6(
netinfo_addr);
tor_addr_from_ipv6_bytes(tor_addr, (const char *)ipv6_bytes);
tor_addr_from_ipv6_bytes(tor_addr, ipv6_bytes);
} else {
log_fn(LOG_PROTOCOL_WARN, LD_OR, "Cannot read address from NETINFO "
"- wrong type/length.");

View File

@ -559,11 +559,17 @@ circuit_handle_first_hop(origin_circuit_t *circ)
fmt_addrport(&firsthop->extend_info->addr,
firsthop->extend_info->port));
n_chan = channel_get_for_extend(firsthop->extend_info->identity_digest,
&firsthop->extend_info->ed_identity,
&firsthop->extend_info->addr,
&msg,
&should_launch);
/* We'll cleanup this code in #33220, when we add an IPv6 address to
* extend_info_t. */
const bool addr_is_ipv4 =
(tor_addr_family(&firsthop->extend_info->addr) == AF_INET);
n_chan = channel_get_for_extend(
firsthop->extend_info->identity_digest,
&firsthop->extend_info->ed_identity,
addr_is_ipv4 ? &firsthop->extend_info->addr : NULL,
addr_is_ipv4 ? NULL : &firsthop->extend_info->addr,
&msg,
&should_launch);
if (!n_chan) {
/* not currently connected in a useful way. */

View File

@ -3531,7 +3531,7 @@ connection_ap_handshake_socks_resolved,(entry_connection_t *conn,
}
} else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) {
tor_addr_t a;
tor_addr_from_ipv6_bytes(&a, (char*)answer);
tor_addr_from_ipv6_bytes(&a, answer);
if (! tor_addr_is_null(&a)) {
client_dns_set_addressmap(conn,
conn->socks_request->address, &a,

View File

@ -240,11 +240,21 @@ created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in)
static int
check_extend_cell(const extend_cell_t *cell)
{
const bool is_extend2 = (cell->cell_type == RELAY_COMMAND_EXTEND2);
if (tor_digest_is_zero((const char*)cell->node_id))
return -1;
/* We don't currently allow EXTEND2 cells without an IPv4 address */
if (tor_addr_family(&cell->orport_ipv4.addr) == AF_UNSPEC)
return -1;
if (!tor_addr_port_is_valid_ap(&cell->orport_ipv4, 0)) {
/* EXTEND cells must have an IPv4 address. */
if (!is_extend2) {
return -1;
}
/* EXTEND2 cells must have at least one IP address.
* It can be IPv4 or IPv6. */
if (!tor_addr_port_is_valid_ap(&cell->orport_ipv6, 0)) {
return -1;
}
}
if (cell->create_cell.cell_type == CELL_CREATE) {
if (cell->cell_type != RELAY_COMMAND_EXTEND)
return -1;
@ -343,7 +353,7 @@ extend_cell_from_extend2_cell_body(extend_cell_t *cell_out,
continue;
found_ipv6 = 1;
tor_addr_from_ipv6_bytes(&cell_out->orport_ipv6.addr,
(const char *)ls->un_ipv6_addr);
ls->un_ipv6_addr);
cell_out->orport_ipv6.port = ls->un_ipv6_port;
break;
case LS_LEGACY_ID:
@ -364,7 +374,12 @@ extend_cell_from_extend2_cell_body(extend_cell_t *cell_out,
}
}
if (!found_rsa_id || !found_ipv4) /* These are mandatory */
/* EXTEND2 cells must have an RSA ID */
if (!found_rsa_id)
return -1;
/* EXTEND2 cells must have at least one IP address */
if (!found_ipv4 && !found_ipv6)
return -1;
return create_cell_from_create2_cell_body(&cell_out->create_cell,
@ -620,12 +635,13 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out,
break;
case RELAY_COMMAND_EXTEND2:
{
uint8_t n_specifiers = 2;
uint8_t n_specifiers = 1;
*command_out = RELAY_COMMAND_EXTEND2;
extend2_cell_body_t *cell = extend2_cell_body_new();
link_specifier_t *ls;
{
/* IPv4 specifier first. */
if (tor_addr_port_is_valid_ap(&cell_in->orport_ipv4, 0)) {
/* Maybe IPv4 specifier first. */
++n_specifiers;
ls = link_specifier_new();
extend2_cell_body_add_ls(cell, ls);
ls->ls_type = LS_IPV4;
@ -651,6 +667,17 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out,
ls->ls_len = 32;
memcpy(ls->un_ed25519_id, cell_in->ed_pubkey.pubkey, 32);
}
if (tor_addr_port_is_valid_ap(&cell_in->orport_ipv6, 0)) {
/* Then maybe IPv6 specifier. */
++n_specifiers;
ls = link_specifier_new();
extend2_cell_body_add_ls(cell, ls);
ls->ls_type = LS_IPV6;
ls->ls_len = 18;
tor_addr_copy_ipv6_bytes(ls->un_ipv6_addr,
&cell_in->orport_ipv6.addr);
ls->un_ipv6_port = cell_in->orport_ipv6.port;
}
cell->n_spec = n_specifiers;
/* Now, the handshake */

View File

@ -167,7 +167,7 @@ policy_expand_unspec(smartlist_t **policy)
}
tor_addr_from_ipv4h(&newpolicy_ipv4.addr, 0);
tor_addr_from_ipv6_bytes(&newpolicy_ipv6.addr,
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
(const uint8_t *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy_ipv4));
smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy_ipv6));
addr_policy_free(p);
@ -1005,7 +1005,7 @@ fascist_firewall_choose_address_ls(const smartlist_t *lspecs,
* direct connection. */
if (have_v6) continue;
tor_addr_from_ipv6_bytes(&addr_v6,
(const char *) link_specifier_getconstarray_un_ipv6_addr(ls));
link_specifier_getconstarray_un_ipv6_addr(ls));
port_v6 = link_specifier_get_un_ipv6_port(ls);
have_v6 = 1;
break;

View File

@ -867,7 +867,7 @@ connection_ap_process_end_not_open(
ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+5));
} else if (rh->length == 17 || rh->length == 21) {
tor_addr_from_ipv6_bytes(&addr,
(char*)(cell->payload+RELAY_HEADER_SIZE+1));
(cell->payload+RELAY_HEADER_SIZE+1));
if (rh->length == 21)
ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+17));
}
@ -1092,7 +1092,7 @@ connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
return -1;
if (get_uint8(payload + 4) != 6)
return -1;
tor_addr_from_ipv6_bytes(addr_out, (char*)(payload + 5));
tor_addr_from_ipv6_bytes(addr_out, (payload + 5));
bytes = ntohl(get_uint32(payload + 21));
if (bytes <= INT32_MAX)
*ttl_out = (int) bytes;
@ -1165,7 +1165,7 @@ resolved_cell_parse(const cell_t *cell, const relay_header_t *rh,
if (answer_len != 16)
goto err;
addr = tor_malloc_zero(sizeof(*addr));
tor_addr_from_ipv6_bytes(&addr->addr, (const char*) cp);
tor_addr_from_ipv6_bytes(&addr->addr, cp);
cp += 16;
addr->ttl = ntohl(get_uint32(cp));
cp += 4;
@ -3217,7 +3217,7 @@ decode_address_from_payload(tor_addr_t *addr_out, const uint8_t *payload,
case RESOLVED_TYPE_IPV6:
if (payload[1] != 16)
return NULL;
tor_addr_from_ipv6_bytes(addr_out, (char*)(payload+2));
tor_addr_from_ipv6_bytes(addr_out, (payload+2));
break;
default:
tor_addr_make_unspec(addr_out);

View File

@ -587,9 +587,8 @@ parse_socks5_client_request(const uint8_t *raw_data, socks_request_t *req,
strlcpy(req->address, hostname, sizeof(req->address));
} break;
case 4: {
const char *ipv6 =
(const char *)socks5_client_request_getarray_dest_addr_ipv6(
trunnel_req);
const uint8_t *ipv6 =
socks5_client_request_getarray_dest_addr_ipv6(trunnel_req);
tor_addr_from_ipv6_bytes(&destaddr, ipv6);
tor_addr_to_str(req->address, &destaddr, sizeof(req->address), 1);

View File

@ -902,7 +902,7 @@ get_random_virtual_addr(const virtual_addr_conf_t *conf, tor_addr_t *addr_out)
}
if (ipv6)
tor_addr_from_ipv6_bytes(addr_out, (char*) bytes);
tor_addr_from_ipv6_bytes(addr_out, bytes);
else
tor_addr_from_ipv4n(addr_out, get_uint32(bytes));

View File

@ -18,6 +18,8 @@
#include "orconfig.h"
#include "feature/relay/circuitbuild_relay.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "core/or/or.h"
#include "app/config/config.h"
@ -36,6 +38,7 @@
#include "feature/nodelist/nodelist.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
#include "feature/relay/selftest.h"
@ -119,6 +122,49 @@ circuit_extend_add_ed25519_helper(struct extend_cell_t *ec)
return 0;
}
/* Check if the address and port in the tor_addr_port_t <b>ap</b> are valid,
* and are allowed by the current ExtendAllowPrivateAddresses config.
*
* If they are valid, return true.
* Otherwise, if they are invalid, return false.
*
* If <b>log_zero_addrs</b> is true, log warnings about zero addresses at
* <b>log_level</b>. If <b>log_internal_addrs</b> is true, log warnings about
* internal addresses at <b>log_level</b>.
*/
static bool
circuit_extend_addr_port_is_valid(const struct tor_addr_port_t *ap,
bool log_zero_addrs, bool log_internal_addrs,
int log_level)
{
/* It's safe to print the family. But we don't want to print the address,
* unless specifically configured to do so. (Zero addresses aren't sensitive,
* But some internal addresses might be.)*/
if (!tor_addr_port_is_valid_ap(ap, 0)) {
if (log_zero_addrs) {
log_fn(log_level, LD_PROTOCOL,
"Client asked me to extend to a zero destination port or "
"%s address '%s'.",
fmt_addr_family(&ap->addr), safe_str(fmt_addrport_ap(ap)));
}
return false;
}
if (tor_addr_is_internal(&ap->addr, 0) &&
!get_options()->ExtendAllowPrivateAddresses) {
if (log_internal_addrs) {
log_fn(log_level, LD_PROTOCOL,
"Client asked me to extend to a private %s address '%s'.",
fmt_addr_family(&ap->addr),
safe_str(fmt_and_decorate_addr(&ap->addr)));
}
return false;
}
return true;
}
/* Before replying to an extend cell, check the link specifiers in the extend
* cell <b>ec</b>, which was received on the circuit <b>circ</b>.
*
@ -139,17 +185,28 @@ circuit_extend_lspec_valid_helper(const struct extend_cell_t *ec,
return -1;
}
if (!ec->orport_ipv4.port || tor_addr_is_null(&ec->orport_ipv4.addr)) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Client asked me to extend to zero destination port or addr.");
return -1;
}
if (tor_addr_is_internal(&ec->orport_ipv4.addr, 0) &&
!get_options()->ExtendAllowPrivateAddresses) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Client asked me to extend to a private address.");
/* Check the addresses, without logging */
const int ipv4_valid = circuit_extend_addr_port_is_valid(&ec->orport_ipv4,
false, false, 0);
const int ipv6_valid = circuit_extend_addr_port_is_valid(&ec->orport_ipv6,
false, false, 0);
/* We need at least one valid address */
if (!ipv4_valid && !ipv6_valid) {
/* Now, log the invalid addresses at protocol warning level */
circuit_extend_addr_port_is_valid(&ec->orport_ipv4,
true, true, LOG_PROTOCOL_WARN);
circuit_extend_addr_port_is_valid(&ec->orport_ipv6,
true, true, LOG_PROTOCOL_WARN);
/* And fail */
return -1;
} else if (!ipv4_valid) {
/* Always log unexpected internal addresses, but go on to use the other
* valid address */
circuit_extend_addr_port_is_valid(&ec->orport_ipv4,
false, true, LOG_PROTOCOL_WARN);
} else if (!ipv6_valid) {
circuit_extend_addr_port_is_valid(&ec->orport_ipv6,
false, true, LOG_PROTOCOL_WARN);
}
IF_BUG_ONCE(circ->magic != OR_CIRCUIT_MAGIC) {
@ -183,10 +240,64 @@ circuit_extend_lspec_valid_helper(const struct extend_cell_t *ec,
return 0;
}
/* If possible, return a supported, non-NULL IP address.
*
* If both addresses are supported and non-NULL, choose one uniformly at
* random.
*
* If we have an IPv6-only extend, but IPv6 is not supported, returns NULL.
* If both addresses are NULL, also returns NULL. */
STATIC const tor_addr_port_t *
circuit_choose_ip_ap_for_extend(const tor_addr_port_t *ipv4_ap,
const tor_addr_port_t *ipv6_ap)
{
const bool ipv6_supported = router_can_extend_over_ipv6(get_options());
/* If IPv6 is not supported, we can't use the IPv6 address. */
if (!ipv6_supported) {
ipv6_ap = NULL;
}
/* If there is no IPv6 address, IPv4 is always supported.
* Until clients include IPv6 ORPorts, and most relays support IPv6,
* this is the most common case. */
if (!ipv6_ap) {
return ipv4_ap;
}
/* If there is no IPv4 address, return the (possibly NULL) IPv6 address. */
if (!ipv4_ap) {
return ipv6_ap;
}
/* Now we have an IPv4 and an IPv6 address, and IPv6 is supported.
* So make an IPv6 connection at random, with probability 1 in N.
* 1 means "always IPv6 (and no IPv4)"
* 2 means "equal probability of IPv4 or IPv6"
* ... (and so on) ...
* (UINT_MAX - 1) means "almost always IPv4 (and almost never IPv6)"
* To disable IPv6, set ipv6_supported to 0.
*/
#define IPV6_CONNECTION_ONE_IN_N 2
bool choose_ipv6 = crypto_fast_rng_one_in_n(get_thread_fast_rng(),
IPV6_CONNECTION_ONE_IN_N);
if (choose_ipv6) {
return ipv6_ap;
} else {
return ipv4_ap;
}
}
/* When there is no open channel for an extend cell <b>ec</b>, set up the
* circuit <b>circ</b> to wait for a new connection. If <b>should_launch</b>
* is true, open a new connection. (Otherwise, we are already waiting for a
* new connection to the same relay.)
* circuit <b>circ</b> to wait for a new connection.
*
* If <b>should_launch</b> is true, open a new connection. (Otherwise, we are
* already waiting for a new connection to the same relay.)
*
* Check if IPv6 extends are supported by our current configuration. If they
* are, new connections may be made over IPv4 or IPv6. (IPv4 connections are
* always supported.)
*/
STATIC void
circuit_open_connection_for_extend(const struct extend_cell_t *ec,
@ -205,13 +316,36 @@ circuit_open_connection_for_extend(const struct extend_cell_t *ec,
return;
}
/* Check the addresses, without logging */
const int ipv4_valid = circuit_extend_addr_port_is_valid(&ec->orport_ipv4,
false, false, 0);
const int ipv6_valid = circuit_extend_addr_port_is_valid(&ec->orport_ipv6,
false, false, 0);
IF_BUG_ONCE(!ipv4_valid && !ipv6_valid) {
/* circuit_extend_lspec_valid_helper() should have caught this */
circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
return;
}
const tor_addr_port_t *chosen_ap = circuit_choose_ip_ap_for_extend(
ipv4_valid ? &ec->orport_ipv4 : NULL,
ipv6_valid ? &ec->orport_ipv6 : NULL);
if (!chosen_ap) {
/* An IPv6-only extend, but IPv6 is not supported */
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Received IPv6-only extend, but we don't have an IPv6 ORPort.");
circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
return;
}
circ->n_hop = extend_info_new(NULL /*nickname*/,
(const char*)ec->node_id,
&ec->ed_pubkey,
NULL, /*onion_key*/
NULL, /*curve25519_key*/
&ec->orport_ipv4.addr,
ec->orport_ipv4.port);
&chosen_ap->addr,
chosen_ap->port);
circ->n_chan_create_cell = tor_memdup(&ec->create_cell,
sizeof(ec->create_cell));
@ -220,10 +354,11 @@ circuit_open_connection_for_extend(const struct extend_cell_t *ec,
if (should_launch) {
/* we should try to open a connection */
channel_t *n_chan = channel_connect_for_circuit(&ec->orport_ipv4.addr,
ec->orport_ipv4.port,
(const char*)ec->node_id,
&ec->ed_pubkey);
channel_t *n_chan = channel_connect_for_circuit(
&circ->n_hop->addr,
circ->n_hop->port,
circ->n_hop->identity_digest,
&circ->n_hop->ed_identity);
if (!n_chan) {
log_info(LD_CIRC,"Launching n_chan failed. Closing circuit.");
circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
@ -277,16 +412,31 @@ circuit_extend(struct cell_t *cell, struct circuit_t *circ)
if (circuit_extend_lspec_valid_helper(&ec, circ) < 0)
return -1;
/* Check the addresses, without logging */
const int ipv4_valid = circuit_extend_addr_port_is_valid(&ec.orport_ipv4,
false, false, 0);
const int ipv6_valid = circuit_extend_addr_port_is_valid(&ec.orport_ipv6,
false, false, 0);
IF_BUG_ONCE(!ipv4_valid && !ipv6_valid) {
/* circuit_extend_lspec_valid_helper() should have caught this */
return -1;
}
n_chan = channel_get_for_extend((const char*)ec.node_id,
&ec.ed_pubkey,
&ec.orport_ipv4.addr,
ipv4_valid ? &ec.orport_ipv4.addr : NULL,
ipv6_valid ? &ec.orport_ipv6.addr : NULL,
&msg,
&should_launch);
if (!n_chan) {
log_debug(LD_CIRC|LD_OR,"Next router (%s): %s.",
fmt_addrport(&ec.orport_ipv4.addr,ec.orport_ipv4.port),
msg?msg:"????");
/* We can't use fmt_addr*() twice in the same function call,
* because it uses a static buffer. */
log_debug(LD_CIRC|LD_OR, "Next router IPv4 (%s): %s.",
fmt_addrport_ap(&ec.orport_ipv4),
msg ? msg : "????");
log_debug(LD_CIRC|LD_OR, "Next router IPv6 (%s).",
fmt_addrport_ap(&ec.orport_ipv6));
circuit_open_connection_for_extend(&ec, circ, should_launch);

View File

@ -75,6 +75,9 @@ STATIC int circuit_extend_state_valid_helper(const struct circuit_t *circ);
STATIC int circuit_extend_add_ed25519_helper(struct extend_cell_t *ec);
STATIC int circuit_extend_lspec_valid_helper(const struct extend_cell_t *ec,
const struct circuit_t *circ);
STATIC const tor_addr_port_t * circuit_choose_ip_ap_for_extend(
const tor_addr_port_t *ipv4_ap,
const tor_addr_port_t *ipv6_ap);
STATIC void circuit_open_connection_for_extend(const struct extend_cell_t *ec,
struct circuit_t *circ,
int should_launch);

View File

@ -1469,7 +1469,7 @@ router_get_advertised_ipv6_or_ap(const or_options_t *options,
AF_INET6);
if (!addr || port == 0) {
log_info(LD_CONFIG, "There is no advertised IPv6 ORPort.");
log_debug(LD_CONFIG, "There is no advertised IPv6 ORPort.");
return;
}
@ -1490,6 +1490,24 @@ router_get_advertised_ipv6_or_ap(const or_options_t *options,
ipv6_ap_out->port = port;
}
/** Returns true if this router has an advertised IPv6 ORPort. */
bool
router_has_advertised_ipv6_orport(const or_options_t *options)
{
tor_addr_port_t ipv6_ap;
router_get_advertised_ipv6_or_ap(options, &ipv6_ap);
return tor_addr_port_is_valid_ap(&ipv6_ap, 0);
}
/** Returns true if this router has an advertised IPv6 ORPort. */
MOCK_IMPL(bool,
router_can_extend_over_ipv6,(const or_options_t *options))
{
/* We might add some extra checks here, such as ExtendAllowIPv6Addresses
* from ticket 33818. */
return router_has_advertised_ipv6_orport(options);
}
/** Return the port that we should advertise as our DirPort;
* this is one of three possibilities:
* The one that is passed as <b>dirport</b> if the DirPort option is 0, or

View File

@ -68,6 +68,8 @@ uint16_t router_get_active_listener_port_by_type_af(int listener_type,
uint16_t router_get_advertised_or_port(const or_options_t *options);
void router_get_advertised_ipv6_or_ap(const or_options_t *options,
tor_addr_port_t *ipv6_ap_out);
bool router_has_advertised_ipv6_orport(const or_options_t *options);
MOCK_DECL(bool, router_can_extend_over_ipv6,(const or_options_t *options));
uint16_t router_get_advertised_or_port_by_af(const or_options_t *options,
sa_family_t family);
uint16_t router_get_advertised_dir_port(const or_options_t *options,

View File

@ -142,6 +142,8 @@
#define ALL_BUGS_ARE_FATAL
#endif
/** Define ALL_BUGS_ARE_FATAL if you want Tor to crash when any problem comes
* up, so you can get a coredump and track things down. */
#ifdef ALL_BUGS_ARE_FATAL
#define tor_assert_nonfatal_unreached() tor_assert(0)
#define tor_assert_nonfatal(cond) tor_assert((cond))
@ -154,6 +156,9 @@
(tor_assertion_failed_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",NULL), \
tor_abort_(), 1) \
: 0)
#ifndef COCCI
#define IF_BUG_ONCE(cond) if (BUG(cond))
#endif
#elif defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS)
#define tor_assert_nonfatal_unreached() STMT_NIL
#define tor_assert_nonfatal(cond) ((void)(cond))
@ -164,6 +169,9 @@
#define tor_assert_nonfatal_unreached_once() STMT_NIL
#define tor_assert_nonfatal_once(cond) ((void)(cond))
#define BUG(cond) (ASSERT_PREDICT_UNLIKELY_(cond) ? 1 : 0)
#ifndef COCCI
#define IF_BUG_ONCE(cond) if (BUG(cond))
#endif
#else /* Normal case, !ALL_BUGS_ARE_FATAL, !DISABLE_ASSERTS_IN_UNIT_TESTS */
#define tor_assert_nonfatal_unreached() STMT_BEGIN \
tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 0, NULL); \
@ -200,7 +208,6 @@
(ASSERT_PREDICT_UNLIKELY_(cond) ? \
(tor_bug_occurred_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",0,NULL),1) \
: 0)
#endif /* defined(ALL_BUGS_ARE_FATAL) || ... */
#ifndef COCCI
#ifdef __GNUC__
@ -232,7 +239,7 @@
#define IF_BUG_ONCE_VARNAME__(a) \
IF_BUG_ONCE_VARNAME_(a)
/** This macro behaves as 'if (bug(x))', except that it only logs its
/** This macro behaves as 'if (BUG(x))', except that it only logs its
* warning once, no matter how many times it triggers.
*/
@ -240,9 +247,15 @@
IF_BUG_ONCE__(ASSERT_PREDICT_UNLIKELY_(cond), \
IF_BUG_ONCE_VARNAME__(__LINE__))
/** Define this if you want Tor to crash when any problem comes up,
* so you can get a coredump and track things down. */
// #define tor_fragile_assert() tor_assert_unreached(0)
#endif /* defined(ALL_BUGS_ARE_FATAL) || ... */
/** In older code, we used tor_fragile_assert() to mark optional failure
* points. At these points, we could make some debug builds fail.
* (But release builds would continue.)
*
* To get the same behaviour in recent tor versions, define
* ALL_BUGS_ARE_FATAL, and use any non-fatal assertion or *BUG() macro.
*/
#define tor_fragile_assert() tor_assert_nonfatal_unreached_once()
void tor_assertion_failed_(const char *fname, unsigned int line,

View File

@ -608,7 +608,8 @@ tor_addr_parse_mask_ports(const char *s,
family = AF_INET;
tor_addr_from_ipv4h(addr_out, 0);
} else if (flags & TAPMP_STAR_IPV6_ONLY) {
static char nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
static uint8_t nil_bytes[16] =
{ [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
family = AF_INET6;
tor_addr_from_ipv6_bytes(addr_out, nil_bytes);
} else {
@ -629,7 +630,7 @@ tor_addr_parse_mask_ports(const char *s,
tor_addr_from_ipv4h(addr_out, 0);
any_flag = 1;
} else if (!strcmp(address, "*6") && (flags & TAPMP_EXTENDED_STAR)) {
static char nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
static uint8_t nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
family = AF_INET6;
tor_addr_from_ipv6_bytes(addr_out, nil_bytes);
any_flag = 1;
@ -887,7 +888,7 @@ tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr)
/** Set <b>dest</b> to equal the IPv6 address in the 16 bytes at
* <b>ipv6_bytes</b>. */
void
tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *ipv6_bytes)
tor_addr_from_ipv6_bytes(tor_addr_t *dest, const uint8_t *ipv6_bytes)
{
tor_assert(dest);
tor_assert(ipv6_bytes);
@ -900,7 +901,21 @@ tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *ipv6_bytes)
void
tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6)
{
tor_addr_from_ipv6_bytes(dest, (const char*)in6->s6_addr);
tor_addr_from_ipv6_bytes(dest, in6->s6_addr);
}
/** Set the 16 bytes at <b>dest</b> to equal the IPv6 address <b>src</b>.
* <b>src</b> must be an IPv6 address, if it is not, log a warning, and clear
* <b>dest</b>. */
void
tor_addr_copy_ipv6_bytes(uint8_t *dest, const tor_addr_t *src)
{
tor_assert(dest);
tor_assert(src);
memset(dest, 0, 16);
IF_BUG_ONCE(src->family != AF_INET6)
return;
memcpy(dest, src->addr.in6_addr.s6_addr, 16);
}
/** Copy a tor_addr_t from <b>src</b> to <b>dest</b>.
@ -1192,6 +1207,39 @@ fmt_addr32(uint32_t addr)
return buf;
}
/** Return a string representing the family of <b>addr</b>.
*
* This string is a string constant, and must not be freed.
* This function is thread-safe.
*/
const char *
fmt_addr_family(const tor_addr_t *addr)
{
static int default_bug_once = 0;
IF_BUG_ONCE(!addr)
return "NULL pointer";
switch (tor_addr_family(addr)) {
case AF_INET6:
return "IPv6";
case AF_INET:
return "IPv4";
case AF_UNIX:
return "UNIX socket";
case AF_UNSPEC:
return "unspecified";
default:
if (!default_bug_once) {
log_warn(LD_BUG, "Called with unknown address family %d",
(int)tor_addr_family(addr));
default_bug_once = 1;
}
return "unknown";
}
//return "(unreachable code)";
}
/** Convert the string in <b>src</b> to a tor_addr_t <b>addr</b>. The string
* may be an IPv4 address, or an IPv6 address surrounded by square brackets.
*
@ -1416,10 +1464,10 @@ ifconf_free_ifc_buf(struct ifconf *ifc)
* into smartlist of <b>tor_addr_t</b> structures.
*/
STATIC smartlist_t *
ifreq_to_smartlist(char *buf, size_t buflen)
ifreq_to_smartlist(const uint8_t *buf, size_t buflen)
{
smartlist_t *result = smartlist_new();
char *end = buf + buflen;
const uint8_t *end = buf + buflen;
/* These acrobatics are due to alignment issues which trigger
* undefined behaviour traps on OSX. */
@ -1493,7 +1541,7 @@ get_interface_addresses_ioctl(int severity, sa_family_t family)
/* Ensure we have least IFREQ_SIZE bytes unused at the end. Otherwise, we
* don't know if we got everything during ioctl. */
} while (mult * IFREQ_SIZE - ifc.ifc_len <= IFREQ_SIZE);
result = ifreq_to_smartlist(ifc.ifc_buf, ifc.ifc_len);
result = ifreq_to_smartlist((const uint8_t *)ifc.ifc_buf, ifc.ifc_len);
done:
if (fd >= 0)

View File

@ -104,6 +104,10 @@ int tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa,
uint16_t *port_out);
void tor_addr_make_unspec(tor_addr_t *a);
void tor_addr_make_null(tor_addr_t *a, sa_family_t family);
#define tor_addr_port_make_null(addr, port, family) \
(void)(tor_addr_make_null(addr, family), (port) = 0)
#define tor_addr_port_make_null_ap(ap, family) \
tor_addr_port_make_null(&(ap)->addr, (ap)->port, family)
char *tor_sockaddr_to_str(const struct sockaddr *sa);
/** Return an in6_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not
@ -221,7 +225,9 @@ char *tor_addr_to_str_dup(const tor_addr_t *addr) ATTR_MALLOC;
const char *fmt_addr_impl(const tor_addr_t *addr, int decorate);
const char *fmt_addrport(const tor_addr_t *addr, uint16_t port);
const char * fmt_addr32(uint32_t addr);
#define fmt_addrport_ap(ap) fmt_addrport(&(ap)->addr, (ap)->port)
const char *fmt_addr32(uint32_t addr);
const char *fmt_addr_family(const tor_addr_t *addr);
MOCK_DECL(int,get_interface_address6,(int severity, sa_family_t family,
tor_addr_t *addr));
@ -298,11 +304,12 @@ void tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr);
* order. */
#define tor_addr_from_ipv4h(dest, v4addr) \
tor_addr_from_ipv4n((dest), htonl(v4addr))
void tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *bytes);
void tor_addr_from_ipv6_bytes(tor_addr_t *dest, const uint8_t *bytes);
/** Set <b>dest</b> to the IPv4 address incoded in <b>in</b>. */
#define tor_addr_from_in(dest, in) \
tor_addr_from_ipv4n((dest), (in)->s_addr);
void tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6);
void tor_addr_copy_ipv6_bytes(uint8_t *dest, const tor_addr_t *src);
int tor_addr_is_null(const tor_addr_t *addr);
int tor_addr_is_loopback(const tor_addr_t *addr);
@ -393,8 +400,8 @@ STATIC struct smartlist_t *get_interface_addresses_win32(int severity,
#endif /* defined(HAVE_IP_ADAPTER_TO_SMARTLIST) */
#ifdef HAVE_IFCONF_TO_SMARTLIST
STATIC struct smartlist_t *ifreq_to_smartlist(char *ifr,
size_t buflen);
STATIC struct smartlist_t *ifreq_to_smartlist(const uint8_t *ifr,
size_t buflen);
STATIC struct smartlist_t *get_interface_addresses_ioctl(int severity,
sa_family_t family);
#endif /* defined(HAVE_IFCONF_TO_SMARTLIST) */

View File

@ -460,7 +460,7 @@ test_address_ifreq_to_smartlist(void *arg)
ifc->ifc_len = sizeof(struct ifreq);
ifc->ifc_ifcu.ifcu_req = ifr;
results = ifreq_to_smartlist(ifc->ifc_buf,ifc->ifc_len);
results = ifreq_to_smartlist((const uint8_t *)ifc->ifc_buf,ifc->ifc_len);
tt_int_op(smartlist_len(results),OP_EQ,1);
tor_addr = smartlist_get(results, 0);
@ -483,7 +483,7 @@ test_address_ifreq_to_smartlist(void *arg)
SMARTLIST_FOREACH(results, tor_addr_t *, t, tor_free(t));
smartlist_free(results);
results = ifreq_to_smartlist(ifc->ifc_buf,ifc->ifc_len);
results = ifreq_to_smartlist((const uint8_t *)ifc->ifc_buf,ifc->ifc_len);
tt_int_op(smartlist_len(results),OP_EQ,2);
tor_addr = smartlist_get(results, 0);

View File

@ -713,16 +713,20 @@ test_cfmt_extend_cells(void *arg)
tt_mem_op(cc->onionskin,OP_EQ, b, 99+20);
tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND2);
/* We'll generate it minus the IPv6 address and minus the konami code */
tt_int_op(p2_len, OP_EQ, 89+99-34-20);
/* We'll generate it minus the konami code */
tt_int_op(p2_len, OP_EQ, 89+99-34);
test_memeq_hex(p2,
/* Two items: one that same darn IP address. */
"02000612F40001F0F1"
/* The next is a digest : anthropomorphization */
"0214616e7468726f706f6d6f727068697a6174696f6e"
/* Three items */
"03"
/* IPv4 address */
"0006" "12F40001" "F0F1"
/* The next is an RSA digest: anthropomorphization */
"0214" "616e7468726f706f6d6f727068697a6174696f6e"
/*IPv6 address */
"0112" "20020000000000000000000000f0c51e" "1112"
/* Now the handshake prologue */
"01050063");
tt_mem_op(p2+1+8+22+4,OP_EQ, b, 99+20);
tt_mem_op(p2+1+8+22+20+4, OP_EQ, b, 99+20);
tt_int_op(0, OP_EQ, create_cell_format_relayed(&cell, cc));
/* Now let's add an ed25519 key to that extend2 cell. */
@ -732,22 +736,31 @@ test_cfmt_extend_cells(void *arg)
/* As before, since we aren't extending by ed25519. */
get_options_mutable()->ExtendByEd25519ID = 0;
tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
tt_int_op(p2_len, OP_EQ, 89+99-34-20);
tt_int_op(p2_len, OP_EQ, 89+99-34);
test_memeq_hex(p2,
"02000612F40001F0F1"
"03"
"000612F40001F0F1"
"0214616e7468726f706f6d6f727068697a6174696f6e"
"011220020000000000000000000000f0c51e1112"
"01050063");
/* Now try with the ed25519 ID. */
get_options_mutable()->ExtendByEd25519ID = 1;
tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
tt_int_op(p2_len, OP_EQ, 89+99-34-20 + 34);
tt_int_op(p2_len, OP_EQ, 89+99);
test_memeq_hex(p2,
"03000612F40001F0F1"
/* Four items */
"04"
/* IPv4 address */
"0006" "12F40001" "F0F1"
/* The next is an RSA digest: anthropomorphization */
"0214616e7468726f706f6d6f727068697a6174696f6e"
// ed digest follows:
/* Then an ed public key: brownshoesdontmakeit/brownshoesd */
"0320" "62726f776e73686f6573646f6e746d616b656"
"9742f62726f776e73686f657364"
/*IPv6 address */
"0112" "20020000000000000000000000f0c51e" "1112"
/* Now the handshake prologue */
"01050063");
/* Can we parse that? Did the key come through right? */
memset(&ec, 0, sizeof(ec));
@ -756,6 +769,40 @@ test_cfmt_extend_cells(void *arg)
tt_mem_op("brownshoesdontmakeit/brownshoesd", OP_EQ,
ec.ed_pubkey.pubkey, 32);
/* Now try IPv6 without IPv4 */
memset(p, 0, sizeof(p));
memcpy(p, "\x02", 1);
memcpy(p+1, "\x02\x14" "anthropomorphization", 22);
memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 20);
memcpy(p+43, "\xff\xff\x00\x20", 4);
tt_int_op(0, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
tt_int_op(RELAY_COMMAND_EXTEND2, OP_EQ, ec.cell_type);
tt_assert(fast_mem_is_zero((const char *)&ec.orport_ipv4.addr,
sizeof(tor_addr_t)));
tt_int_op(0, OP_EQ, ec.orport_ipv4.port);
tt_str_op("7878:7878:7878:7878:7878:7878:7878:7878",
OP_EQ, fmt_addr(&ec.orport_ipv6.addr));
tt_int_op(22873, OP_EQ, ec.orport_ipv6.port);
tt_assert(ed25519_public_key_is_zero(&ec.ed_pubkey));
tt_mem_op(ec.node_id,OP_EQ, "anthropomorphization", 20);
tt_int_op(cc->cell_type, OP_EQ, CELL_CREATE2);
tt_int_op(cc->handshake_type, OP_EQ, 0xffff);
tt_int_op(cc->handshake_len, OP_EQ, 32);
tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND2);
tt_int_op(p2_len, OP_EQ, 47+32);
test_memeq_hex(p2,
/* Two items */
"02"
/* The next is an RSA digest: anthropomorphization */
"0214" "616e7468726f706f6d6f727068697a6174696f6e"
/*IPv6 address */
"0112" "78787878787878787878787878787878" "5959"
/* Now the handshake prologue */
"ffff0020");
tt_int_op(0, OP_EQ, create_cell_format_relayed(&cell, cc));
/* == Now try parsing some junk */
/* Try a too-long handshake */
@ -809,13 +856,6 @@ test_cfmt_extend_cells(void *arg)
memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
memcpy(p+31, "\x01\x11" "xxxxxxxxxxxxxxxxY", 17);
memcpy(p+48, "\xff\xff\x00\x20", 4);
tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
memset(p, 0, sizeof(p));
memcpy(p, "\x02", 1);
memcpy(p+1, "\x02\x14" "anarchoindividualist", 22);
memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 18);
memcpy(p+41, "\xff\xff\x00\x20", 4);
tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));

View File

@ -1326,7 +1326,7 @@ test_channel_for_extend(void *arg)
channel_t *ret_chan = NULL;
char digest[DIGEST_LEN];
ed25519_public_key_t ed_id;
tor_addr_t addr;
tor_addr_t ipv4_addr, ipv6_addr;
const char *msg;
int launch;
time_t now = time(NULL);
@ -1336,6 +1336,9 @@ test_channel_for_extend(void *arg)
memset(digest, 'A', sizeof(digest));
memset(&ed_id, 'B', sizeof(ed_id));
tor_addr_make_null(&ipv4_addr, AF_INET);
tor_addr_make_null(&ipv6_addr, AF_INET6);
chan1 = new_fake_channel();
tt_assert(chan1);
/* Need to be registered to get added to the id map. */
@ -1366,7 +1369,8 @@ test_channel_for_extend(void *arg)
tt_ptr_op(channel_find_by_remote_identity(digest, &ed_id), OP_EQ, chan1);
/* The expected result is chan2 because it is older than chan1. */
ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
&msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@ -1374,7 +1378,8 @@ test_channel_for_extend(void *arg)
/* Switch that around from previous test. */
chan2->timestamp_created = chan1->timestamp_created + 1;
ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
&msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan1);
tt_int_op(launch, OP_EQ, 0);
@ -1383,7 +1388,8 @@ test_channel_for_extend(void *arg)
/* Same creation time, num circuits will be used and they both have 0 so the
* channel 2 should be picked due to how channel_is_better() works. */
chan2->timestamp_created = chan1->timestamp_created;
ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
&msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan1);
tt_int_op(launch, OP_EQ, 0);
@ -1394,7 +1400,8 @@ test_channel_for_extend(void *arg)
/* Condemned the older channel. */
chan1->state = CHANNEL_STATE_CLOSING;
ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
&msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@ -1403,7 +1410,8 @@ test_channel_for_extend(void *arg)
/* Make the older channel a client one. */
channel_mark_client(chan1);
ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
&msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@ -1413,8 +1421,9 @@ test_channel_for_extend(void *arg)
/* Non matching ed identity with valid digest. */
ed25519_public_key_t dumb_ed_id;
memset(&dumb_ed_id, 0, sizeof(dumb_ed_id));
ret_chan = channel_get_for_extend(digest, &dumb_ed_id, &addr, &msg,
&launch);
ret_chan = channel_get_for_extend(digest, &dumb_ed_id,
&ipv4_addr, &ipv6_addr,
&msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Not connected. Connecting.");
tt_int_op(launch, OP_EQ, 1);
@ -1423,7 +1432,8 @@ test_channel_for_extend(void *arg)
test_chan_should_match_target = 1;
chan1->state = CHANNEL_STATE_OPENING;
chan2->state = CHANNEL_STATE_OPENING;
ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
&msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Connection in progress; waiting.");
tt_int_op(launch, OP_EQ, 0);
@ -1432,7 +1442,8 @@ test_channel_for_extend(void *arg)
/* Mark channel 1 as bad for circuits. */
channel_mark_bad_for_new_circs(chan1);
ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
&msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@ -1442,7 +1453,8 @@ test_channel_for_extend(void *arg)
/* Mark both channels as unusable. */
channel_mark_bad_for_new_circs(chan1);
channel_mark_bad_for_new_circs(chan2);
ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
&msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. "
" Launching a new one.");
@ -1453,7 +1465,8 @@ test_channel_for_extend(void *arg)
/* Non canonical channels. */
test_chan_should_match_target = 0;
test_chan_canonical_should_be_reliable = 1;
ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
&msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. "
" Launching a new one.");

View File

@ -30,6 +30,7 @@
#include "feature/client/entrynodes.h"
#include "feature/nodelist/nodelist.h"
#include "feature/relay/circuitbuild_relay.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
#include "feature/nodelist/node_st.h"
@ -219,6 +220,7 @@ test_circuit_extend_state_valid(void *arg)
expect_log_msg("Got an extend cell, but running as a client. Closing.\n");
mock_clean_saved_logs();
#ifndef ALL_BUGS_ARE_FATAL
/* Circuit must be non-NULL */
tor_capture_bugs_(1);
server = 1;
@ -228,6 +230,7 @@ test_circuit_extend_state_valid(void *arg)
"!(ASSERT_PREDICT_UNLIKELY_(!circ))");
tor_end_capture_bugs_();
mock_clean_saved_logs();
#endif /* !defined(ALL_BUGS_ARE_FATAL) */
/* n_chan and n_hop are NULL, this should succeed */
server = 1;
@ -314,6 +317,7 @@ test_circuit_extend_add_ed25519(void *arg)
setup_full_capture_of_logs(LOG_INFO);
#ifndef ALL_BUGS_ARE_FATAL
/* The extend cell must be non-NULL */
tor_capture_bugs_(1);
tt_int_op(circuit_extend_add_ed25519_helper(NULL), OP_EQ, -1);
@ -322,6 +326,7 @@ test_circuit_extend_add_ed25519(void *arg)
"!(ASSERT_PREDICT_UNLIKELY_(!ec))");
tor_end_capture_bugs_();
mock_clean_saved_logs();
#endif /* !defined(ALL_BUGS_ARE_FATAL) */
/* The node id must be non-zero */
memcpy(old_ec, ec, sizeof(extend_cell_t));
@ -474,6 +479,9 @@ mock_get_options(void)
#define PUBLIC_IPV4 "1.2.3.4"
#define INTERNAL_IPV4 "0.0.0.1"
#define PUBLIC_IPV6 "1234::cdef"
#define INTERNAL_IPV6 "::1"
#define VALID_PORT 0x1234
/* Test the different cases in circuit_extend_lspec_valid_helper(). */
@ -492,6 +500,7 @@ test_circuit_extend_lspec_valid(void *arg)
setup_full_capture_of_logs(LOG_INFO);
#ifndef ALL_BUGS_ARE_FATAL
/* Extend cell must be non-NULL */
tor_capture_bugs_(1);
tt_int_op(circuit_extend_lspec_valid_helper(NULL, circ), OP_EQ, -1);
@ -518,41 +527,114 @@ test_circuit_extend_lspec_valid(void *arg)
tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 2);
tor_end_capture_bugs_();
mock_clean_saved_logs();
#endif /* !defined(ALL_BUGS_ARE_FATAL) */
/* IPv4 addr or port are 0, these should fail */
/* IPv4 and IPv6 addr and port are all zero, this should fail */
tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
expect_log_msg("Client asked me to extend to "
"zero destination port or addr.\n");
expect_log_msg("Client asked me to extend to a zero destination port "
"or unspecified address '[scrubbed]'.\n");
mock_clean_saved_logs();
/* Now ask for the actual address in the logs */
fake_options->SafeLogging_ = SAFELOG_SCRUB_NONE;
/* IPv4 port is 0, IPv6 addr and port are both zero, this should fail */
tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
expect_log_msg("Client asked me to extend to "
"zero destination port or addr.\n");
expect_log_msg("Client asked me to extend to a zero destination port "
"or IPv4 address '1.2.3.4:0'.\n");
mock_clean_saved_logs();
tor_addr_make_null(&ec->orport_ipv4.addr, AF_INET);
tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
/* IPv4 addr is 0, IPv6 addr and port are both zero, this should fail */
ec->orport_ipv4.port = VALID_PORT;
tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
expect_log_msg("Client asked me to extend to "
"zero destination port or addr.\n");
expect_log_msg("Client asked me to extend to a zero destination port "
"or IPv4 address '0.0.0.0:4660'.\n");
mock_clean_saved_logs();
ec->orport_ipv4.port = 0;
tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
/* IPv4 addr is internal, and port is valid.
* (IPv6 addr and port are both zero.)
* Result depends on ExtendAllowPrivateAddresses. */
tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
ec->orport_ipv4.port = VALID_PORT;
fake_options->ExtendAllowPrivateAddresses = 0;
tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
expect_log_msg("Client asked me to extend to a private address.\n");
expect_log_msg("Client asked me to extend "
"to a private IPv4 address '0.0.0.1'.\n");
mock_clean_saved_logs();
fake_options->ExtendAllowPrivateAddresses = 0;
tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
/* Now do the same tests, but for IPv6 */
/* IPv6 port is 0, IPv4 addr and port are both zero, this should fail */
tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6);
tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
expect_log_msg("Client asked me to extend to a zero destination port "
"or IPv6 address '[1234::cdef]:0'.\n");
mock_clean_saved_logs();
tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
/* IPv6 addr is 0, IPv4 addr and port are both zero, this should fail */
ec->orport_ipv6.port = VALID_PORT;
tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
expect_log_msg("Client asked me to extend to a zero destination port "
"or IPv6 address '[::]:4660'.\n");
mock_clean_saved_logs();
ec->orport_ipv4.port = 0;
tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
/* IPv6 addr is internal, and port is valid.
* (IPv4 addr and port are both zero.)
* Result depends on ExtendAllowPrivateAddresses. */
tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6);
ec->orport_ipv6.port = VALID_PORT;
fake_options->ExtendAllowPrivateAddresses = 0;
tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
expect_log_msg("Client asked me to extend "
"to a private IPv6 address '[::1]'.\n");
mock_clean_saved_logs();
fake_options->ExtendAllowPrivateAddresses = 0;
tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
/* Both addresses are internal.
* Result depends on ExtendAllowPrivateAddresses. */
tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
ec->orport_ipv4.port = VALID_PORT;
tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6);
ec->orport_ipv6.port = VALID_PORT;
fake_options->ExtendAllowPrivateAddresses = 0;
tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
expect_log_msg("Client asked me to extend "
"to a private IPv4 address '0.0.0.1'.\n");
expect_log_msg("Client asked me to extend "
"to a private IPv6 address '[::1]'.\n");
mock_clean_saved_logs();
fake_options->ExtendAllowPrivateAddresses = 0;
tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
#ifndef ALL_BUGS_ARE_FATAL
/* If we pass the private address check, but don't have the right
* OR circuit magic number, we trigger another bug */
tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
ec->orport_ipv4.port = VALID_PORT;
tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6);
ec->orport_ipv6.port = VALID_PORT;
fake_options->ExtendAllowPrivateAddresses = 1;
tor_capture_bugs_(1);
tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
@ -561,10 +643,27 @@ test_circuit_extend_lspec_valid(void *arg)
tor_end_capture_bugs_();
mock_clean_saved_logs();
fake_options->ExtendAllowPrivateAddresses = 0;
tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
/* Fail again, but this time only set an IPv4 address. */
tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
ec->orport_ipv4.port = VALID_PORT;
fake_options->ExtendAllowPrivateAddresses = 1;
tor_capture_bugs_(1);
tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
/* Since we're using IF_BUG_ONCE(), expect 0-1 bug logs */
tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0);
tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 1);
tor_end_capture_bugs_();
mock_clean_saved_logs();
fake_options->ExtendAllowPrivateAddresses = 0;
#endif /* !defined(ALL_BUGS_ARE_FATAL) */
/* Now set the right magic */
or_circ->base_.magic = OR_CIRCUIT_MAGIC;
#ifndef ALL_BUGS_ARE_FATAL
/* If we pass the OR circuit magic check, but don't have p_chan,
* we trigger another bug */
fake_options->ExtendAllowPrivateAddresses = 1;
@ -591,6 +690,7 @@ test_circuit_extend_lspec_valid(void *arg)
tor_addr_make_null(&ec->orport_ipv4.addr, AF_INET);
ec->orport_ipv4.port = 0x0000;
#endif /* !defined(ALL_BUGS_ARE_FATAL) */
/* Now let's fake a p_chan and the addresses */
tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
@ -622,6 +722,41 @@ test_circuit_extend_lspec_valid(void *arg)
tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
mock_clean_saved_logs();
/* Now let's check that we warn, but succeed, when only one address is
* private */
tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
ec->orport_ipv4.port = VALID_PORT;
tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6);
ec->orport_ipv6.port = VALID_PORT;
fake_options->ExtendAllowPrivateAddresses = 0;
tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
expect_log_msg("Client asked me to extend "
"to a private IPv4 address '0.0.0.1'.\n");
mock_clean_saved_logs();
tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
/* Now with private IPv6 */
tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
ec->orport_ipv4.port = VALID_PORT;
tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6);
ec->orport_ipv6.port = VALID_PORT;
fake_options->ExtendAllowPrivateAddresses = 0;
tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
expect_log_msg("Client asked me to extend "
"to a private IPv6 address '[::1]'.\n");
mock_clean_saved_logs();
tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
/* Now reset to public IPv4 and IPv6 */
tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
ec->orport_ipv4.port = VALID_PORT;
tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6);
ec->orport_ipv6.port = VALID_PORT;
/* Fail on matching non-zero identities */
memset(&ec->ed_pubkey, 0xEE, sizeof(ec->ed_pubkey));
memset(&p_chan->ed25519_identity, 0xEE, sizeof(p_chan->ed25519_identity));
@ -686,6 +821,97 @@ test_circuit_extend_lspec_valid(void *arg)
tor_free(p_chan);
}
static bool can_extend_over_ipv6_result = false;
static int mock_router_can_extend_over_ipv6_calls = 0;
static bool
mock_router_can_extend_over_ipv6(const or_options_t *options)
{
(void)options;
mock_router_can_extend_over_ipv6_calls++;
return can_extend_over_ipv6_result;
}
/* Test the different cases in circuit_choose_ip_ap_for_extend(). */
static void
test_circuit_choose_ip_ap_for_extend(void *arg)
{
(void)arg;
tor_addr_port_t ipv4_ap;
tor_addr_port_t ipv6_ap;
/* Set up valid addresses */
tor_addr_parse(&ipv4_ap.addr, PUBLIC_IPV4);
ipv4_ap.port = VALID_PORT;
tor_addr_parse(&ipv6_ap.addr, PUBLIC_IPV6);
ipv6_ap.port = VALID_PORT;
or_options_t *fake_options = options_new();
MOCK(get_options, mock_get_options);
mocked_options = fake_options;
MOCK(router_can_extend_over_ipv6,
mock_router_can_extend_over_ipv6);
can_extend_over_ipv6_result = true;
mock_router_can_extend_over_ipv6_calls = 0;
/* No valid addresses */
can_extend_over_ipv6_result = true;
mock_router_can_extend_over_ipv6_calls = 0;
tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, NULL), OP_EQ, NULL);
tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
can_extend_over_ipv6_result = false;
mock_router_can_extend_over_ipv6_calls = 0;
tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, NULL), OP_EQ, NULL);
tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
/* One valid address: IPv4 */
can_extend_over_ipv6_result = true;
mock_router_can_extend_over_ipv6_calls = 0;
tt_ptr_op(circuit_choose_ip_ap_for_extend(&ipv4_ap, NULL), OP_EQ, &ipv4_ap);
tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
can_extend_over_ipv6_result = false;
mock_router_can_extend_over_ipv6_calls = 0;
tt_ptr_op(circuit_choose_ip_ap_for_extend(&ipv4_ap, NULL), OP_EQ, &ipv4_ap);
tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
/* One valid address: IPv6 */
can_extend_over_ipv6_result = true;
mock_router_can_extend_over_ipv6_calls = 0;
tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, &ipv6_ap), OP_EQ, &ipv6_ap);
tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
can_extend_over_ipv6_result = false;
mock_router_can_extend_over_ipv6_calls = 0;
tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, &ipv6_ap), OP_EQ, NULL);
tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
/* Two valid addresses */
const tor_addr_port_t *chosen_addr = NULL;
can_extend_over_ipv6_result = true;
mock_router_can_extend_over_ipv6_calls = 0;
chosen_addr = circuit_choose_ip_ap_for_extend(&ipv4_ap, &ipv6_ap);
tt_assert(chosen_addr == &ipv4_ap || chosen_addr == &ipv6_ap);
tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
can_extend_over_ipv6_result = false;
mock_router_can_extend_over_ipv6_calls = 0;
tt_ptr_op(circuit_choose_ip_ap_for_extend(&ipv4_ap, &ipv6_ap),
OP_EQ, &ipv4_ap);
tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
done:
UNMOCK(get_options);
or_options_free(fake_options);
mocked_options = NULL;
UNMOCK(router_can_extend_over_ipv6);
tor_free(fake_options);
}
static int mock_circuit_close_calls = 0;
static void
mock_circuit_mark_for_close_(circuit_t *circ, int reason,
@ -714,23 +940,41 @@ mock_channel_connect_for_circuit(const tor_addr_t *addr,
return mock_channel_connect_nchan;
}
/* Test the different cases in circuit_open_connection_for_extend(). */
/* Test the different cases in circuit_open_connection_for_extend().
* Chooses different IP addresses depending on the first character in arg:
* - 4: IPv4
* - 6: IPv6
* - d: IPv4 and IPv6 (dual-stack)
*/
static void
test_circuit_open_connection_for_extend(void *arg)
{
(void)arg;
const char ip_version = ((const char *)arg)[0];
const bool use_ipv4 = (ip_version == '4' || ip_version == 'd');
const bool use_ipv6 = (ip_version == '6' || ip_version == 'd');
tor_assert(use_ipv4 || use_ipv6);
extend_cell_t *ec = tor_malloc_zero(sizeof(extend_cell_t));
circuit_t *circ = tor_malloc_zero(sizeof(circuit_t));
channel_t *fake_n_chan = tor_malloc_zero(sizeof(channel_t));
or_options_t *fake_options = options_new();
MOCK(get_options, mock_get_options);
mocked_options = fake_options;
MOCK(circuit_mark_for_close_, mock_circuit_mark_for_close_);
mock_circuit_close_calls = 0;
MOCK(channel_connect_for_circuit, mock_channel_connect_for_circuit);
mock_channel_connect_calls = 0;
mock_channel_connect_nchan = NULL;
MOCK(router_can_extend_over_ipv6,
mock_router_can_extend_over_ipv6);
can_extend_over_ipv6_result = true;
setup_full_capture_of_logs(LOG_INFO);
#ifndef ALL_BUGS_ARE_FATAL
/* Circuit must be non-NULL */
mock_circuit_close_calls = 0;
mock_channel_connect_calls = 0;
@ -772,6 +1016,33 @@ test_circuit_open_connection_for_extend(void *arg)
tor_end_capture_bugs_();
mock_clean_saved_logs();
/* Fail, because neither address is valid */
mock_circuit_close_calls = 0;
mock_channel_connect_calls = 0;
tor_capture_bugs_(1);
circuit_open_connection_for_extend(ec, circ, 0);
/* Close the circuit, don't connect */
tt_int_op(mock_circuit_close_calls, OP_EQ, 1);
tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
/* Check state */
tt_ptr_op(circ->n_hop, OP_EQ, NULL);
tt_ptr_op(circ->n_chan_create_cell, OP_EQ, NULL);
tt_int_op(circ->state, OP_EQ, 0);
/* Cleanup */
tor_end_capture_bugs_();
mock_clean_saved_logs();
#endif /* !defined(ALL_BUGS_ARE_FATAL) */
/* Set up valid addresses */
if (use_ipv4) {
tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
ec->orport_ipv4.port = VALID_PORT;
}
if (use_ipv6) {
tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6);
ec->orport_ipv6.port = VALID_PORT;
}
/* Succeed, but don't try to open a connection */
mock_circuit_close_calls = 0;
mock_channel_connect_calls = 0;
@ -812,7 +1083,7 @@ test_circuit_open_connection_for_extend(void *arg)
mock_circuit_close_calls = 0;
mock_channel_connect_calls = 0;
circuit_open_connection_for_extend(ec, circ, 1);
/* Try to connect, and succeed, leaving the circuit open */
/* Connection attempt succeeded, leaving the circuit open */
tt_int_op(mock_circuit_close_calls, OP_EQ, 0);
tt_int_op(mock_channel_connect_calls, OP_EQ, 1);
/* Check state */
@ -835,6 +1106,12 @@ test_circuit_open_connection_for_extend(void *arg)
UNMOCK(channel_connect_for_circuit);
mock_channel_connect_calls = 0;
UNMOCK(get_options);
or_options_free(fake_options);
mocked_options = NULL;
UNMOCK(router_can_extend_over_ipv6);
tor_free(ec);
tor_free(circ->n_hop);
tor_free(circ->n_chan_create_cell);
@ -869,13 +1146,15 @@ static channel_t *mock_channel_get_for_extend_nchan = NULL;
static channel_t *
mock_channel_get_for_extend(const char *rsa_id_digest,
const ed25519_public_key_t *ed_id,
const tor_addr_t *target_addr,
const tor_addr_t *target_ipv4_addr,
const tor_addr_t *target_ipv6_addr,
const char **msg_out,
int *launch_out)
{
(void)rsa_id_digest;
(void)ed_id;
(void)target_addr;
(void)target_ipv4_addr;
(void)target_ipv6_addr;
/* channel_get_for_extend() requires non-NULL arguments */
tt_ptr_op(msg_out, OP_NE, NULL);
@ -941,6 +1220,7 @@ test_circuit_extend(void *arg)
setup_full_capture_of_logs(LOG_INFO);
#ifndef ALL_BUGS_ARE_FATAL
/* Circuit must be non-NULL */
tor_capture_bugs_(1);
tt_int_op(circuit_extend(cell, NULL), OP_EQ, -1);
@ -967,6 +1247,7 @@ test_circuit_extend(void *arg)
tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 2);
tor_end_capture_bugs_();
mock_clean_saved_logs();
#endif /* !defined(ALL_BUGS_ARE_FATAL) */
/* Clients can't extend */
server = 0;
@ -1002,8 +1283,8 @@ test_circuit_extend(void *arg)
tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
expect_log_msg("Client asked me to extend to "
"zero destination port or addr.\n");
expect_log_msg("Client asked me to extend to a zero destination port "
"or unspecified address '[scrubbed]'.\n");
mock_clean_saved_logs();
mock_extend_cell_parse_calls = 0;
@ -1012,6 +1293,7 @@ test_circuit_extend(void *arg)
PUBLIC_IPV4);
mock_extend_cell_parse_cell_out.orport_ipv4.port = VALID_PORT;
#ifndef ALL_BUGS_ARE_FATAL
tor_capture_bugs_(1);
tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
@ -1021,6 +1303,7 @@ test_circuit_extend(void *arg)
tor_end_capture_bugs_();
mock_clean_saved_logs();
mock_extend_cell_parse_calls = 0;
#endif /* !defined(ALL_BUGS_ARE_FATAL) */
/* Now add the right magic and a p_chan. */
or_circ->base_.magic = OR_CIRCUIT_MAGIC;
@ -1166,6 +1449,7 @@ test_onionskin_answer(void *arg)
setup_full_capture_of_logs(LOG_INFO);
#ifndef ALL_BUGS_ARE_FATAL
/* Circuit must be non-NULL */
tor_capture_bugs_(1);
tt_int_op(onionskin_answer(NULL, created_cell,
@ -1209,6 +1493,7 @@ test_onionskin_answer(void *arg)
"!(ASSERT_PREDICT_UNLIKELY_(!rend_circ_nonce))");
tor_end_capture_bugs_();
mock_clean_saved_logs();
#endif /* !defined(ALL_BUGS_ARE_FATAL) */
/* Also, the keys length must be CPATH_KEY_MATERIAL_LEN, but we can't catch
* asserts in unit tests. */
@ -1240,6 +1525,12 @@ test_onionskin_answer(void *arg)
#define TEST_CIRCUIT(name, flags) \
{ #name, test_circuit_ ## name, flags, NULL, NULL }
#ifndef COCCI
#define TEST_CIRCUIT_PASSTHROUGH(name, flags, arg) \
{ #name "/" arg, test_circuit_ ## name, flags, \
&passthrough_setup, (void *)(arg) }
#endif
struct testcase_t circuitbuild_tests[] = {
TEST_NEW_ROUTE_LEN(noexit, 0),
TEST_NEW_ROUTE_LEN(safe_exit, 0),
@ -1251,7 +1542,10 @@ struct testcase_t circuitbuild_tests[] = {
TEST_CIRCUIT(extend_state_valid, TT_FORK),
TEST_CIRCUIT(extend_add_ed25519, TT_FORK),
TEST_CIRCUIT(extend_lspec_valid, TT_FORK),
TEST_CIRCUIT(open_connection_for_extend, TT_FORK),
TEST_CIRCUIT(choose_ip_ap_for_extend, 0),
TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "4"),
TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "6"),
TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "dual-stack"),
TEST_CIRCUIT(extend, TT_FORK),
TEST(onionskin_answer, TT_FORK, NULL, NULL),

View File

@ -509,7 +509,7 @@ do_resolve(const char *hostname,
} else if (atype == SOCKS5_ATYPE_IPV6) {
/* IPv6 address */
tor_addr_from_ipv6_bytes(result_addr,
(const char *)socks5_server_reply_getarray_bind_addr_ipv6(reply));
socks5_server_reply_getarray_bind_addr_ipv6(reply));
} else if (atype == SOCKS5_ATYPE_HOSTNAME) {
/* Domain name */
domainname_t *dn =