Add support for knowing multiple HTTP DirPorts for an authority.

(These aren't yet set or used.)
This commit is contained in:
Nick Mathewson 2021-02-23 14:09:03 -05:00
parent 97e51dd01b
commit 4e977cce40
3 changed files with 144 additions and 1 deletions

View File

@ -16,6 +16,8 @@
#include "core/or/or.h"
#include "feature/nodelist/routerstatus_st.h"
struct smartlist_t;
/** Represents information about a single trusted or fallback directory
* server. */
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
* 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
* dir_server_t to
* directory_request_set_routerstatus.

View File

@ -43,6 +43,14 @@
#include "feature/dirclient/dir_server_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
* authority. */
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. */
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
@ -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
* 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
router_addr_is_trusted_dir_type(const tor_addr_t *addr, dirinfo_type_t type)
{
@ -404,10 +420,98 @@ trusted_dir_server_new(const char *nickname, const char *address,
ipv6_addrport,
digest,
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);
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.
*/
static 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
* <b>addr</b>:<b>or_port</b>/<b>dir_port</b>, with identity key digest
* <b>id_digest</b> */
@ -447,6 +551,10 @@ dir_server_free_(dir_server_t *ds)
if (!ds)
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->description);
tor_free(ds->address);

View File

@ -11,6 +11,28 @@
#ifndef 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);
const smartlist_t *router_get_trusted_dir_servers(void);
const smartlist_t *router_get_fallback_dir_servers(void);
@ -28,6 +50,10 @@ MOCK_DECL(dir_server_t *, trusteddirserver_get_by_v3_auth_digest,
MOCK_DECL(int, router_digest_is_trusted_dir_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);
bool router_addr_is_trusted_dir_type(const tor_addr_t *addr,
dirinfo_type_t type);
#define router_addr_is_trusted_dir(d) \
@ -41,6 +67,9 @@ dir_server_t *trusted_dir_server_new(const char *nickname, const char *address,
const tor_addr_port_t *addrport_ipv6,
const char *digest, const char *v3_auth_digest,
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,
uint16_t dir_port, uint16_t or_port,
const tor_addr_port_t *addrport_ipv6,