mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-22 06:21:55 +01:00
r9318@Kushana: nickm | 2006-10-22 15:22:57 -0400
Let directory authorities set the BadExit flag if they like. Also, refactor directory authority code so we can believe multiple things about a single router, and do fewer linear searches. svn:r8794
This commit is contained in:
parent
833f8245c4
commit
42bab1c6d3
6 changed files with 228 additions and 180 deletions
|
@ -11,6 +11,8 @@ Changes in version 0.1.2.3-alpha - 2006-10-??
|
|||
- Directory servers now provide 'Pragma: no-cache' and 'Expires'
|
||||
headers for content, so that we can work better in the presence of
|
||||
caching HTTP proxies.
|
||||
- Allow authorities to list nodes as bad exits by fingerprint or by
|
||||
address.
|
||||
|
||||
o Minor features, controller:
|
||||
- Add a REASON field to CIRC events; for backward compatibility, this
|
||||
|
|
5
doc/TODO
5
doc/TODO
|
@ -70,7 +70,6 @@ x - We should ship with a list of stable dir mirrors -- they're not
|
|||
|
||||
N - Simplify authority operation
|
||||
- Follow weasel's proposal, crossed with mixminion dir config format
|
||||
- Reject/invalidate by IP.
|
||||
|
||||
- Servers are easy to setup and run: being a relay is about as easy as
|
||||
being a client.
|
||||
|
@ -279,7 +278,9 @@ d - Write limiting; separate token bucket for write
|
|||
- Implement
|
||||
|
||||
Minor items for 0.1.2.x as time permits:
|
||||
- some way for the authorities to set BadExit for some nodes manually.
|
||||
o Some way for the authorities to set BadExit for some nodes manually.
|
||||
- When we export something from foo.c file for testing purposes only,
|
||||
make a foo_test.h file for test.c to include.
|
||||
- "getinfo fingerprint" controller command
|
||||
- "setevent guards" controller command
|
||||
- The Debian package now uses --verify-config when (re)starting,
|
||||
|
|
14
doc/tor.1.in
14
doc/tor.1.in
|
@ -779,6 +779,12 @@ option is only useful for authoritative directories, so you probably
|
|||
don't want to use it.
|
||||
.LP
|
||||
.TP
|
||||
\fBAuthDirBadExit \fR\fIAddressPattern\fR...\fP
|
||||
Authoritative directories only. A set of address patterns for servers that
|
||||
will be listed as bad exits in any network status document this authority
|
||||
publishes, if \fBAuthDirListBadExits\fR is set.
|
||||
.LP
|
||||
.TP
|
||||
\fBAuthDirInvalid \fR\fIAddressPattern\fR...\fP
|
||||
Authoritative directories only. A set of address patterns for servers that
|
||||
will never be listed as "valid" in any network status document that this
|
||||
|
@ -792,6 +798,14 @@ authority publishes, or accepted as an OR address in any descriptor submitted
|
|||
for publication by this authority.
|
||||
.LP
|
||||
.TP
|
||||
\fBAuthDirListBadExits \fR\fB0\fR|\fB1\fR\fP
|
||||
Authoritative directories only. If set to 1, this directory has
|
||||
some opinion about which nodes are unsuitable as exit nodes. (Do not
|
||||
set this to 1 unless you plan to list nonfunctioning exits as bad;
|
||||
otherwise, you are effectively voting in favor of every declared exit
|
||||
as an exit.)
|
||||
.LP
|
||||
.TP
|
||||
\fBAuthDirRejectUnlisted \fR\fB0\fR|\fB1\fR\fP
|
||||
Authoritative directories only. If set to 1, the directory server
|
||||
rejects all uploaded server descriptors that aren't explicitly listed
|
||||
|
|
|
@ -128,9 +128,11 @@ static config_var_t _option_vars[] = {
|
|||
VAR("AllowInvalidNodes", CSV, AllowInvalidNodes,
|
||||
"middle,rendezvous"),
|
||||
VAR("AssumeReachable", BOOL, AssumeReachable, "0"),
|
||||
VAR("AuthDirBadExit", LINELIST, AuthDirReject, NULL),
|
||||
VAR("AuthDirInvalid", LINELIST, AuthDirInvalid, NULL),
|
||||
VAR("AuthDirReject", LINELIST, AuthDirReject, NULL),
|
||||
VAR("AuthDirRejectUnlisted",BOOL, AuthDirRejectUnlisted,"0"),
|
||||
VAR("AuthDirListBadExits", BOOL, AuthDirListBadExits, "0"),
|
||||
VAR("AuthoritativeDirectory",BOOL, AuthoritativeDir, "0"),
|
||||
VAR("AvoidDiskWrites", BOOL, AvoidDiskWrites, "0"),
|
||||
VAR("BandwidthBurst", MEMUNIT, BandwidthBurst, "6 MB"),
|
||||
|
|
373
src/or/dirserv.c
373
src/or/dirserv.c
|
@ -21,13 +21,6 @@ const char dirserv_c_id[] =
|
|||
* directory authorities. */
|
||||
#define MAX_UNTRUSTED_NETWORKSTATUSES 16
|
||||
|
||||
typedef enum {
|
||||
FP_NAMED, /**< Listed in fingerprint file. */
|
||||
FP_VALID, /**< Unlisted but believed valid. */
|
||||
FP_INVALID, /**< Believed invalid. */
|
||||
FP_REJECT, /**< We will not publish this router. */
|
||||
} router_status_t;
|
||||
|
||||
/** Do we need to regenerate the directory when someone asks for it? */
|
||||
static int the_directory_is_dirty = 1;
|
||||
static int runningrouters_is_dirty = 1;
|
||||
|
@ -37,11 +30,12 @@ static void directory_remove_invalid(void);
|
|||
static cached_dir_t *dirserv_regenerate_directory(void);
|
||||
static char *format_versions_list(config_line_t *ln);
|
||||
/* Should be static; exposed for testing */
|
||||
struct authdir_config_t;
|
||||
int add_fingerprint_to_dir(const char *nickname, const char *fp,
|
||||
smartlist_t *list);
|
||||
static router_status_t dirserv_router_get_status(const routerinfo_t *router,
|
||||
const char **msg);
|
||||
static router_status_t
|
||||
struct authdir_config_t *list);
|
||||
static uint32_t dirserv_router_get_status(const routerinfo_t *router,
|
||||
const char **msg);
|
||||
static uint32_t
|
||||
dirserv_get_status_impl(const char *fp, const char *nickname,
|
||||
const char *address,
|
||||
uint32_t addr, uint16_t or_port,
|
||||
|
@ -53,39 +47,57 @@ static void clear_cached_dir(cached_dir_t *d);
|
|||
|
||||
/************** Fingerprint handling code ************/
|
||||
|
||||
/** A member of fingerprint_list: maps a name to a fingerprint.
|
||||
**/
|
||||
typedef struct fingerprint_entry_t {
|
||||
char *nickname; /**< The name of a router (if this fingerprint is bound to a
|
||||
* name); the string "!reject" (if this fingerprint should
|
||||
* always be rejected); or the string "!invalid" (if this
|
||||
* fingerprint should be accepted but never marked as
|
||||
* valid. */
|
||||
char *fingerprint; /**< Stored as HEX_DIGEST_LEN characters, followed by a
|
||||
* NUL */
|
||||
} fingerprint_entry_t;
|
||||
#define FP_NAMED 1 /**< Listed in fingerprint file. */
|
||||
#define FP_INVALID 2 /**< Believed invalid. */
|
||||
#define FP_REJECT 4 /**< We will not publish this router. */
|
||||
#define FP_BADEXIT 8 /**< We'll tell clients not to use this as an exit. */
|
||||
|
||||
typedef struct router_status_t {
|
||||
char nickname[MAX_NICKNAME_LEN+1];
|
||||
uint32_t status;
|
||||
} router_status_t;
|
||||
|
||||
/** List of nickname-\>identity fingerprint mappings for all the routers
|
||||
* that we name. Used to prevent router impersonation. */
|
||||
* that we name. Used to prevent router impersonation. DODDOC */
|
||||
typedef struct authdir_config_t {
|
||||
strmap_t *fp_by_name; /* Map from lc nickname to fingerprint */
|
||||
digestmap_t *status_by_digest; /* Map from digest to FP_x mask */
|
||||
} authdir_config_t;
|
||||
|
||||
/* Should be static; exposed for testing */
|
||||
smartlist_t *fingerprint_list = NULL;
|
||||
authdir_config_t *fingerprint_list = NULL;
|
||||
|
||||
static authdir_config_t *
|
||||
authdir_config_new(void)
|
||||
{
|
||||
authdir_config_t *list = tor_malloc_zero(sizeof(authdir_config_t));
|
||||
list->fp_by_name = strmap_new();
|
||||
list->status_by_digest = digestmap_new();
|
||||
return list;
|
||||
}
|
||||
|
||||
/** Add the fingerprint <b>fp</b> for the nickname <b>nickname</b> to
|
||||
* the smartlist of fingerprint_entry_t's <b>list</b>. Return 0 if it's
|
||||
* new, or 1 if we replaced the old value.
|
||||
*/
|
||||
int /* Should be static; exposed for testing */
|
||||
add_fingerprint_to_dir(const char *nickname, const char *fp, smartlist_t *list)
|
||||
add_fingerprint_to_dir(const char *nickname, const char *fp,
|
||||
authdir_config_t *list)
|
||||
{
|
||||
int i;
|
||||
fingerprint_entry_t *ent;
|
||||
char *fingerprint;
|
||||
char d[DIGEST_LEN];
|
||||
router_status_t *status;
|
||||
tor_assert(nickname);
|
||||
tor_assert(fp);
|
||||
tor_assert(list);
|
||||
|
||||
fingerprint = tor_strdup(fp);
|
||||
tor_strstrip(fingerprint, " ");
|
||||
if (base16_decode(d, DIGEST_LEN, fingerprint, strlen(fingerprint))) {
|
||||
log_warn(LD_DIRSERV, "Couldn't decode fingerprint \"%s\"",
|
||||
escaped(fp));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) {
|
||||
log_warn(LD_DIRSERV, "Tried to add a mapping for reserved nickname %s",
|
||||
|
@ -93,20 +105,33 @@ add_fingerprint_to_dir(const char *nickname, const char *fp, smartlist_t *list)
|
|||
return 0;
|
||||
}
|
||||
|
||||
status = digestmap_get(list->status_by_digest, d);
|
||||
if (!status) {
|
||||
status = tor_malloc_zero(sizeof(router_status_t));
|
||||
digestmap_set(list->status_by_digest, d, status);
|
||||
}
|
||||
|
||||
if (nickname[0] != '!') {
|
||||
for (i = 0; i < smartlist_len(list); ++i) {
|
||||
ent = smartlist_get(list, i);
|
||||
if (!strcasecmp(ent->nickname,nickname)) {
|
||||
tor_free(ent->fingerprint);
|
||||
ent->fingerprint = fingerprint;
|
||||
return 1;
|
||||
char *old_fp = strmap_get_lc(list->fp_by_name, nickname);
|
||||
if (old_fp) {
|
||||
if (!strcasecmp(fingerprint, old_fp)) {
|
||||
tor_free(fingerprint);
|
||||
} else {
|
||||
tor_free(old_fp);
|
||||
strmap_set_lc(list->fp_by_name, nickname, fingerprint);
|
||||
}
|
||||
}
|
||||
status->status |= FP_NAMED;
|
||||
strlcpy(status->nickname, nickname, sizeof(status->nickname));
|
||||
} else {
|
||||
if (!strcasecmp(nickname, "!reject")) {
|
||||
status->status |= FP_REJECT;
|
||||
} else if (!strcasecmp(nickname, "!invalid")) {
|
||||
status->status |= FP_INVALID;
|
||||
} else if (!strcasecmp(nickname, "!badexit")) {
|
||||
status->status |= FP_BADEXIT;
|
||||
}
|
||||
}
|
||||
ent = tor_malloc(sizeof(fingerprint_entry_t));
|
||||
ent->nickname = tor_strdup(nickname);
|
||||
ent->fingerprint = fingerprint;
|
||||
smartlist_add(list, ent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -121,7 +146,7 @@ dirserv_add_own_fingerprint(const char *nickname, crypto_pk_env_t *pk)
|
|||
return -1;
|
||||
}
|
||||
if (!fingerprint_list)
|
||||
fingerprint_list = smartlist_create();
|
||||
fingerprint_list = authdir_config_new();
|
||||
add_fingerprint_to_dir(nickname, fp, fingerprint_list);
|
||||
return 0;
|
||||
}
|
||||
|
@ -138,7 +163,7 @@ dirserv_load_fingerprint_file(void)
|
|||
char fname[512];
|
||||
char *cf;
|
||||
char *nickname, *fingerprint;
|
||||
smartlist_t *fingerprint_list_new;
|
||||
authdir_config_t *fingerprint_list_new;
|
||||
int result;
|
||||
config_line_t *front=NULL, *list;
|
||||
or_options_t *options = get_options();
|
||||
|
@ -165,7 +190,7 @@ dirserv_load_fingerprint_file(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
fingerprint_list_new = smartlist_create();
|
||||
fingerprint_list_new = authdir_config_new();
|
||||
|
||||
for (list=front; list; list=list->next) {
|
||||
nickname = list->key; fingerprint = list->value;
|
||||
|
@ -177,7 +202,8 @@ dirserv_load_fingerprint_file(void)
|
|||
}
|
||||
if (!is_legal_nickname(nickname) &&
|
||||
strcasecmp(nickname, "!reject") &&
|
||||
strcasecmp(nickname, "!invalid")) {
|
||||
strcasecmp(nickname, "!invalid") &&
|
||||
strcasecmp(nickname, "!badexit")) {
|
||||
log_notice(LD_CONFIG,
|
||||
"Invalid nickname '%s' in fingerprint file. Skipping.",
|
||||
nickname);
|
||||
|
@ -200,6 +226,23 @@ dirserv_load_fingerprint_file(void)
|
|||
DEFAULT_CLIENT_NICKNAME);
|
||||
continue;
|
||||
}
|
||||
if (0==strcasecmp(nickname, DEFAULT_CLIENT_NICKNAME)) {
|
||||
/* If you approved an OR called "client", then clients who use
|
||||
* the default nickname could all be rejected. That's no good. */
|
||||
log_notice(LD_CONFIG,
|
||||
"Authorizing a nickname '%s' would break "
|
||||
"many clients; skipping.",
|
||||
DEFAULT_CLIENT_NICKNAME);
|
||||
continue;
|
||||
}
|
||||
if (0==strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) {
|
||||
/* If you approved an OR called "unnamed", then clients will be
|
||||
* confused.*/
|
||||
log_notice(LD_CONFIG,
|
||||
"Authorizing a nickname '%s' is not allowed; skipping.",
|
||||
UNNAMED_ROUTER_NICKNAME);
|
||||
continue;
|
||||
}
|
||||
if (add_fingerprint_to_dir(nickname, fingerprint, fingerprint_list_new)
|
||||
!= 0)
|
||||
log_notice(LD_CONFIG, "Duplicate nickname '%s'.", nickname);
|
||||
|
@ -219,17 +262,17 @@ dirserv_load_fingerprint_file(void)
|
|||
*
|
||||
* If the status is 'FP_REJECT' and <b>msg</b> is provided, set
|
||||
* *<b>msg</b> to an explanation of why. */
|
||||
static router_status_t
|
||||
static uint32_t
|
||||
dirserv_router_get_status(const routerinfo_t *router, const char **msg)
|
||||
{
|
||||
char fingerprint[FINGERPRINT_LEN+1];
|
||||
char d[DIGEST_LEN];
|
||||
|
||||
if (crypto_pk_get_fingerprint(router->identity_pkey, fingerprint, 0)) {
|
||||
if (crypto_pk_get_digest(router->identity_pkey, d)) {
|
||||
log_warn(LD_BUG,"Error computing fingerprint");
|
||||
return FP_REJECT;
|
||||
}
|
||||
|
||||
return dirserv_get_status_impl(fingerprint, router->nickname,
|
||||
return dirserv_get_status_impl(d, router->nickname,
|
||||
router->address,
|
||||
router->addr, router->or_port,
|
||||
router->platform, router->contact_info,
|
||||
|
@ -241,17 +284,15 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg)
|
|||
int
|
||||
dirserv_would_reject_router(routerstatus_t *rs)
|
||||
{
|
||||
char fp[FINGERPRINT_LEN+1];
|
||||
router_status_t res;
|
||||
base16_encode(fp, sizeof(fp), rs->identity_digest, DIGEST_LEN);
|
||||
uint32_t res;
|
||||
|
||||
res = dirserv_get_status_impl(fp, rs->nickname,
|
||||
res = dirserv_get_status_impl(rs->identity_digest, rs->nickname,
|
||||
"", /* address is only used in logs */
|
||||
rs->addr, rs->or_port,
|
||||
NULL, NULL,
|
||||
NULL, 0);
|
||||
|
||||
return (res == FP_REJECT);
|
||||
return (res & FP_REJECT) != 0;
|
||||
}
|
||||
|
||||
/** Helper: As dirserv_get_router_status, but takes the router fingerprint
|
||||
|
@ -261,42 +302,71 @@ dirserv_would_reject_router(routerstatus_t *rs)
|
|||
* If should_log is false, do not log messages. (There's not much point in
|
||||
* logging that we're rejecting servers we'll not download.)
|
||||
*/
|
||||
static router_status_t
|
||||
dirserv_get_status_impl(const char *fp, const char *nickname,
|
||||
static uint32_t
|
||||
dirserv_get_status_impl(const char *id_digest, const char *nickname,
|
||||
const char *address,
|
||||
uint32_t addr, uint16_t or_port,
|
||||
const char *platform, const char *contact,
|
||||
const char **msg, int should_log)
|
||||
{
|
||||
fingerprint_entry_t *nn_ent = NULL, *fp_ent = NULL;
|
||||
char fp[HEX_DIGEST_LEN+1];
|
||||
int reject_unlisted = get_options()->AuthDirRejectUnlisted;
|
||||
uint32_t result = 0;
|
||||
router_status_t *status_by_digest;
|
||||
char *fp_by_name;
|
||||
if (!fingerprint_list)
|
||||
fingerprint_list = smartlist_create();
|
||||
fingerprint_list = authdir_config_new();
|
||||
|
||||
base16_encode(fp, sizeof(fp), id_digest, DIGEST_LEN);
|
||||
|
||||
if (should_log)
|
||||
log_debug(LD_DIRSERV, "%d fingerprints known.",
|
||||
smartlist_len(fingerprint_list));
|
||||
SMARTLIST_FOREACH(fingerprint_list, fingerprint_entry_t *, ent,
|
||||
{
|
||||
if (!strcasecmp(fp,ent->fingerprint))
|
||||
fp_ent = ent;
|
||||
if (!strcasecmp(nickname,ent->nickname))
|
||||
nn_ent = ent;
|
||||
});
|
||||
digestmap_size(fingerprint_list->status_by_digest));
|
||||
|
||||
if (fp_ent) {
|
||||
if (!strcasecmp(fp_ent->nickname, "!reject")) {
|
||||
if ((fp_by_name =
|
||||
strmap_get_lc(fingerprint_list->fp_by_name, nickname))) {
|
||||
if (!strcasecmp(fp, fp_by_name)) {
|
||||
result |= FP_NAMED;
|
||||
if (should_log)
|
||||
log_debug(LD_DIRSERV,"Good fingerprint for '%s'",nickname);
|
||||
} else {
|
||||
if (should_log) {
|
||||
char *esc_contact = esc_for_log(contact);
|
||||
log_warn(LD_DIRSERV,
|
||||
"Mismatched fingerprint for '%s': expected '%s' got '%s'. "
|
||||
"ContactInfo '%s', platform '%s'.)",
|
||||
nickname, fp_by_name, fp,
|
||||
esc_contact,
|
||||
platform ? escaped(platform) : "");
|
||||
tor_free(esc_contact);
|
||||
}
|
||||
if (msg)
|
||||
*msg = "Fingerprint is marked rejected";
|
||||
return FP_REJECT;
|
||||
} else if (!strcasecmp(fp_ent->nickname, "!invalid")) {
|
||||
if (msg)
|
||||
*msg = "Fingerprint is marked invalid";
|
||||
return FP_INVALID;
|
||||
*msg = "Rejected: There is already a named server with this nickname "
|
||||
"and a different fingerprint.";
|
||||
return FP_REJECT; /* Wrong fingerprint. */
|
||||
}
|
||||
}
|
||||
status_by_digest = digestmap_get(fingerprint_list->status_by_digest,
|
||||
id_digest);
|
||||
result |= (status_by_digest->status & ~FP_NAMED);
|
||||
|
||||
if (!nn_ent) { /* No such server known with that nickname */
|
||||
if (result & FP_REJECT) {
|
||||
if (msg)
|
||||
*msg = "Fingerprint is marked rejected";
|
||||
return FP_REJECT;
|
||||
} else if (result & FP_INVALID) {
|
||||
if (msg)
|
||||
*msg = "Fingerprint is marked invalid";
|
||||
}
|
||||
|
||||
if (authdir_policy_badexit_address(addr, or_port)) {
|
||||
if (should_log)
|
||||
log_info(LD_DIRSERV, "Marking '%s' as bad exit because of address '%s'",
|
||||
nickname, address);
|
||||
result |= FP_BADEXIT;
|
||||
}
|
||||
|
||||
if (!(result & FP_NAMED)) {
|
||||
if (!authdir_policy_permits_address(addr, or_port)) {
|
||||
if (should_log)
|
||||
log_info(LD_DIRSERV, "Rejecting '%s' because of address '%s'",
|
||||
|
@ -309,38 +379,17 @@ dirserv_get_status_impl(const char *fp, const char *nickname,
|
|||
if (should_log)
|
||||
log_info(LD_DIRSERV, "Not marking '%s' valid because of address '%s'",
|
||||
nickname, address);
|
||||
return FP_INVALID;
|
||||
result |= FP_INVALID;
|
||||
}
|
||||
if (should_log)
|
||||
log_debug(LD_DIRSERV,"No fingerprint found for '%s'",nickname);
|
||||
if (reject_unlisted)
|
||||
return FP_REJECT;
|
||||
/* 0.1.0.2-rc was the first version that did enough self-testing that
|
||||
* we're willing to take its word about whether it's running . */
|
||||
if (!platform || tor_version_as_new_as(platform,"0.1.0.2-rc"))
|
||||
return reject_unlisted ? FP_REJECT : FP_VALID;
|
||||
else
|
||||
return FP_INVALID;
|
||||
}
|
||||
if (0==strcasecmp(nn_ent->fingerprint, fp)) {
|
||||
if (should_log)
|
||||
log_debug(LD_DIRSERV,"Good fingerprint for '%s'",nickname);
|
||||
if (!strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME))
|
||||
return FP_VALID;
|
||||
else
|
||||
return FP_NAMED; /* Right fingerprint. */
|
||||
} else {
|
||||
if (should_log) {
|
||||
char *esc_contact = esc_for_log(contact);
|
||||
log_warn(LD_DIRSERV,
|
||||
"Mismatched fingerprint for '%s': expected '%s' got '%s'. "
|
||||
"ContactInfo '%s', platform '%s'.)",
|
||||
nickname, nn_ent->fingerprint, fp,
|
||||
esc_contact,
|
||||
platform ? escaped(platform) : "");
|
||||
tor_free(esc_contact);
|
||||
}
|
||||
if (msg)
|
||||
*msg = "Rejected: There is already a named server with this nickname "
|
||||
"and a different fingerprint.";
|
||||
return FP_REJECT; /* Wrong fingerprint. */
|
||||
result |= FP_INVALID;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** If we are an authoritative dirserver, and the list of approved
|
||||
|
@ -349,35 +398,25 @@ dirserv_get_status_impl(const char *fp, const char *nickname,
|
|||
const char *
|
||||
dirserv_get_nickname_by_digest(const char *digest)
|
||||
{
|
||||
char hexdigest[HEX_DIGEST_LEN+1];
|
||||
router_status_t *status;
|
||||
if (!fingerprint_list)
|
||||
return NULL;
|
||||
tor_assert(digest);
|
||||
|
||||
base16_encode(hexdigest, HEX_DIGEST_LEN+1, digest, DIGEST_LEN);
|
||||
SMARTLIST_FOREACH(fingerprint_list, fingerprint_entry_t*, ent,
|
||||
{ if (!strcasecmp(hexdigest, ent->fingerprint))
|
||||
return ent->nickname; } );
|
||||
return NULL;
|
||||
status = digestmap_get(fingerprint_list->status_by_digest, digest);
|
||||
return status ? status->nickname : NULL;
|
||||
}
|
||||
|
||||
/** Clear the current fingerprint list. */
|
||||
void
|
||||
dirserv_free_fingerprint_list(void)
|
||||
{
|
||||
int i;
|
||||
fingerprint_entry_t *ent;
|
||||
if (!fingerprint_list)
|
||||
return;
|
||||
|
||||
for (i = 0; i < smartlist_len(fingerprint_list); ++i) {
|
||||
ent = smartlist_get(fingerprint_list, i);
|
||||
tor_free(ent->nickname);
|
||||
tor_free(ent->fingerprint);
|
||||
tor_free(ent);
|
||||
}
|
||||
smartlist_free(fingerprint_list);
|
||||
fingerprint_list = NULL;
|
||||
strmap_free(fingerprint_list->fp_by_name, _tor_free);
|
||||
digestmap_free(fingerprint_list->status_by_digest, _tor_free);
|
||||
tor_free(fingerprint_list);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -419,11 +458,11 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
|
|||
int complain)
|
||||
{
|
||||
/* Okay. Now check whether the fingerprint is recognized. */
|
||||
router_status_t status = dirserv_router_get_status(ri, msg);
|
||||
uint32_t status = dirserv_router_get_status(ri, msg);
|
||||
time_t now;
|
||||
int severity = complain ? LOG_NOTICE : LOG_INFO;
|
||||
tor_assert(msg);
|
||||
if (status == FP_REJECT)
|
||||
if (status & FP_REJECT)
|
||||
return -1; /* msg is already set. */
|
||||
|
||||
/* Is there too much clock skew? */
|
||||
|
@ -458,21 +497,9 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
|
|||
return -1;
|
||||
}
|
||||
/* Okay, looks like we're willing to accept this one. */
|
||||
switch (status) {
|
||||
case FP_NAMED:
|
||||
ri->is_named = ri->is_valid = 1;
|
||||
break;
|
||||
case FP_VALID:
|
||||
ri->is_named = 0;
|
||||
ri->is_valid = 1;
|
||||
break;
|
||||
case FP_INVALID:
|
||||
ri->is_named = ri->is_valid = 0;
|
||||
break;
|
||||
case FP_REJECT:
|
||||
default:
|
||||
tor_assert(0);
|
||||
}
|
||||
ri->is_named = (status & FP_NAMED) ? 1 : 0;
|
||||
ri->is_valid = (status & FP_INVALID) ? 0 : 1;
|
||||
ri->is_bad_exit = (status & FP_BADEXIT) ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -553,38 +580,31 @@ directory_remove_invalid(void)
|
|||
for (i = 0; i < smartlist_len(rl->routers); ++i) {
|
||||
const char *msg;
|
||||
routerinfo_t *ent = smartlist_get(rl->routers, i);
|
||||
router_status_t r = dirserv_router_get_status(ent, &msg);
|
||||
switch (r) {
|
||||
case FP_REJECT:
|
||||
log_info(LD_DIRSERV, "Router '%s' is now rejected: %s",
|
||||
ent->nickname, msg?msg:"");
|
||||
routerlist_remove(rl, ent, i--, 0);
|
||||
changed = 1;
|
||||
break;
|
||||
case FP_NAMED:
|
||||
if (!ent->is_valid || !ent->is_named) {
|
||||
log_info(LD_DIRSERV,
|
||||
"Router '%s' is now valid and named.", ent->nickname);
|
||||
ent->is_valid = ent->is_named = 1;
|
||||
changed = 1;
|
||||
}
|
||||
break;
|
||||
case FP_VALID:
|
||||
if (!ent->is_valid || ent->is_named) {
|
||||
log_info(LD_DIRSERV, "Router '%s' is now valid.", ent->nickname);
|
||||
ent->is_valid = 1;
|
||||
ent->is_named = 0;
|
||||
changed = 1;
|
||||
}
|
||||
break;
|
||||
case FP_INVALID:
|
||||
if (ent->is_valid || ent->is_named) {
|
||||
log_info(LD_DIRSERV,
|
||||
"Router '%s' is no longer valid.", ent->nickname);
|
||||
ent->is_valid = ent->is_named = 0;
|
||||
changed = 1;
|
||||
}
|
||||
break;
|
||||
uint32_t r = dirserv_router_get_status(ent, &msg);
|
||||
if (r & FP_REJECT) {
|
||||
log_info(LD_DIRSERV, "Router '%s' is now rejected: %s",
|
||||
ent->nickname, msg?msg:"");
|
||||
routerlist_remove(rl, ent, i--, 0);
|
||||
changed = 1;
|
||||
}
|
||||
if (!(r & FP_NAMED) != !ent->is_named) {
|
||||
log_info(LD_DIRSERV,
|
||||
"Router '%s' is now %snamed.", ent->nickname,
|
||||
(r&FP_NAMED)?"":"un");
|
||||
ent->is_named = (r&FP_NAMED)?1:0;
|
||||
changed = 1;
|
||||
}
|
||||
if (!(r & FP_INVALID) != !!ent->is_valid) {
|
||||
log_info(LD_DIRSERV, "Router '%s' is now %svalid.", ent->nickname,
|
||||
(r&FP_INVALID) ? "in" : "");
|
||||
ent->is_valid = (r&FP_INVALID)?0:1;
|
||||
changed = 1;
|
||||
}
|
||||
if (!(r & FP_BADEXIT) != !ent->is_bad_exit) {
|
||||
log_info(LD_DIRSERV, "Router '%s' is now a %s exit", ent->nickname,
|
||||
(r & FP_BADEXIT) ? "bad" : "good");
|
||||
ent->is_bad_exit = (r&FP_BADEXIT) ? 1: 0;
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
if (changed)
|
||||
|
@ -598,7 +618,6 @@ directory_remove_invalid(void)
|
|||
char *
|
||||
dirserver_getinfo_unregistered(const char *question)
|
||||
{
|
||||
router_status_t r;
|
||||
smartlist_t *answerlist;
|
||||
char buf[1024];
|
||||
char *answer;
|
||||
|
@ -607,9 +626,9 @@ dirserver_getinfo_unregistered(const char *question)
|
|||
|
||||
answerlist = smartlist_create();
|
||||
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ent, {
|
||||
r = dirserv_router_get_status(ent, NULL);
|
||||
uint32_t r = dirserv_router_get_status(ent, NULL);
|
||||
if (router_get_advertised_bandwidth(ent) >= (size_t)min_bw &&
|
||||
r != FP_NAMED) {
|
||||
!(r & FP_NAMED)) {
|
||||
/* then log this one */
|
||||
tor_snprintf(buf, sizeof(buf),
|
||||
"%s: BW %d on '%s'.",
|
||||
|
@ -1361,6 +1380,7 @@ generate_v2_networkstatus(void)
|
|||
time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH;
|
||||
int naming = options->NamingAuthoritativeDir;
|
||||
int versioning = options->VersioningAuthoritativeDir;
|
||||
int listbadexits = options->AuthDirListBadExits;
|
||||
const char *contact;
|
||||
|
||||
if (resolve_my_address(LOG_WARN, options, &addr, &hostname)<0) {
|
||||
|
@ -1401,7 +1421,7 @@ generate_v2_networkstatus(void)
|
|||
"fingerprint %s\n"
|
||||
"contact %s\n"
|
||||
"published %s\n"
|
||||
"dir-options%s%s\n"
|
||||
"dir-options%s%s%s\n"
|
||||
"%s%s" /* client versions %s */
|
||||
"%s%s%s" /* \nserver versions %s \n */
|
||||
"dir-signing-key\n%s\n",
|
||||
|
@ -1410,6 +1430,7 @@ generate_v2_networkstatus(void)
|
|||
contact,
|
||||
published,
|
||||
naming ? " Names" : "",
|
||||
listbadexits ? " BadExits" : "",
|
||||
versioning ? " Versions" : "",
|
||||
versioning ? "client-versions " : "",
|
||||
versioning ? client_versions : "",
|
||||
|
@ -1448,6 +1469,7 @@ generate_v2_networkstatus(void)
|
|||
int f_valid = ri->is_valid;
|
||||
int f_guard = f_fast && f_stable &&
|
||||
router_get_advertised_bandwidth(ri) > guard_bandwidth;
|
||||
int f_bad_exit = listbadexits && ri->is_bad_exit;
|
||||
/* 0.1.1.9-alpha is the first version to support fetch by descriptor
|
||||
* hash. */
|
||||
int f_v2_dir = ri->dir_port &&
|
||||
|
@ -1468,7 +1490,7 @@ generate_v2_networkstatus(void)
|
|||
|
||||
if (tor_snprintf(outp, endp-outp,
|
||||
"r %s %s %s %s %s %d %d\n"
|
||||
"s%s%s%s%s%s%s%s%s%s\n",
|
||||
"s%s%s%s%s%s%s%s%s%s%s\n",
|
||||
ri->nickname,
|
||||
identity64,
|
||||
digest64,
|
||||
|
@ -1477,6 +1499,7 @@ generate_v2_networkstatus(void)
|
|||
ri->or_port,
|
||||
ri->dir_port,
|
||||
f_authority?" Authority":"",
|
||||
f_bad_exit?" BadExit":"",
|
||||
f_exit?" Exit":"",
|
||||
f_fast?" Fast":"",
|
||||
f_guard?" Guard":"",
|
||||
|
@ -2015,14 +2038,8 @@ connection_dirserv_flushed_some(dir_connection_t *conn)
|
|||
void
|
||||
dirserv_free_all(void)
|
||||
{
|
||||
if (fingerprint_list) {
|
||||
SMARTLIST_FOREACH(fingerprint_list, fingerprint_entry_t*, fp,
|
||||
{ tor_free(fp->nickname);
|
||||
tor_free(fp->fingerprint);
|
||||
tor_free(fp); });
|
||||
smartlist_free(fingerprint_list);
|
||||
fingerprint_list = NULL;
|
||||
}
|
||||
dirserv_free_fingerprint_list();
|
||||
|
||||
cached_dir_decref(the_directory);
|
||||
clear_cached_dir(&the_runningrouters);
|
||||
cached_dir_decref(the_v2_networkstatus);
|
||||
|
|
|
@ -18,6 +18,7 @@ static addr_policy_t *socks_policy = NULL;
|
|||
static addr_policy_t *dir_policy = NULL;
|
||||
static addr_policy_t *authdir_reject_policy = NULL;
|
||||
static addr_policy_t *authdir_invalid_policy = NULL;
|
||||
static addr_policy_t *authdir_badexit_policy = NULL;
|
||||
|
||||
/** Parsed addr_policy_t describing which addresses we believe we can start
|
||||
* circuits at. */
|
||||
|
@ -203,6 +204,15 @@ authdir_policy_valid_address(uint32_t addr, uint16_t port)
|
|||
return addr_policy_permits_address(addr, port, authdir_invalid_policy);
|
||||
}
|
||||
|
||||
/** Return 1 if <b>addr</b>:<b>port</b> should be marked as a bad exit,
|
||||
* based on <b>authdir_badexit_policy</b>. Else return 0.
|
||||
*/
|
||||
int
|
||||
authdir_policy_badexit_address(uint32_t addr, uint16_t port)
|
||||
{
|
||||
return ! addr_policy_permits_address(addr, port, authdir_badexit_policy);
|
||||
}
|
||||
|
||||
#define REJECT(arg) \
|
||||
do { *msg = tor_strdup(arg); goto err; } while (0)
|
||||
int
|
||||
|
@ -271,6 +281,8 @@ policies_parse_from_options(or_options_t *options)
|
|||
&authdir_reject_policy, ADDR_POLICY_REJECT);
|
||||
load_policy_from_option(options->AuthDirInvalid,
|
||||
&authdir_invalid_policy, ADDR_POLICY_REJECT);
|
||||
load_policy_from_option(options->AuthDirBadExit,
|
||||
&authdir_badexit_policy, ADDR_POLICY_REJECT);
|
||||
parse_reachable_addresses();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue