123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839 |
- /* Copyright (c) 2001-2004, Roger Dingledine.
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2018, The Tor Project, Inc. */
- /* See LICENSE for licensing information */
- /**
- * \file process_descs.c
- * \brief Make decisions about uploaded descriptors
- *
- * Authorities use the code in this module to decide what to do with just-
- * uploaded descriptors, and to manage the fingerprint file that helps
- * them make those decisions.
- **/
- #include "core/or/or.h"
- #include "feature/dirauth/process_descs.h"
- #include "app/config/config.h"
- #include "core/or/policies.h"
- #include "core/or/versions.h"
- #include "feature/dirauth/keypin.h"
- #include "feature/dirauth/reachability.h"
- #include "feature/dirclient/dlstatus.h"
- #include "feature/dircommon/directory.h"
- #include "feature/nodelist/describe.h"
- #include "feature/nodelist/networkstatus.h"
- #include "feature/nodelist/nodelist.h"
- #include "feature/nodelist/routerinfo.h"
- #include "feature/nodelist/routerlist.h"
- #include "feature/dirparse/routerparse.h"
- #include "feature/nodelist/torcert.h"
- #include "feature/relay/router.h"
- #include "core/or/tor_version_st.h"
- #include "feature/nodelist/extrainfo_st.h"
- #include "feature/nodelist/node_st.h"
- #include "feature/nodelist/routerinfo_st.h"
- #include "feature/nodelist/routerstatus_st.h"
- #include "lib/encoding/confline.h"
- /** How far in the future do we allow a router to get? (seconds) */
- #define ROUTER_ALLOW_SKEW (60*60*12)
- static void directory_remove_invalid(void);
- struct authdir_config_t;
- static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei,
- const char **msg);
- static uint32_t
- dirserv_get_status_impl(const char *fp, const char *nickname,
- uint32_t addr, uint16_t or_port,
- const char *platform, const char **msg,
- int severity);
- /* 1 Historically used to indicate Named */
- #define FP_INVALID 2 /**< Believed invalid. */
- #define FP_REJECT 4 /**< We will not publish this router. */
- /* 8 Historically used to avoid using this as a dir. */
- #define FP_BADEXIT 16 /**< We'll tell clients not to use this as an exit. */
- /* 32 Historically used to indicade Unnamed */
- /** Target of status_by_digest map. */
- typedef uint32_t router_status_t;
- static void add_fingerprint_to_dir(const char *fp,
- struct authdir_config_t *list,
- router_status_t add_status);
- /** List of nickname-\>identity fingerprint mappings for all the routers
- * that we name. Used to prevent router impersonation. */
- 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 router_status_t. */
- } authdir_config_t;
- /** Should be static; exposed for testing. */
- static authdir_config_t *fingerprint_list = NULL;
- /** Allocate and return a new, empty, authdir_config_t. */
- 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> to the smartlist of fingerprint_entry_t's
- * <b>list</b>, or-ing the currently set status flags with
- * <b>add_status</b>.
- */
- /* static */ void
- add_fingerprint_to_dir(const char *fp, authdir_config_t *list,
- router_status_t add_status)
- {
- char *fingerprint;
- char d[DIGEST_LEN];
- router_status_t *status;
- tor_assert(fp);
- tor_assert(list);
- fingerprint = tor_strdup(fp);
- tor_strstrip(fingerprint, " ");
- if (base16_decode(d, DIGEST_LEN,
- fingerprint, strlen(fingerprint)) != DIGEST_LEN) {
- log_warn(LD_DIRSERV, "Couldn't decode fingerprint \"%s\"",
- escaped(fp));
- tor_free(fingerprint);
- return;
- }
- 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);
- }
- tor_free(fingerprint);
- *status |= add_status;
- return;
- }
- /** Add the fingerprint for this OR to the global list of recognized
- * identity key fingerprints. */
- int
- dirserv_add_own_fingerprint(crypto_pk_t *pk)
- {
- char fp[FINGERPRINT_LEN+1];
- if (crypto_pk_get_fingerprint(pk, fp, 0)<0) {
- log_err(LD_BUG, "Error computing fingerprint");
- return -1;
- }
- if (!fingerprint_list)
- fingerprint_list = authdir_config_new();
- add_fingerprint_to_dir(fp, fingerprint_list, 0);
- return 0;
- }
- /** Load the nickname-\>fingerprint mappings stored in the approved-routers
- * file. The file format is line-based, with each non-blank holding one
- * nickname, some space, and a fingerprint for that nickname. On success,
- * replace the current fingerprint list with the new list and return 0. On
- * failure, leave the current fingerprint list untouched, and return -1. */
- int
- dirserv_load_fingerprint_file(void)
- {
- char *fname;
- char *cf;
- char *nickname, *fingerprint;
- authdir_config_t *fingerprint_list_new;
- int result;
- config_line_t *front=NULL, *list;
- fname = get_datadir_fname("approved-routers");
- log_info(LD_GENERAL,
- "Reloading approved fingerprints from \"%s\"...", fname);
- cf = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL);
- if (!cf) {
- log_warn(LD_FS, "Cannot open fingerprint file '%s'. That's ok.", fname);
- tor_free(fname);
- return 0;
- }
- tor_free(fname);
- result = config_get_lines(cf, &front, 0);
- tor_free(cf);
- if (result < 0) {
- log_warn(LD_CONFIG, "Error reading from fingerprint file");
- return -1;
- }
- fingerprint_list_new = authdir_config_new();
- for (list=front; list; list=list->next) {
- char digest_tmp[DIGEST_LEN];
- router_status_t add_status = 0;
- nickname = list->key; fingerprint = list->value;
- tor_strstrip(fingerprint, " "); /* remove spaces */
- if (strlen(fingerprint) != HEX_DIGEST_LEN ||
- base16_decode(digest_tmp, sizeof(digest_tmp),
- fingerprint, HEX_DIGEST_LEN) != sizeof(digest_tmp)) {
- log_notice(LD_CONFIG,
- "Invalid fingerprint (nickname '%s', "
- "fingerprint %s). Skipping.",
- nickname, fingerprint);
- continue;
- }
- if (!strcasecmp(nickname, "!reject")) {
- add_status = FP_REJECT;
- } else if (!strcasecmp(nickname, "!badexit")) {
- add_status = FP_BADEXIT;
- } else if (!strcasecmp(nickname, "!invalid")) {
- add_status = FP_INVALID;
- }
- add_fingerprint_to_dir(fingerprint, fingerprint_list_new, add_status);
- }
- config_free_lines(front);
- dirserv_free_fingerprint_list();
- fingerprint_list = fingerprint_list_new;
- /* Delete any routers whose fingerprints we no longer recognize */
- directory_remove_invalid();
- return 0;
- }
- /* If this is set, then we don't allow routers that have advertised an Ed25519
- * identity to stop doing so. This is going to be essential for good identity
- * security: otherwise anybody who can attack RSA-1024 but not Ed25519 could
- * just sign fake descriptors missing the Ed25519 key. But we won't actually
- * be able to prevent that kind of thing until we're confident that there isn't
- * actually a legit reason to downgrade to 0.2.5. Now we are not recommending
- * 0.2.5 anymore so there is no reason to keep the #undef.
- */
- #define DISABLE_DISABLING_ED25519
- /** Check whether <b>router</b> has a nickname/identity key combination that
- * we recognize from the fingerprint list, or an IP we automatically act on
- * according to our configuration. Return the appropriate router status.
- *
- * If the status is 'FP_REJECT' and <b>msg</b> is provided, set
- * *<b>msg</b> to an explanation of why. */
- uint32_t
- dirserv_router_get_status(const routerinfo_t *router, const char **msg,
- int severity)
- {
- char d[DIGEST_LEN];
- const int key_pinning = get_options()->AuthDirPinKeys;
- if (crypto_pk_get_digest(router->identity_pkey, d)) {
- log_warn(LD_BUG,"Error computing fingerprint");
- if (msg)
- *msg = "Bug: Error computing fingerprint";
- return FP_REJECT;
- }
- /* Check for the more usual versions to reject a router first. */
- const uint32_t r = dirserv_get_status_impl(d, router->nickname,
- router->addr, router->or_port,
- router->platform, msg, severity);
- if (r)
- return r;
- /* dirserv_get_status_impl already rejects versions older than 0.2.4.18-rc,
- * and onion_curve25519_pkey was introduced in 0.2.4.8-alpha.
- * But just in case a relay doesn't provide or lies about its version, or
- * doesn't include an ntor key in its descriptor, check that it exists,
- * and is non-zero (clients check that it's non-zero before using it). */
- if (!routerinfo_has_curve25519_onion_key(router)) {
- log_fn(severity, LD_DIR,
- "Descriptor from router %s is missing an ntor curve25519 onion "
- "key.", router_describe(router));
- if (msg)
- *msg = "Missing ntor curve25519 onion key. Please upgrade!";
- return FP_REJECT;
- }
- if (router->cache_info.signing_key_cert) {
- /* This has an ed25519 identity key. */
- if (KEYPIN_MISMATCH ==
- keypin_check((const uint8_t*)router->cache_info.identity_digest,
- router->cache_info.signing_key_cert->signing_key.pubkey)) {
- log_fn(severity, LD_DIR,
- "Descriptor from router %s has an Ed25519 key, "
- "but the <rsa,ed25519> keys don't match what they were before.",
- router_describe(router));
- if (key_pinning) {
- if (msg) {
- *msg = "Ed25519 identity key or RSA identity key has changed.";
- }
- return FP_REJECT;
- }
- }
- } else {
- /* No ed25519 key */
- if (KEYPIN_MISMATCH == keypin_check_lone_rsa(
- (const uint8_t*)router->cache_info.identity_digest)) {
- log_fn(severity, LD_DIR,
- "Descriptor from router %s has no Ed25519 key, "
- "when we previously knew an Ed25519 for it. Ignoring for now, "
- "since Ed25519 keys are fairly new.",
- router_describe(router));
- #ifdef DISABLE_DISABLING_ED25519
- if (key_pinning) {
- if (msg) {
- *msg = "Ed25519 identity key has disappeared.";
- }
- return FP_REJECT;
- }
- #endif /* defined(DISABLE_DISABLING_ED25519) */
- }
- }
- return 0;
- }
- /** Return true if there is no point in downloading the router described by
- * <b>rs</b> because this directory would reject it. */
- int
- dirserv_would_reject_router(const routerstatus_t *rs)
- {
- uint32_t res;
- res = dirserv_get_status_impl(rs->identity_digest, rs->nickname,
- rs->addr, rs->or_port,
- NULL, NULL, LOG_DEBUG);
- return (res & FP_REJECT) != 0;
- }
- /** Helper: As dirserv_router_get_status, but takes the router fingerprint
- * (hex, no spaces), nickname, address (used for logging only), IP address, OR
- * port and platform (logging only) as arguments.
- *
- * Log messages at 'severity'. (There's not much point in
- * logging that we're rejecting servers we'll not download.)
- */
- static uint32_t
- dirserv_get_status_impl(const char *id_digest, const char *nickname,
- uint32_t addr, uint16_t or_port,
- const char *platform, const char **msg, int severity)
- {
- uint32_t result = 0;
- router_status_t *status_by_digest;
- if (!fingerprint_list)
- fingerprint_list = authdir_config_new();
- log_debug(LD_DIRSERV, "%d fingerprints, %d digests known.",
- strmap_size(fingerprint_list->fp_by_name),
- digestmap_size(fingerprint_list->status_by_digest));
- if (platform) {
- tor_version_t ver_tmp;
- if (tor_version_parse_platform(platform, &ver_tmp, 1) < 0) {
- if (msg) {
- *msg = "Malformed platform string.";
- }
- return FP_REJECT;
- }
- }
- /* Versions before Tor 0.2.4.18-rc are too old to support, and are
- * missing some important security fixes too. Disable them. */
- if (platform && !tor_version_as_new_as(platform,"0.2.4.18-rc")) {
- if (msg)
- *msg = "Tor version is insecure or unsupported. Please upgrade!";
- return FP_REJECT;
- }
- /* Tor 0.2.9.x where x<5 suffers from bug #20499, where relays don't
- * keep their consensus up to date so they make bad guards.
- * The simple fix is to just drop them from the network. */
- if (platform &&
- tor_version_as_new_as(platform,"0.2.9.0-alpha") &&
- !tor_version_as_new_as(platform,"0.2.9.5-alpha")) {
- if (msg)
- *msg = "Tor version contains bug 20499. Please upgrade!";
- return FP_REJECT;
- }
- status_by_digest = digestmap_get(fingerprint_list->status_by_digest,
- id_digest);
- if (status_by_digest)
- result |= *status_by_digest;
- if (result & FP_REJECT) {
- if (msg)
- *msg = "Fingerprint is marked rejected -- if you think this is a "
- "mistake please set a valid email address in ContactInfo and "
- "send an email to bad-relays@lists.torproject.org mentioning "
- "your fingerprint(s)?";
- return FP_REJECT;
- } else if (result & FP_INVALID) {
- if (msg)
- *msg = "Fingerprint is marked invalid";
- }
- if (authdir_policy_badexit_address(addr, or_port)) {
- log_fn(severity, LD_DIRSERV,
- "Marking '%s' as bad exit because of address '%s'",
- nickname, fmt_addr32(addr));
- result |= FP_BADEXIT;
- }
- if (!authdir_policy_permits_address(addr, or_port)) {
- log_fn(severity, LD_DIRSERV, "Rejecting '%s' because of address '%s'",
- nickname, fmt_addr32(addr));
- if (msg)
- *msg = "Suspicious relay address range -- if you think this is a "
- "mistake please set a valid email address in ContactInfo and "
- "send an email to bad-relays@lists.torproject.org mentioning "
- "your address(es) and fingerprint(s)?";
- return FP_REJECT;
- }
- if (!authdir_policy_valid_address(addr, or_port)) {
- log_fn(severity, LD_DIRSERV,
- "Not marking '%s' valid because of address '%s'",
- nickname, fmt_addr32(addr));
- result |= FP_INVALID;
- }
- return result;
- }
- /** 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)
- {
- tor_addr_t addr;
- if (get_options()->DirAllowPrivateAddresses)
- return 0; /* whatever it is, we're fine with it */
- tor_addr_from_ipv4h(&addr, ri->addr);
- if (tor_addr_is_internal(&addr, 0)) {
- log_info(LD_DIRSERV,
- "Router %s published internal IP address. Refusing.",
- router_describe(ri));
- 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,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, int *valid_out)
- {
- /* Okay. Now check whether the fingerprint is recognized. */
- time_t now;
- int severity = (complain && ri->contact_info) ? LOG_NOTICE : LOG_INFO;
- uint32_t status = dirserv_router_get_status(ri, msg, severity);
- 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 %s is too "
- "far (%d minutes) in the future; possible clock skew. Not adding "
- "(%s)",
- router_describe(ri),
- (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 %s is too far "
- "(%d minutes) in the past. Not adding (%s)",
- router_describe(ri),
- (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 %s has invalid address. Not adding (%s).",
- router_describe(ri),
- esc_router_info(ri));
- *msg = "Rejected: Address is a private address.";
- return -1;
- }
- *valid_out = ! (status & FP_INVALID);
- return 0;
- }
- /** Update the relevant flags of <b>node</b> based on our opinion as a
- * directory authority in <b>authstatus</b>, as returned by
- * dirserv_router_get_status or equivalent. */
- void
- dirserv_set_node_flags_from_authoritative_status(node_t *node,
- uint32_t authstatus)
- {
- node->is_valid = (authstatus & FP_INVALID) ? 0 : 1;
- node->is_bad_exit = (authstatus & FP_BADEXIT) ? 1 : 0;
- }
- /** True iff <b>a</b> is more severe than <b>b</b>. */
- static int
- WRA_MORE_SEVERE(was_router_added_t a, was_router_added_t b)
- {
- return a < b;
- }
- /** As for dirserv_add_descriptor(), but accepts multiple documents, and
- * returns the most severe error that occurred for any one of them. */
- was_router_added_t
- dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
- const char *source,
- const char **msg)
- {
- was_router_added_t r, 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);
- r=ROUTER_ADDED_SUCCESSFULLY; /*Least severe return value. */
- 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";
- /* XXX Not cool: we return -1 below, but (was_router_added_t)-1 is
- * ROUTER_BAD_EI, which isn't what's gone wrong here. :( */
- return -1;
- }
- s = desc;
- list = smartlist_new();
- if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 0, 0,
- annotation_buf, NULL)) {
- SMARTLIST_FOREACH(list, routerinfo_t *, ri, {
- msg_out = NULL;
- tor_assert(ri->purpose == purpose);
- r_tmp = dirserv_add_descriptor(ri, &msg_out, source);
- if (WRA_MORE_SEVERE(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, NULL)) {
- SMARTLIST_FOREACH(list, extrainfo_t *, ei, {
- msg_out = NULL;
- r_tmp = dirserv_add_extrainfo(ei, &msg_out);
- if (WRA_MORE_SEVERE(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 (WRA_WAS_ADDED(r))
- r = ROUTER_IS_ALREADY_KNOWN;
- } else {
- *msg = "(no message)";
- }
- }
- return r;
- }
- /** 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, or NULL if there is no such
- * message. Use <b>source</b> to produce better log messages.
- *
- * If <b>ri</b> is not added to the list of server descriptors, free it.
- * That means the caller must not access <b>ri</b> after this function
- * returns, since it might have been freed.
- *
- * Return the status of the operation.
- *
- * This function is only called when fresh descriptors are posted, not when
- * we re-load the cache.
- */
- was_router_added_t
- dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source)
- {
- was_router_added_t r;
- routerinfo_t *ri_old;
- char *desc, *nickname;
- const size_t desclen = ri->cache_info.signed_descriptor_len +
- ri->cache_info.annotations_len;
- const int key_pinning = get_options()->AuthDirPinKeys;
- *msg = NULL;
- /* 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 '%s'"
- " (source: %s) with size %d. Either this is an attack, or the "
- "MAX_DESCRIPTOR_UPLOAD_SIZE (%d) constant is too low.",
- ri->nickname, source, (int)ri->cache_info.signed_descriptor_len,
- MAX_DESCRIPTOR_UPLOAD_SIZE);
- *msg = "Router descriptor was too large.";
- r = ROUTER_AUTHDIR_REJECTS;
- goto fail;
- }
- /* 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_mutable_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 (source: %s); "
- "differences are cosmetic.",
- router_describe(ri), source);
- *msg = "Not replacing router descriptor; no information has changed since "
- "the last one with this identity.";
- r = ROUTER_IS_ALREADY_KNOWN;
- goto fail;
- }
- /* Do keypinning again ... this time, to add the pin if appropriate */
- int keypin_status;
- if (ri->cache_info.signing_key_cert) {
- ed25519_public_key_t *pkey = &ri->cache_info.signing_key_cert->signing_key;
- /* First let's validate this pubkey before pinning it */
- if (ed25519_validate_pubkey(pkey) < 0) {
- log_warn(LD_DIRSERV, "Received bad key from %s (source %s)",
- router_describe(ri), source);
- routerinfo_free(ri);
- return ROUTER_AUTHDIR_REJECTS;
- }
- /* Now pin it! */
- keypin_status = keypin_check_and_add(
- (const uint8_t*)ri->cache_info.identity_digest,
- pkey->pubkey, ! key_pinning);
- } else {
- keypin_status = keypin_check_lone_rsa(
- (const uint8_t*)ri->cache_info.identity_digest);
- #ifndef DISABLE_DISABLING_ED25519
- if (keypin_status == KEYPIN_MISMATCH)
- keypin_status = KEYPIN_NOT_FOUND;
- #endif
- }
- if (keypin_status == KEYPIN_MISMATCH && key_pinning) {
- log_info(LD_DIRSERV, "Dropping descriptor from %s (source: %s) because "
- "its key did not match an older RSA/Ed25519 keypair",
- router_describe(ri), source);
- *msg = "Looks like your keypair has changed? This authority previously "
- "recorded a different RSA identity for this Ed25519 identity (or vice "
- "versa.) Did you replace or copy some of your key files, but not "
- "the others? You should either restore the expected keypair, or "
- "delete your keys and restart Tor to start your relay with a new "
- "identity.";
- r = ROUTER_AUTHDIR_REJECTS;
- goto fail;
- }
- /* Make a copy of desc, since router_add_to_routerlist might free
- * ri and its associated signed_descriptor_t. */
- desc = tor_strndup(ri->cache_info.signed_descriptor_body, desclen);
- nickname = tor_strdup(ri->nickname);
- /* Tell if we're about to need to launch a test if we add this. */
- ri->needs_retest_if_added =
- dirserv_should_launch_reachability_test(ri, ri_old);
- r = router_add_to_routerlist(ri, msg, 0, 0);
- if (!WRA_WAS_ADDED(r)) {
- /* unless the routerinfo was fine, just out-of-date */
- log_info(LD_DIRSERV,
- "Did not add descriptor from '%s' (source: %s): %s.",
- nickname, source, *msg ? *msg : "(no message)");
- } else {
- smartlist_t *changed;
- changed = smartlist_new();
- smartlist_add(changed, ri);
- routerlist_descriptors_added(changed, 0);
- smartlist_free(changed);
- if (!*msg) {
- *msg = "Descriptor accepted";
- }
- log_info(LD_DIRSERV,
- "Added descriptor from '%s' (source: %s): %s.",
- nickname, source, *msg);
- }
- tor_free(desc);
- tor_free(nickname);
- return r;
- fail:
- {
- const char *desc_digest = ri->cache_info.signed_descriptor_digest;
- download_status_t *dls =
- router_get_dl_status_by_descriptor_digest(desc_digest);
- if (dls) {
- log_info(LD_GENERAL, "Marking router with descriptor %s as rejected, "
- "and therefore undownloadable",
- hex_str(desc_digest, DIGEST_LEN));
- download_status_mark_impossible(dls);
- }
- routerinfo_free(ri);
- }
- return r;
- }
- /** As dirserv_add_descriptor, but for an extrainfo_t <b>ei</b>. */
- static was_router_added_t
- dirserv_add_extrainfo(extrainfo_t *ei, const char **msg)
- {
- routerinfo_t *ri;
- int r;
- was_router_added_t rv;
- tor_assert(msg);
- *msg = NULL;
- /* Needs to be mutable so routerinfo_incompatible_with_extrainfo
- * can mess with some of the flags in ri->cache_info. */
- ri = router_get_mutable_by_digest(ei->cache_info.identity_digest);
- if (!ri) {
- *msg = "No corresponding router descriptor for extra-info descriptor";
- rv = ROUTER_BAD_EI;
- goto fail;
- }
- /* 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";
- rv = ROUTER_BAD_EI;
- goto fail;
- }
- if ((r = routerinfo_incompatible_with_extrainfo(ri->identity_pkey, ei,
- &ri->cache_info, msg))) {
- if (r<0) {
- extrainfo_free(ei);
- return ROUTER_IS_ALREADY_KNOWN;
- }
- rv = ROUTER_BAD_EI;
- goto fail;
- }
- router_add_extrainfo_to_routerlist(ei, msg, 0, 0);
- return ROUTER_ADDED_SUCCESSFULLY;
- fail:
- {
- const char *d = ei->cache_info.signed_descriptor_digest;
- signed_descriptor_t *sd = router_get_by_extrainfo_digest((char*)d);
- if (sd) {
- log_info(LD_GENERAL, "Marking extrainfo with descriptor %s as "
- "rejected, and therefore undownloadable",
- hex_str((char*)d,DIGEST_LEN));
- download_status_mark_impossible(&sd->ei_dl_status);
- }
- extrainfo_free(ei);
- }
- return rv;
- }
- /** Remove all descriptors whose nicknames or fingerprints no longer
- * are allowed by our fingerprint list. (Descriptors that used to be
- * good can become bad when we reload the fingerprint list.)
- */
- static void
- directory_remove_invalid(void)
- {
- routerlist_t *rl = router_get_routerlist();
- smartlist_t *nodes = smartlist_new();
- smartlist_add_all(nodes, nodelist_get_list());
- SMARTLIST_FOREACH_BEGIN(nodes, node_t *, node) {
- const char *msg = NULL;
- const char *description;
- routerinfo_t *ent = node->ri;
- uint32_t r;
- if (!ent)
- continue;
- r = dirserv_router_get_status(ent, &msg, LOG_INFO);
- description = router_describe(ent);
- if (r & FP_REJECT) {
- log_info(LD_DIRSERV, "Router %s is now rejected: %s",
- description, msg?msg:"");
- routerlist_remove(rl, ent, 0, time(NULL));
- continue;
- }
- if (bool_neq((r & FP_INVALID), !node->is_valid)) {
- log_info(LD_DIRSERV, "Router '%s' is now %svalid.", description,
- (r&FP_INVALID) ? "in" : "");
- node->is_valid = (r&FP_INVALID)?0:1;
- }
- if (bool_neq((r & FP_BADEXIT), node->is_bad_exit)) {
- log_info(LD_DIRSERV, "Router '%s' is now a %s exit", description,
- (r & FP_BADEXIT) ? "bad" : "good");
- node->is_bad_exit = (r&FP_BADEXIT) ? 1: 0;
- }
- } SMARTLIST_FOREACH_END(node);
- routerlist_assert_ok(rl);
- smartlist_free(nodes);
- }
|