mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-25 15:10:48 +01:00
Merge branch 'tor-gitlab/mr/327'
Conflicts: src/test/test.c Minor comment issue.
This commit is contained in:
commit
3bd7367274
9 changed files with 472 additions and 6 deletions
|
@ -5466,6 +5466,77 @@ pt_parse_transport_line(const or_options_t *options,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a flag describing an extra dirport for a directory authority.
|
||||||
|
*
|
||||||
|
* Right now, the supported format is exactly:
|
||||||
|
* `{upload,download,voting}=http://[IP:PORT]/`.
|
||||||
|
* Other URL schemes, and other suffixes, might be supported in the future.
|
||||||
|
*
|
||||||
|
* Only call this function if `flag` starts with one of the above strings.
|
||||||
|
*
|
||||||
|
* Return 0 on success, and -1 on failure.
|
||||||
|
*
|
||||||
|
* If `ds` is provided, then add any parsed dirport to `ds`. If `ds` is NULL,
|
||||||
|
* take no action other than parsing.
|
||||||
|
**/
|
||||||
|
static int
|
||||||
|
parse_dirauth_dirport(dir_server_t *ds, const char *flag)
|
||||||
|
{
|
||||||
|
tor_assert(flag);
|
||||||
|
|
||||||
|
auth_dirport_usage_t usage;
|
||||||
|
|
||||||
|
if (!strcasecmpstart(flag, "upload=")) {
|
||||||
|
usage = AUTH_USAGE_UPLOAD;
|
||||||
|
} else if (!strcasecmpstart(flag, "download=")) {
|
||||||
|
usage = AUTH_USAGE_DOWNLOAD;
|
||||||
|
} else if (!strcasecmpstart(flag, "vote=")) {
|
||||||
|
usage = AUTH_USAGE_VOTING;
|
||||||
|
} else {
|
||||||
|
// We shouldn't get called with a flag that we don't recognize.
|
||||||
|
tor_assert_nonfatal_unreached();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *eq = strchr(flag, '=');
|
||||||
|
tor_assert(eq);
|
||||||
|
const char *target = eq + 1;
|
||||||
|
|
||||||
|
// Find the part inside the http://{....}/
|
||||||
|
if (strcmpstart(target, "http://")) {
|
||||||
|
log_warn(LD_CONFIG, "Unsupported URL scheme in authority flag %s", flag);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
const char *addr = target + strlen("http://");
|
||||||
|
|
||||||
|
const char *eos = strchr(addr, '/');
|
||||||
|
size_t addr_len;
|
||||||
|
if (eos && strcmp(eos, "/")) {
|
||||||
|
log_warn(LD_CONFIG, "Unsupported URL prefix in authority flag %s", flag);
|
||||||
|
return -1;
|
||||||
|
} else if (eos) {
|
||||||
|
addr_len = eos - addr;
|
||||||
|
} else {
|
||||||
|
addr_len = strlen(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, parse the addr:port part.
|
||||||
|
char *addr_string = tor_strndup(addr, addr_len);
|
||||||
|
tor_addr_port_t dirport;
|
||||||
|
memset(&dirport, 0, sizeof(dirport));
|
||||||
|
int rv = tor_addr_port_parse(LOG_WARN, addr_string,
|
||||||
|
&dirport.addr, &dirport.port, -1);
|
||||||
|
if (ds != NULL && rv == 0) {
|
||||||
|
trusted_dir_server_add_dirport(ds, usage, &dirport);
|
||||||
|
} else if (rv == -1) {
|
||||||
|
log_warn(LD_CONFIG, "Unable to parse address in authority flag %s",flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
tor_free(addr_string);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
/** Read the contents of a DirAuthority line from <b>line</b>. If
|
/** Read the contents of a DirAuthority line from <b>line</b>. If
|
||||||
* <b>validate_only</b> is 0, and the line is well-formed, and it
|
* <b>validate_only</b> is 0, and the line is well-formed, and it
|
||||||
* shares any bits with <b>required_type</b> or <b>required_type</b>
|
* shares any bits with <b>required_type</b> or <b>required_type</b>
|
||||||
|
@ -5486,6 +5557,7 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
|
||||||
char v3_digest[DIGEST_LEN];
|
char v3_digest[DIGEST_LEN];
|
||||||
dirinfo_type_t type = 0;
|
dirinfo_type_t type = 0;
|
||||||
double weight = 1.0;
|
double weight = 1.0;
|
||||||
|
smartlist_t *extra_dirports = smartlist_new();
|
||||||
|
|
||||||
memset(v3_digest, 0, sizeof(v3_digest));
|
memset(v3_digest, 0, sizeof(v3_digest));
|
||||||
|
|
||||||
|
@ -5554,6 +5626,12 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
|
||||||
}
|
}
|
||||||
ipv6_addrport_ptr = &ipv6_addrport;
|
ipv6_addrport_ptr = &ipv6_addrport;
|
||||||
}
|
}
|
||||||
|
} else if (!strcasecmpstart(flag, "upload=") ||
|
||||||
|
!strcasecmpstart(flag, "download=") ||
|
||||||
|
!strcasecmpstart(flag, "vote=")) {
|
||||||
|
// We'll handle these after creating the authority object.
|
||||||
|
smartlist_add(extra_dirports, flag);
|
||||||
|
flag = NULL; // prevent double-free.
|
||||||
} else {
|
} else {
|
||||||
log_warn(LD_CONFIG, "Unrecognized flag '%s' on DirAuthority line",
|
log_warn(LD_CONFIG, "Unrecognized flag '%s' on DirAuthority line",
|
||||||
flag);
|
flag);
|
||||||
|
@ -5597,6 +5675,13 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (validate_only) {
|
||||||
|
SMARTLIST_FOREACH_BEGIN(extra_dirports, const char *, cp) {
|
||||||
|
if (parse_dirauth_dirport(NULL, cp) < 0)
|
||||||
|
goto err;
|
||||||
|
} SMARTLIST_FOREACH_END(cp);
|
||||||
|
}
|
||||||
|
|
||||||
if (!validate_only && (!required_type || required_type & type)) {
|
if (!validate_only && (!required_type || required_type & type)) {
|
||||||
dir_server_t *ds;
|
dir_server_t *ds;
|
||||||
if (required_type)
|
if (required_type)
|
||||||
|
@ -5608,16 +5693,23 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
|
||||||
ipv6_addrport_ptr,
|
ipv6_addrport_ptr,
|
||||||
digest, v3_digest, type, weight)))
|
digest, v3_digest, type, weight)))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
SMARTLIST_FOREACH_BEGIN(extra_dirports, const char *, cp) {
|
||||||
|
if (parse_dirauth_dirport(ds, cp) < 0)
|
||||||
|
goto err;
|
||||||
|
} SMARTLIST_FOREACH_END(cp);
|
||||||
dir_server_add(ds);
|
dir_server_add(ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
r = 0;
|
r = 0;
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
r = -1;
|
r = -1;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
SMARTLIST_FOREACH(extra_dirports, char*, s, tor_free(s));
|
||||||
|
smartlist_free(extra_dirports);
|
||||||
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
|
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
|
||||||
smartlist_free(items);
|
smartlist_free(items);
|
||||||
tor_free(addrport);
|
tor_free(addrport);
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
#include "core/or/or.h"
|
#include "core/or/or.h"
|
||||||
#include "feature/nodelist/routerstatus_st.h"
|
#include "feature/nodelist/routerstatus_st.h"
|
||||||
|
|
||||||
|
struct smartlist_t;
|
||||||
|
|
||||||
/** Represents information about a single trusted or fallback directory
|
/** Represents information about a single trusted or fallback directory
|
||||||
* server. */
|
* server. */
|
||||||
struct dir_server_t {
|
struct dir_server_t {
|
||||||
|
@ -48,6 +50,10 @@ struct dir_server_t {
|
||||||
time_t addr_current_at; /**< When was the document that we derived the
|
time_t addr_current_at; /**< When was the document that we derived the
|
||||||
* address information from published? */
|
* address information from published? */
|
||||||
|
|
||||||
|
/** Authority only. Can be null. If present, a list of auth_dirport_t
|
||||||
|
* representing HTTP dirports for this authority. */
|
||||||
|
struct smartlist_t *auth_dirports;
|
||||||
|
|
||||||
routerstatus_t fake_status; /**< Used when we need to pass this trusted
|
routerstatus_t fake_status; /**< Used when we need to pass this trusted
|
||||||
* dir_server_t to
|
* dir_server_t to
|
||||||
* directory_request_set_routerstatus.
|
* directory_request_set_routerstatus.
|
||||||
|
|
|
@ -1119,6 +1119,7 @@ directory_request_set_routerstatus(directory_request_t *req,
|
||||||
{
|
{
|
||||||
req->routerstatus = status;
|
req->routerstatus = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper: update the addresses, ports, and identities in <b>req</b>
|
* Helper: update the addresses, ports, and identities in <b>req</b>
|
||||||
* from the routerstatus object in <b>req</b>. Return 0 on success.
|
* from the routerstatus object in <b>req</b>. Return 0 on success.
|
||||||
|
@ -1161,7 +1162,7 @@ directory_request_set_dir_from_routerstatus(directory_request_t *req)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* At this point, if we are a client making a direct connection to a
|
/* At this point, if we are a client making a direct connection to a
|
||||||
* directory server, we have selected a server that has at least one address
|
* directory server, we have selected a server that has at least one address
|
||||||
* allowed by ClientUseIPv4/6 and Reachable{"",OR,Dir}Addresses. This
|
* allowed by ClientUseIPv4/6 and Reachable{"",OR,Dir}Addresses. This
|
||||||
* selection uses the preference in ClientPreferIPv6{OR,Dir}Port, if
|
* selection uses the preference in ClientPreferIPv6{OR,Dir}Port, if
|
||||||
|
@ -1176,6 +1177,37 @@ directory_request_set_dir_from_routerstatus(directory_request_t *req)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* One last thing: If we're talking to an authority, we might want to use
|
||||||
|
* a special HTTP port for it based on our purpose.
|
||||||
|
*/
|
||||||
|
if (req->indirection == DIRIND_DIRECT_CONN && status->is_authority) {
|
||||||
|
const dir_server_t *ds = router_get_trusteddirserver_by_digest(
|
||||||
|
status->identity_digest);
|
||||||
|
if (ds) {
|
||||||
|
const tor_addr_port_t *v4 = NULL;
|
||||||
|
if (authdir_mode_v3(get_options())) {
|
||||||
|
// An authority connecting to another authority should always
|
||||||
|
// prefer the VOTING usage, if one is specifically configured.
|
||||||
|
v4 = trusted_dir_server_get_dirport_exact(
|
||||||
|
ds, AUTH_USAGE_VOTING, AF_INET);
|
||||||
|
}
|
||||||
|
if (! v4) {
|
||||||
|
// Everybody else should prefer a usage dependent on their
|
||||||
|
// the dir_purpose.
|
||||||
|
auth_dirport_usage_t usage =
|
||||||
|
auth_dirport_usage_for_purpose(req->dir_purpose);
|
||||||
|
v4 = trusted_dir_server_get_dirport(ds, usage, AF_INET);
|
||||||
|
}
|
||||||
|
tor_assert_nonfatal(v4);
|
||||||
|
if (v4) {
|
||||||
|
// XXXX We could, if we wanted, also select a v6 address. But a v4
|
||||||
|
// address must exist here, and we as a relay are required to support
|
||||||
|
// ipv4. So we just that.
|
||||||
|
tor_addr_port_copy(&use_dir_ap, v4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
directory_request_set_or_addr_port(req, &use_or_ap);
|
directory_request_set_or_addr_port(req, &use_or_ap);
|
||||||
directory_request_set_dir_addr_port(req, &use_dir_ap);
|
directory_request_set_dir_addr_port(req, &use_dir_ap);
|
||||||
directory_request_set_directory_id_digest(req, status->identity_digest);
|
directory_request_set_directory_id_digest(req, status->identity_digest);
|
||||||
|
@ -1194,7 +1226,7 @@ directory_initiate_request,(directory_request_t *request))
|
||||||
tor_assert_nonfatal(
|
tor_assert_nonfatal(
|
||||||
! directory_request_dir_contact_info_specified(request));
|
! directory_request_dir_contact_info_specified(request));
|
||||||
if (directory_request_set_dir_from_routerstatus(request) < 0) {
|
if (directory_request_set_dir_from_routerstatus(request) < 0) {
|
||||||
return;
|
return; // or here XXXX
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1309,6 +1341,8 @@ directory_initiate_request,(directory_request_t *request))
|
||||||
entry_guard_cancel(&guard_state);
|
entry_guard_cancel(&guard_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXXX This is the case where we replace.
|
||||||
|
|
||||||
switch (connection_connect(TO_CONN(conn), conn->base_.address, &addr,
|
switch (connection_connect(TO_CONN(conn), conn->base_.address, &addr,
|
||||||
port, &socket_error)) {
|
port, &socket_error)) {
|
||||||
case -1:
|
case -1:
|
||||||
|
|
|
@ -43,6 +43,14 @@
|
||||||
#include "feature/dirclient/dir_server_st.h"
|
#include "feature/dirclient/dir_server_st.h"
|
||||||
#include "feature/nodelist/node_st.h"
|
#include "feature/nodelist/node_st.h"
|
||||||
|
|
||||||
|
/** Information about an (HTTP) dirport for a directory authority. */
|
||||||
|
struct auth_dirport_t {
|
||||||
|
/** What is the intended usage for this dirport? One of AUTH_USAGE_* */
|
||||||
|
auth_dirport_usage_t usage;
|
||||||
|
/** What is the correct address/port ? */
|
||||||
|
tor_addr_port_t dirport;
|
||||||
|
};
|
||||||
|
|
||||||
/** Global list of a dir_server_t object for each directory
|
/** Global list of a dir_server_t object for each directory
|
||||||
* authority. */
|
* authority. */
|
||||||
static smartlist_t *trusted_dir_servers = NULL;
|
static smartlist_t *trusted_dir_servers = NULL;
|
||||||
|
@ -66,6 +74,11 @@ add_trusted_dir_to_nodelist_addr_set(const dir_server_t *dir)
|
||||||
/* IPv6 DirPort is not a thing yet for authorities. */
|
/* IPv6 DirPort is not a thing yet for authorities. */
|
||||||
nodelist_add_addr_to_address_set(&dir->ipv6_addr, dir->ipv6_orport, 0);
|
nodelist_add_addr_to_address_set(&dir->ipv6_addr, dir->ipv6_orport, 0);
|
||||||
}
|
}
|
||||||
|
if (dir->auth_dirports) {
|
||||||
|
SMARTLIST_FOREACH_BEGIN(dir->auth_dirports, const auth_dirport_t *, p) {
|
||||||
|
nodelist_add_addr_to_address_set(&p->dirport.addr, 0, p->dirport.port);
|
||||||
|
} SMARTLIST_FOREACH_END(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Go over the trusted directory server list and add their address(es) to the
|
/** Go over the trusted directory server list and add their address(es) to the
|
||||||
|
@ -256,7 +269,10 @@ MOCK_IMPL(int, router_digest_is_trusted_dir_type,
|
||||||
/** Return true iff the given address matches a trusted directory that matches
|
/** Return true iff the given address matches a trusted directory that matches
|
||||||
* at least one bit of type.
|
* at least one bit of type.
|
||||||
*
|
*
|
||||||
* If type is NO_DIRINFO or ALL_DIRINFO, any authority is matched. */
|
* If type is NO_DIRINFO or ALL_DIRINFO, any authority is matched.
|
||||||
|
*
|
||||||
|
* Only ORPorts' addresses are considered.
|
||||||
|
*/
|
||||||
bool
|
bool
|
||||||
router_addr_is_trusted_dir_type(const tor_addr_t *addr, dirinfo_type_t type)
|
router_addr_is_trusted_dir_type(const tor_addr_t *addr, dirinfo_type_t type)
|
||||||
{
|
{
|
||||||
|
@ -281,6 +297,42 @@ router_addr_is_trusted_dir_type(const tor_addr_t *addr, dirinfo_type_t type)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return an appropriate usage value describing which authdir port to use
|
||||||
|
* for a given directory connection purpose.
|
||||||
|
*/
|
||||||
|
auth_dirport_usage_t
|
||||||
|
auth_dirport_usage_for_purpose(int purpose)
|
||||||
|
{
|
||||||
|
switch (purpose) {
|
||||||
|
case DIR_PURPOSE_FETCH_SERVERDESC:
|
||||||
|
case DIR_PURPOSE_FETCH_EXTRAINFO:
|
||||||
|
case DIR_PURPOSE_FETCH_CONSENSUS:
|
||||||
|
case DIR_PURPOSE_FETCH_CERTIFICATE:
|
||||||
|
case DIR_PURPOSE_FETCH_MICRODESC:
|
||||||
|
return AUTH_USAGE_DOWNLOAD;
|
||||||
|
|
||||||
|
case DIR_PURPOSE_UPLOAD_DIR:
|
||||||
|
return AUTH_USAGE_UPLOAD;
|
||||||
|
|
||||||
|
case DIR_PURPOSE_UPLOAD_VOTE:
|
||||||
|
case DIR_PURPOSE_UPLOAD_SIGNATURES:
|
||||||
|
case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
|
||||||
|
case DIR_PURPOSE_FETCH_STATUS_VOTE:
|
||||||
|
return AUTH_USAGE_VOTING;
|
||||||
|
|
||||||
|
case DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2:
|
||||||
|
case DIR_PURPOSE_SERVER:
|
||||||
|
case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
|
||||||
|
case DIR_PURPOSE_FETCH_RENDDESC_V2:
|
||||||
|
case DIR_PURPOSE_UPLOAD_HSDESC:
|
||||||
|
case DIR_PURPOSE_FETCH_HSDESC:
|
||||||
|
case DIR_PURPOSE_HAS_FETCHED_HSDESC:
|
||||||
|
default:
|
||||||
|
tor_assert_nonfatal_unreached();
|
||||||
|
return AUTH_USAGE_LEGACY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Create a directory server at <b>address</b>:<b>port</b>, with OR identity
|
/** Create a directory server at <b>address</b>:<b>port</b>, with OR identity
|
||||||
* key <b>digest</b> which has DIGEST_LEN bytes. If <b>address</b> is NULL,
|
* key <b>digest</b> which has DIGEST_LEN bytes. If <b>address</b> is NULL,
|
||||||
* add ourself. If <b>is_authority</b>, this is a directory authority. Return
|
* add ourself. If <b>is_authority</b>, this is a directory authority. Return
|
||||||
|
@ -357,6 +409,7 @@ dir_server_new(int is_authority,
|
||||||
ent->fake_status.ipv4_dirport = ent->ipv4_dirport;
|
ent->fake_status.ipv4_dirport = ent->ipv4_dirport;
|
||||||
ent->fake_status.ipv4_orport = ent->ipv4_orport;
|
ent->fake_status.ipv4_orport = ent->ipv4_orport;
|
||||||
ent->fake_status.ipv6_orport = ent->ipv6_orport;
|
ent->fake_status.ipv6_orport = ent->ipv6_orport;
|
||||||
|
ent->fake_status.is_authority = !! is_authority;
|
||||||
|
|
||||||
return ent;
|
return ent;
|
||||||
}
|
}
|
||||||
|
@ -404,10 +457,98 @@ trusted_dir_server_new(const char *nickname, const char *address,
|
||||||
ipv6_addrport,
|
ipv6_addrport,
|
||||||
digest,
|
digest,
|
||||||
v3_auth_digest, type, weight);
|
v3_auth_digest, type, weight);
|
||||||
|
|
||||||
|
if (ipv4_dirport) {
|
||||||
|
tor_addr_port_t p;
|
||||||
|
memset(&p, 0, sizeof(p));
|
||||||
|
tor_addr_copy(&p.addr, &ipv4_addr);
|
||||||
|
p.port = ipv4_dirport;
|
||||||
|
trusted_dir_server_add_dirport(result, AUTH_USAGE_LEGACY, &p);
|
||||||
|
}
|
||||||
tor_free(hostname);
|
tor_free(hostname);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add @a dirport as an HTTP DirPort contact point for the directory authority
|
||||||
|
* @a ds, for use when contacting that authority for the given @a usage.
|
||||||
|
*
|
||||||
|
* Multiple ports of the same usage are allowed; if present, then only
|
||||||
|
* the first one of each address family is currently used.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
trusted_dir_server_add_dirport(dir_server_t *ds,
|
||||||
|
auth_dirport_usage_t usage,
|
||||||
|
const tor_addr_port_t *dirport)
|
||||||
|
{
|
||||||
|
tor_assert(ds);
|
||||||
|
tor_assert(dirport);
|
||||||
|
|
||||||
|
if (BUG(! ds->is_authority)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ds->auth_dirports == NULL) {
|
||||||
|
ds->auth_dirports = smartlist_new();
|
||||||
|
}
|
||||||
|
|
||||||
|
auth_dirport_t *port = tor_malloc_zero(sizeof(auth_dirport_t));
|
||||||
|
port->usage = usage;
|
||||||
|
tor_addr_port_copy(&port->dirport, dirport);
|
||||||
|
smartlist_add(ds->auth_dirports, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for trusted_dir_server_get_dirport: only return the exact requested
|
||||||
|
* usage type.
|
||||||
|
*/
|
||||||
|
const tor_addr_port_t *
|
||||||
|
trusted_dir_server_get_dirport_exact(const dir_server_t *ds,
|
||||||
|
auth_dirport_usage_t usage,
|
||||||
|
int addr_family)
|
||||||
|
{
|
||||||
|
tor_assert(ds);
|
||||||
|
tor_assert_nonfatal(addr_family == AF_INET || addr_family == AF_INET6);
|
||||||
|
if (ds->auth_dirports == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
SMARTLIST_FOREACH_BEGIN(ds->auth_dirports, const auth_dirport_t *, port) {
|
||||||
|
if (port->usage == usage &&
|
||||||
|
tor_addr_family(&port->dirport.addr) == addr_family) {
|
||||||
|
return &port->dirport;
|
||||||
|
}
|
||||||
|
} SMARTLIST_FOREACH_END(port);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the DirPort of the authority @a ds for with the usage type
|
||||||
|
* @a usage and address family @a addr_family. If none is found, try
|
||||||
|
* again with an AUTH_USAGE_LEGACY dirport, if there is one. Return NULL
|
||||||
|
* if no port can be found.
|
||||||
|
*/
|
||||||
|
const tor_addr_port_t *
|
||||||
|
trusted_dir_server_get_dirport(const dir_server_t *ds,
|
||||||
|
auth_dirport_usage_t usage,
|
||||||
|
int addr_family)
|
||||||
|
{
|
||||||
|
const tor_addr_port_t *port;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
port = trusted_dir_server_get_dirport_exact(ds, usage, addr_family);
|
||||||
|
if (port)
|
||||||
|
return port;
|
||||||
|
|
||||||
|
// If we tried LEGACY, there is no fallback from this point.
|
||||||
|
if (usage == AUTH_USAGE_LEGACY)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Try again with LEGACY.
|
||||||
|
usage = AUTH_USAGE_LEGACY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Return a new dir_server_t for a fallback directory server at
|
/** Return a new dir_server_t for a fallback directory server at
|
||||||
* <b>addr</b>:<b>or_port</b>/<b>dir_port</b>, with identity key digest
|
* <b>addr</b>:<b>or_port</b>/<b>dir_port</b>, with identity key digest
|
||||||
* <b>id_digest</b> */
|
* <b>id_digest</b> */
|
||||||
|
@ -447,6 +588,10 @@ dir_server_free_(dir_server_t *ds)
|
||||||
if (!ds)
|
if (!ds)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (ds->auth_dirports) {
|
||||||
|
SMARTLIST_FOREACH(ds->auth_dirports, auth_dirport_t *, p, tor_free(p));
|
||||||
|
smartlist_free(ds->auth_dirports);
|
||||||
|
}
|
||||||
tor_free(ds->nickname);
|
tor_free(ds->nickname);
|
||||||
tor_free(ds->description);
|
tor_free(ds->description);
|
||||||
tor_free(ds->address);
|
tor_free(ds->address);
|
||||||
|
|
|
@ -11,6 +11,28 @@
|
||||||
#ifndef TOR_DIRLIST_H
|
#ifndef TOR_DIRLIST_H
|
||||||
#define TOR_DIRLIST_H
|
#define TOR_DIRLIST_H
|
||||||
|
|
||||||
|
typedef struct auth_dirport_t auth_dirport_t;
|
||||||
|
/**
|
||||||
|
* Different usages for an authority's HTTP directory port.
|
||||||
|
*
|
||||||
|
* Historically, only legacy ports existed; proposal 330 added multiple types
|
||||||
|
* of dirport to better enable authorities to offload work and resist DoS
|
||||||
|
* attacks.
|
||||||
|
**/
|
||||||
|
typedef enum auth_dirport_usage_t {
|
||||||
|
/** Flag for an authority's dirport that is intended for misc/legacy
|
||||||
|
* usage. May be used when no other dirport is available. */
|
||||||
|
AUTH_USAGE_LEGACY,
|
||||||
|
/** Flag for an authority's dirport that is intended for descriptor uploads
|
||||||
|
* only. */
|
||||||
|
AUTH_USAGE_UPLOAD,
|
||||||
|
/** Flag for an authority's dirport that is intended for voting only */
|
||||||
|
AUTH_USAGE_VOTING,
|
||||||
|
/** Flag for an authority's dirport that is intended for relay downloads
|
||||||
|
* only. */
|
||||||
|
AUTH_USAGE_DOWNLOAD,
|
||||||
|
} auth_dirport_usage_t;
|
||||||
|
|
||||||
int get_n_authorities(dirinfo_type_t type);
|
int get_n_authorities(dirinfo_type_t type);
|
||||||
const smartlist_t *router_get_trusted_dir_servers(void);
|
const smartlist_t *router_get_trusted_dir_servers(void);
|
||||||
const smartlist_t *router_get_fallback_dir_servers(void);
|
const smartlist_t *router_get_fallback_dir_servers(void);
|
||||||
|
@ -18,6 +40,8 @@ smartlist_t *router_get_trusted_dir_servers_mutable(void);
|
||||||
smartlist_t *router_get_fallback_dir_servers_mutable(void);
|
smartlist_t *router_get_fallback_dir_servers_mutable(void);
|
||||||
void mark_all_dirservers_up(smartlist_t *server_list);
|
void mark_all_dirservers_up(smartlist_t *server_list);
|
||||||
|
|
||||||
|
auth_dirport_usage_t auth_dirport_usage_for_purpose(int purpose);
|
||||||
|
|
||||||
dir_server_t *router_get_trusteddirserver_by_digest(const char *d);
|
dir_server_t *router_get_trusteddirserver_by_digest(const char *d);
|
||||||
dir_server_t *router_get_fallback_dirserver_by_digest(
|
dir_server_t *router_get_fallback_dirserver_by_digest(
|
||||||
const char *digest);
|
const char *digest);
|
||||||
|
@ -28,6 +52,14 @@ MOCK_DECL(dir_server_t *, trusteddirserver_get_by_v3_auth_digest,
|
||||||
MOCK_DECL(int, router_digest_is_trusted_dir_type,
|
MOCK_DECL(int, router_digest_is_trusted_dir_type,
|
||||||
(const char *digest, dirinfo_type_t type));
|
(const char *digest, dirinfo_type_t type));
|
||||||
|
|
||||||
|
const tor_addr_port_t *trusted_dir_server_get_dirport(const dir_server_t *ds,
|
||||||
|
auth_dirport_usage_t usage,
|
||||||
|
int addr_family);
|
||||||
|
const tor_addr_port_t *trusted_dir_server_get_dirport_exact(
|
||||||
|
const dir_server_t *ds,
|
||||||
|
auth_dirport_usage_t usage,
|
||||||
|
int addr_family);
|
||||||
|
|
||||||
bool router_addr_is_trusted_dir_type(const tor_addr_t *addr,
|
bool router_addr_is_trusted_dir_type(const tor_addr_t *addr,
|
||||||
dirinfo_type_t type);
|
dirinfo_type_t type);
|
||||||
#define router_addr_is_trusted_dir(d) \
|
#define router_addr_is_trusted_dir(d) \
|
||||||
|
@ -41,6 +73,9 @@ dir_server_t *trusted_dir_server_new(const char *nickname, const char *address,
|
||||||
const tor_addr_port_t *addrport_ipv6,
|
const tor_addr_port_t *addrport_ipv6,
|
||||||
const char *digest, const char *v3_auth_digest,
|
const char *digest, const char *v3_auth_digest,
|
||||||
dirinfo_type_t type, double weight);
|
dirinfo_type_t type, double weight);
|
||||||
|
void trusted_dir_server_add_dirport(dir_server_t *ds,
|
||||||
|
auth_dirport_usage_t usage,
|
||||||
|
const tor_addr_port_t *dirport);
|
||||||
dir_server_t *fallback_dir_server_new(const tor_addr_t *addr,
|
dir_server_t *fallback_dir_server_new(const tor_addr_t *addr,
|
||||||
uint16_t dir_port, uint16_t or_port,
|
uint16_t dir_port, uint16_t or_port,
|
||||||
const tor_addr_port_t *addrport_ipv6,
|
const tor_addr_port_t *addrport_ipv6,
|
||||||
|
|
|
@ -170,6 +170,7 @@ src_test_test_SOURCES += \
|
||||||
src/test/test_crypto_rng.c \
|
src/test/test_crypto_rng.c \
|
||||||
src/test/test_data.c \
|
src/test/test_data.c \
|
||||||
src/test/test_dir.c \
|
src/test/test_dir.c \
|
||||||
|
src/test/test_dirauth_ports.c \
|
||||||
src/test/test_dirvote.c \
|
src/test/test_dirvote.c \
|
||||||
src/test/test_dir_common.c \
|
src/test/test_dir_common.c \
|
||||||
src/test/test_dir_handle_get.c \
|
src/test/test_dir_handle_get.c \
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
/* Copyright (c) 2001-2004, Roger Dingledine.
|
/* Copyright (c) 2001-2004, Roger Dingledine.
|
||||||
->a * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
|
||||||
* Copyright (c) 2007-2021, The Tor Project, Inc. */
|
* Copyright (c) 2007-2021, The Tor Project, Inc. */
|
||||||
/* See LICENSE for licensing information */
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
@ -673,6 +672,7 @@ struct testgroup_t testgroups[] = {
|
||||||
{ "crypto/pem/", pem_tests },
|
{ "crypto/pem/", pem_tests },
|
||||||
{ "crypto/rng/", crypto_rng_tests },
|
{ "crypto/rng/", crypto_rng_tests },
|
||||||
{ "dir/", dir_tests },
|
{ "dir/", dir_tests },
|
||||||
|
{ "dir/auth/ports/", dirauth_port_tests },
|
||||||
{ "dir/auth/process_descs/", process_descs_tests },
|
{ "dir/auth/process_descs/", process_descs_tests },
|
||||||
{ "dir/md/", microdesc_tests },
|
{ "dir/md/", microdesc_tests },
|
||||||
{ "dirauth/dirvote/", dirvote_tests},
|
{ "dirauth/dirvote/", dirvote_tests},
|
||||||
|
|
|
@ -120,6 +120,7 @@ extern struct testcase_t crypto_ope_tests[];
|
||||||
extern struct testcase_t crypto_openssl_tests[];
|
extern struct testcase_t crypto_openssl_tests[];
|
||||||
extern struct testcase_t crypto_rng_tests[];
|
extern struct testcase_t crypto_rng_tests[];
|
||||||
extern struct testcase_t crypto_tests[];
|
extern struct testcase_t crypto_tests[];
|
||||||
|
extern struct testcase_t dirauth_port_tests[];
|
||||||
extern struct testcase_t dir_handle_get_tests[];
|
extern struct testcase_t dir_handle_get_tests[];
|
||||||
extern struct testcase_t dir_tests[];
|
extern struct testcase_t dir_tests[];
|
||||||
extern struct testcase_t dirvote_tests[];
|
extern struct testcase_t dirvote_tests[];
|
||||||
|
|
152
src/test/test_dirauth_ports.c
Normal file
152
src/test/test_dirauth_ports.c
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
/* Copyright (c) 2001-2004, Roger Dingledine.
|
||||||
|
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||||
|
* Copyright (c) 2007-2021, The Tor Project, Inc. */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
#include "orconfig.h"
|
||||||
|
#define CONFIG_PRIVATE
|
||||||
|
|
||||||
|
#include "core/or/or.h"
|
||||||
|
#include "feature/dirclient/dir_server_st.h"
|
||||||
|
#include "feature/nodelist/dirlist.h"
|
||||||
|
#include "app/config/config.h"
|
||||||
|
#include "test/test.h"
|
||||||
|
#include "test/log_test_helpers.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_dirauth_port_parsing(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
// This one is okay.
|
||||||
|
int rv = parse_dir_authority_line(
|
||||||
|
"moria1 orport=9101 "
|
||||||
|
"v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
|
||||||
|
"upload=http://128.31.0.39:9131/ "
|
||||||
|
"download=http://128.31.0.39:9131 "
|
||||||
|
"vote=http://128.31.0.39:9131/ "
|
||||||
|
"128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
|
||||||
|
NO_DIRINFO, 1);
|
||||||
|
tt_int_op(rv,OP_EQ,0);
|
||||||
|
|
||||||
|
// These have bad syntax.
|
||||||
|
setup_capture_of_logs(LOG_WARN);
|
||||||
|
rv = parse_dir_authority_line(
|
||||||
|
"moria1 orport=9101 "
|
||||||
|
"v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
|
||||||
|
"uploadx=http://128.31.0.39:9131/ "
|
||||||
|
"128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
|
||||||
|
NO_DIRINFO, 1);
|
||||||
|
tt_int_op(rv,OP_EQ,0);
|
||||||
|
expect_log_msg_containing("Unrecognized flag");
|
||||||
|
mock_clean_saved_logs();
|
||||||
|
|
||||||
|
rv = parse_dir_authority_line(
|
||||||
|
"moria1 orport=9101 "
|
||||||
|
"v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
|
||||||
|
"upload=https://128.31.0.39:9131/ " // https is not recognized
|
||||||
|
"128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
|
||||||
|
NO_DIRINFO, 1);
|
||||||
|
tt_int_op(rv,OP_EQ,-1);
|
||||||
|
expect_log_msg_containing("Unsupported URL scheme");
|
||||||
|
mock_clean_saved_logs();
|
||||||
|
|
||||||
|
rv = parse_dir_authority_line(
|
||||||
|
"moria1 orport=9101 "
|
||||||
|
"v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
|
||||||
|
"upload=http://128.31.0.39:9131/tor " // suffix is not supported
|
||||||
|
"128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
|
||||||
|
NO_DIRINFO, 1);
|
||||||
|
tt_int_op(rv,OP_EQ,-1);
|
||||||
|
expect_log_msg_containing("Unsupported URL prefix");
|
||||||
|
mock_clean_saved_logs();
|
||||||
|
|
||||||
|
rv = parse_dir_authority_line(
|
||||||
|
"moria1 orport=9101 "
|
||||||
|
"v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
|
||||||
|
"upload=http://128.31.0.256:9131/ " // "256" is not ipv4.
|
||||||
|
"128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
|
||||||
|
NO_DIRINFO, 1);
|
||||||
|
tt_int_op(rv,OP_EQ,-1);
|
||||||
|
expect_log_msg_containing("Unable to parse address");
|
||||||
|
|
||||||
|
rv = parse_dir_authority_line(
|
||||||
|
"moria1 orport=9101 "
|
||||||
|
"v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
|
||||||
|
"upload=http://xyz.example.com/ " // hostnames not supported.
|
||||||
|
"128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
|
||||||
|
NO_DIRINFO, 1);
|
||||||
|
tt_int_op(rv,OP_EQ,-1);
|
||||||
|
expect_log_msg_containing("Unable to parse address");
|
||||||
|
|
||||||
|
done:
|
||||||
|
teardown_capture_of_logs();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_dirauth_port_lookup(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
clear_dir_servers();
|
||||||
|
|
||||||
|
int rv = parse_dir_authority_line(
|
||||||
|
"moria1 orport=9101 "
|
||||||
|
"v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
|
||||||
|
"upload=http://128.31.0.40:9132/ "
|
||||||
|
"download=http://128.31.0.41:9133 "
|
||||||
|
"vote=http://128.31.0.42:9134/ "
|
||||||
|
"128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
|
||||||
|
NO_DIRINFO, 0);
|
||||||
|
tt_int_op(rv,OP_EQ,0);
|
||||||
|
|
||||||
|
rv = parse_dir_authority_line(
|
||||||
|
"morgoth orport=9101 "
|
||||||
|
"v3ident=D586D18309DED4CDFFFFFFFFDB97EFA96D330566 "
|
||||||
|
"upload=http://128.31.0.43:9140/ "
|
||||||
|
"128.31.0.44:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
|
||||||
|
NO_DIRINFO, 0);
|
||||||
|
tt_int_op(rv,OP_EQ,0);
|
||||||
|
|
||||||
|
const smartlist_t *servers = router_get_trusted_dir_servers();
|
||||||
|
tt_assert(servers);
|
||||||
|
tt_int_op(smartlist_len(servers), OP_EQ, 2);
|
||||||
|
const dir_server_t *moria = smartlist_get(servers, 0);
|
||||||
|
const dir_server_t *morgoth = smartlist_get(servers, 1);
|
||||||
|
tt_str_op(moria->nickname, OP_EQ, "moria1");
|
||||||
|
tt_str_op(morgoth->nickname, OP_EQ, "morgoth");
|
||||||
|
|
||||||
|
const tor_addr_port_t *dirport;
|
||||||
|
|
||||||
|
dirport = trusted_dir_server_get_dirport(moria,
|
||||||
|
AUTH_USAGE_UPLOAD, AF_INET);
|
||||||
|
tt_int_op(dirport->port, OP_EQ, 9132);
|
||||||
|
dirport = trusted_dir_server_get_dirport(moria,
|
||||||
|
AUTH_USAGE_DOWNLOAD, AF_INET);
|
||||||
|
tt_int_op(dirport->port, OP_EQ, 9133);
|
||||||
|
dirport = trusted_dir_server_get_dirport(moria,
|
||||||
|
AUTH_USAGE_VOTING, AF_INET);
|
||||||
|
tt_int_op(dirport->port, OP_EQ, 9134);
|
||||||
|
|
||||||
|
dirport = trusted_dir_server_get_dirport(morgoth,
|
||||||
|
AUTH_USAGE_UPLOAD, AF_INET);
|
||||||
|
tt_int_op(dirport->port, OP_EQ, 9140);
|
||||||
|
dirport = trusted_dir_server_get_dirport(morgoth,
|
||||||
|
AUTH_USAGE_DOWNLOAD, AF_INET);
|
||||||
|
tt_int_op(dirport->port, OP_EQ, 9131); // fallback
|
||||||
|
dirport = trusted_dir_server_get_dirport(morgoth,
|
||||||
|
AUTH_USAGE_VOTING, AF_INET);
|
||||||
|
tt_int_op(dirport->port, OP_EQ, 9131); // fallback
|
||||||
|
|
||||||
|
done:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define T(name) \
|
||||||
|
{ #name, test_dirauth_port_ ## name, TT_FORK, NULL, NULL }
|
||||||
|
|
||||||
|
struct testcase_t dirauth_port_tests[] = {
|
||||||
|
T(parsing),
|
||||||
|
T(lookup),
|
||||||
|
END_OF_TESTCASES
|
||||||
|
};
|
Loading…
Add table
Reference in a new issue