📄 dirserv.c
字号:
platform ? escaped(platform) : "");
tor_free(esc_contact);
}
if (msg)
*msg = "Rejected: There is already a named server with this nickname "
"and a different fingerprint.";
}
status_by_digest = digestmap_get(fingerprint_list->status_by_digest,
id_digest);
if (status_by_digest)
result |= (status_by_digest->status & ~FP_NAMED);
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_baddir_address(addr, or_port)) {
if (should_log)
log_info(LD_DIRSERV,
"Marking '%s' as bad directory because of address '%s'",
nickname, address);
result |= FP_BADDIR;
}
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'",
nickname, address);
if (msg)
*msg = "Authdir is rejecting routers in this range.";
return FP_REJECT;
}
if (!authdir_policy_valid_address(addr, or_port)) {
if (should_log)
log_info(LD_DIRSERV, "Not marking '%s' valid because of address '%s'",
nickname, address);
result |= FP_INVALID;
}
if (reject_unlisted) {
if (msg)
*msg = "Authdir rejects unknown routers.";
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"))
result |= FP_INVALID;
}
return result;
}
/** If we are an authoritative dirserver, and the list of approved
* servers contains one whose identity key digest is <b>digest</b>,
* return that router's nickname. Otherwise return NULL. */
const char *
dirserv_get_nickname_by_digest(const char *digest)
{
router_status_t *status;
if (!fingerprint_list)
return NULL;
tor_assert(digest);
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)
{
if (!fingerprint_list)
return;
strmap_free(fingerprint_list->fp_by_name, _tor_free);
digestmap_free(fingerprint_list->status_by_digest, _tor_free);
tor_free(fingerprint_list);
}
/*
* Descriptor list
*/
/** Return -1 if <b>ri</b> has a private or otherwise bad address,
* unless we're configured to not care. Return 0 if all ok. */
static int
dirserv_router_has_valid_address(routerinfo_t *ri)
{
struct in_addr iaddr;
if (get_options()->DirAllowPrivateAddresses)
return 0; /* whatever it is, we're fine with it */
if (!tor_inet_aton(ri->address, &iaddr)) {
log_info(LD_DIRSERV,"Router '%s' published non-IP address '%s'. Refusing.",
ri->nickname, ri->address);
return -1;
}
if (is_internal_IP(ntohl(iaddr.s_addr), 0)) {
log_info(LD_DIRSERV,
"Router '%s' published internal IP address '%s'. Refusing.",
ri->nickname, ri->address);
return -1; /* it's a private IP, we should reject it */
}
return 0;
}
/** Check whether we, as a directory server, want to accept <b>ri</b>. If so,
* set its is_valid,named,running fields and return 0. Otherwise, return -1.
*
* If the router is rejected, set *<b>msg</b> to an explanation of why.
*
* If <b>complain</b> then explain at log-level 'notice' why we refused
* a descriptor; else explain at log-level 'info'.
*/
int
authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
int complain)
{
/* Okay. Now check whether the fingerprint is recognized. */
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)
return -1; /* msg is already set. */
/* Is there too much clock skew? */
now = time(NULL);
if (ri->cache_info.published_on > now+ROUTER_ALLOW_SKEW) {
log_fn(severity, LD_DIRSERV, "Publication time for nickname '%s' is too "
"far (%d minutes) in the future; possible clock skew. Not adding "
"(%s)",
ri->nickname, (int)((ri->cache_info.published_on-now)/60),
esc_router_info(ri));
*msg = "Rejected: Your clock is set too far in the future, or your "
"timezone is not correct.";
return -1;
}
if (ri->cache_info.published_on < now-ROUTER_MAX_AGE_TO_PUBLISH) {
log_fn(severity, LD_DIRSERV,
"Publication time for router with nickname '%s' is too far "
"(%d minutes) in the past. Not adding (%s)",
ri->nickname, (int)((now-ri->cache_info.published_on)/60),
esc_router_info(ri));
*msg = "Rejected: Server is expired, or your clock is too far in the past,"
" or your timezone is not correct.";
return -1;
}
if (dirserv_router_has_valid_address(ri) < 0) {
log_fn(severity, LD_DIRSERV,
"Router with nickname '%s' has invalid address '%s'. "
"Not adding (%s).",
ri->nickname, ri->address,
esc_router_info(ri));
*msg = "Rejected: Address is not an IP, or IP is a private address.";
return -1;
}
/* Okay, looks like we're willing to accept this one. */
ri->is_named = (status & FP_NAMED) ? 1 : 0;
ri->is_valid = (status & FP_INVALID) ? 0 : 1;
ri->is_bad_directory = (status & FP_BADDIR) ? 1 : 0;
ri->is_bad_exit = (status & FP_BADEXIT) ? 1 : 0;
return 0;
}
/** As for dirserv_add_descriptor, but accepts multiple documents, and
* returns the most severe error that occurred for any one of them. */
int
dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
const char *source,
const char **msg)
{
int r=100; /* higher than any actual return value. */
int r_tmp;
const char *msg_out;
smartlist_t *list;
const char *s;
int n_parsed = 0;
time_t now = time(NULL);
char annotation_buf[ROUTER_ANNOTATION_BUF_LEN];
char time_buf[ISO_TIME_LEN+1];
int general = purpose == ROUTER_PURPOSE_GENERAL;
tor_assert(msg);
format_iso_time(time_buf, now);
if (tor_snprintf(annotation_buf, sizeof(annotation_buf),
"@uploaded-at %s\n"
"@source %s\n"
"%s%s%s", time_buf, escaped(source),
!general ? "@purpose " : "",
!general ? router_purpose_to_string(purpose) : "",
!general ? "\n" : "")<0) {
*msg = "Couldn't format annotations";
return -1;
}
s = desc;
list = smartlist_create();
if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 0, 0,
annotation_buf)) {
SMARTLIST_FOREACH(list, routerinfo_t *, ri, {
msg_out = NULL;
tor_assert(ri->purpose == purpose);
r_tmp = dirserv_add_descriptor(ri, &msg_out);
if (r_tmp < r) {
r = r_tmp;
*msg = msg_out;
}
});
}
n_parsed += smartlist_len(list);
smartlist_clear(list);
s = desc;
if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 1, 0,
NULL)) {
SMARTLIST_FOREACH(list, extrainfo_t *, ei, {
msg_out = NULL;
r_tmp = dirserv_add_extrainfo(ei, &msg_out);
if (r_tmp < r) {
r = r_tmp;
*msg = msg_out;
}
});
}
n_parsed += smartlist_len(list);
smartlist_free(list);
if (! *msg) {
if (!n_parsed) {
*msg = "No descriptors found in your POST.";
if (r > -1)
r = -1;
} else {
*msg = "(no message)";
}
}
return r <= 2 ? r : 2;
}
/** Examine the parsed server descriptor in <b>ri</b> and maybe insert it into
* the list of server descriptors. Set *<b>msg</b> to a message that should be
* passed back to the origin of this descriptor.
*
* Return 2 if descriptor is well-formed and accepted;
* 1 if well-formed and accepted but origin should hear *msg;
* 0 if well-formed but redundant with one we already have;
* -1 if it is rejected and origin should hear *msg;
*
* This function is only called when fresh descriptors are posted, not when
* we re-load the cache.
*/
int
dirserv_add_descriptor(routerinfo_t *ri, const char **msg)
{
int r;
routerinfo_t *ri_old;
char *desc = NULL;
size_t desclen = 0;
/* If it's too big, refuse it now. Otherwise we'll cache it all over the
* network and it'll clog everything up. */
if (ri->cache_info.signed_descriptor_len > MAX_DESCRIPTOR_UPLOAD_SIZE) {
log_notice(LD_DIR, "Somebody attempted to publish a router descriptor "
"with size %d. Either this is an attack, or the "
"MAX_DESCRIPTOR_UPLOAD_SIZE (%d) constant is too low.",
(int)ri->cache_info.signed_descriptor_len,
MAX_DESCRIPTOR_UPLOAD_SIZE);
*msg = "Router descriptor was too large";
control_event_or_authdir_new_descriptor("REJECTED",
ri->cache_info.signed_descriptor_body,
ri->cache_info.signed_descriptor_len, *msg);
routerinfo_free(ri);
return -1;
}
/* Check whether this descriptor is semantically identical to the last one
* from this server. (We do this here and not in router_add_to_routerlist
* because we want to be able to accept the newest router descriptor that
* another authority has, so we all converge on the same one.) */
ri_old = router_get_by_digest(ri->cache_info.identity_digest);
if (ri_old && ri_old->cache_info.published_on < ri->cache_info.published_on
&& router_differences_are_cosmetic(ri_old, ri)
&& !router_is_me(ri)) {
log_info(LD_DIRSERV,
"Not replacing descriptor from '%s'; differences are cosmetic.",
ri->nickname);
*msg = "Not replacing router descriptor; no information has changed since "
"the last one with this identity.";
control_event_or_authdir_new_descriptor("DROPPED",
ri->cache_info.signed_descriptor_body,
ri->cache_info.signed_descriptor_len, *msg);
routerinfo_free(ri);
return 0;
}
if (control_event_is_interesting(EVENT_AUTHDIR_NEWDESCS)) {
/* Make a copy of desc, since router_add_to_routerlist might free
* ri and its associated signed_descriptor_t. */
desclen = ri->cache_info.signed_descriptor_len;
desc = tor_strndup(ri->cache_info.signed_descriptor_body, desclen);
}
if ((r = router_add_to_routerlist(ri, msg, 0, 0))<0) {
if (r < -1 && desc) /* unless the routerinfo was fine, just out-of-date */
control_event_or_authdir_new_descriptor("REJECTED", desc, desclen, *msg);
tor_free(desc);
return r == -1 ? 0 : -1;
} else {
smartlist_t *changed;
control_event_or_authdir_new_descriptor("ACCEPTED", desc, desclen, *msg);
changed = smartlist_create();
smartlist_add(changed, ri);
control_event_descriptors_changed(changed);
smartlist_free(changed);
if (!*msg) {
*msg = ri->is_valid ? "Descriptor for valid server accepted" :
"Descriptor for invalid server accepted";
}
tor_free(desc);
return r == 0 ? 2 : 1;
}
}
/** As dirserv_add_descriptor, but for an extrainfo_t <b>ei</b>. */
static int
dirserv_add_extrainfo(extrainfo_t *ei, const char **msg)
{
routerinfo_t *ri;
int r;
tor_assert(msg);
*msg = NULL;
ri = router_get_by_digest(ei->cache_info.identity_digest);
if (!ri) {
*msg = "No corresponding router descriptor for extra-info descriptor";
extrainfo_free(ei);
return -1;
}
/* If it's too big, refuse it now. Otherwise we'll cache it all over the
* network and it'll clog everything up. */
if (ei->cache_info.signed_descriptor_len > MAX_EXTRAINFO_UPLOAD_SIZE) {
log_notice(LD_DIR, "Somebody attempted to publish an extrainfo "
"with size %d. Either this is an attack, or the "
"MAX_EXTRAINFO_UPLOAD_SIZE (%d) constant is too low.",
(int)ei->cache_info.signed_descriptor_len,
MAX_EXTRAINFO_UPLOAD_SIZE);
*msg = "Extrainfo document was too large";
extrainfo_free(ei);
return -1;
}
if ((r = routerinfo_incompatible_with_extrainfo(ri, ei, NULL, msg))) {
extrainfo_free(ei);
return r < 0 ? 0 : -1;
}
router_add_extrainfo_to_routerlist(ei, msg, 0, 0);
return 2;
}
/** Remove all descriptors whose nicknames or fingerprints no longer
* are allowed by our fingerprint list. (Descriptors that used to be
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -