mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 21:23:58 +01:00
Merge remote-tracking branch 'tor-github/pr/380'
This commit is contained in:
commit
67351f6724
3
changes/ticket27924
Normal file
3
changes/ticket27924
Normal file
@ -0,0 +1,3 @@
|
||||
o Code simplification and refactoring:
|
||||
- Divide the "routerparse.c" module into separate modules for each
|
||||
group of parsed objects. Closes ticket 27924.
|
@ -45,6 +45,7 @@
|
||||
#include "feature/dirauth/process_descs.h"
|
||||
#include "feature/dircache/consdiffmgr.h"
|
||||
#include "feature/dircache/dirserv.h"
|
||||
#include "feature/dirparse/routerparse.h"
|
||||
#include "feature/hibernate/hibernate.h"
|
||||
#include "feature/hs/hs_cache.h"
|
||||
#include "feature/nodelist/authcert.h"
|
||||
@ -52,7 +53,6 @@
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/relay/dns.h"
|
||||
#include "feature/relay/ext_orport.h"
|
||||
#include "feature/relay/onion_queue.h"
|
||||
@ -61,7 +61,6 @@
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/rend/rendclient.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "lib/geoip/geoip.h"
|
||||
#include "feature/stats/geoip_stats.h"
|
||||
#include "feature/stats/predict_ports.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
@ -70,6 +69,8 @@
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "lib/crypt_ops/crypto_s2k.h"
|
||||
#include "lib/err/backtrace.h"
|
||||
#include "lib/geoip/geoip.h"
|
||||
|
||||
#include "lib/process/waitpid.h"
|
||||
|
||||
#include "lib/meminfo/meminfo.h"
|
||||
@ -423,7 +424,6 @@ dumpstats(int severity)
|
||||
|
||||
rep_hist_dump_stats(now,severity);
|
||||
rend_service_dump_stats(severity);
|
||||
dump_distinct_digest_count(severity);
|
||||
}
|
||||
|
||||
/** Called by exit() as we shut down the process.
|
||||
|
@ -46,6 +46,7 @@ LIBTOR_APP_A_SOURCES = \
|
||||
src/core/or/scheduler_kist.c \
|
||||
src/core/or/scheduler_vanilla.c \
|
||||
src/core/or/status.c \
|
||||
src/core/or/versions.c \
|
||||
src/core/proto/proto_cell.c \
|
||||
src/core/proto/proto_control0.c \
|
||||
src/core/proto/proto_ext_or.c \
|
||||
@ -72,6 +73,15 @@ LIBTOR_APP_A_SOURCES = \
|
||||
src/feature/dircommon/directory.c \
|
||||
src/feature/dircommon/fp_pair.c \
|
||||
src/feature/dircommon/voting_schedule.c \
|
||||
src/feature/dirparse/authcert_parse.c \
|
||||
src/feature/dirparse/microdesc_parse.c \
|
||||
src/feature/dirparse/ns_parse.c \
|
||||
src/feature/dirparse/parsecommon.c \
|
||||
src/feature/dirparse/policy_parse.c \
|
||||
src/feature/dirparse/routerparse.c \
|
||||
src/feature/dirparse/sigcommon.c \
|
||||
src/feature/dirparse/signing.c \
|
||||
src/feature/dirparse/unparseable.c \
|
||||
src/feature/hibernate/hibernate.c \
|
||||
src/feature/hs/hs_cache.c \
|
||||
src/feature/hs/hs_cell.c \
|
||||
@ -98,10 +108,8 @@ LIBTOR_APP_A_SOURCES = \
|
||||
src/feature/nodelist/nickname.c \
|
||||
src/feature/nodelist/nodelist.c \
|
||||
src/feature/nodelist/node_select.c \
|
||||
src/feature/nodelist/parsecommon.c \
|
||||
src/feature/nodelist/routerinfo.c \
|
||||
src/feature/nodelist/routerlist.c \
|
||||
src/feature/nodelist/routerparse.c \
|
||||
src/feature/nodelist/routerset.c \
|
||||
src/feature/nodelist/fmt_routerstatus.c \
|
||||
src/feature/nodelist/torcert.c \
|
||||
@ -116,6 +124,7 @@ LIBTOR_APP_A_SOURCES = \
|
||||
src/feature/rend/rendclient.c \
|
||||
src/feature/rend/rendcommon.c \
|
||||
src/feature/rend/rendmid.c \
|
||||
src/feature/rend/rendparse.c \
|
||||
src/feature/rend/rendservice.c \
|
||||
src/feature/stats/geoip_stats.c \
|
||||
src/feature/stats/rephist.c \
|
||||
@ -125,6 +134,7 @@ LIBTOR_APP_A_SOURCES = \
|
||||
# the separation is only in the code location.
|
||||
LIBTOR_APP_A_SOURCES += \
|
||||
src/feature/dirauth/bwauth.c \
|
||||
src/feature/dirauth/dsigs_parse.c \
|
||||
src/feature/dirauth/guardfraction.c \
|
||||
src/feature/dirauth/reachability.c \
|
||||
src/feature/dirauth/recommend_pkg.c \
|
||||
@ -240,6 +250,7 @@ noinst_HEADERS += \
|
||||
src/core/or/status.h \
|
||||
src/core/or/tor_version_st.h \
|
||||
src/core/or/var_cell_st.h \
|
||||
src/core/or/versions.h \
|
||||
src/core/proto/proto_cell.h \
|
||||
src/core/proto/proto_control0.h \
|
||||
src/core/proto/proto_ext_or.h \
|
||||
@ -260,6 +271,7 @@ noinst_HEADERS += \
|
||||
src/feature/dirauth/bwauth.h \
|
||||
src/feature/dirauth/dircollate.h \
|
||||
src/feature/dirauth/dirvote.h \
|
||||
src/feature/dirauth/dsigs_parse.h \
|
||||
src/feature/dirauth/guardfraction.h \
|
||||
src/feature/dirauth/keypin.h \
|
||||
src/feature/dirauth/ns_detached_signatures_st.h \
|
||||
@ -285,6 +297,16 @@ noinst_HEADERS += \
|
||||
src/feature/dircommon/fp_pair.h \
|
||||
src/feature/dircommon/vote_timing_st.h \
|
||||
src/feature/dircommon/voting_schedule.h \
|
||||
src/feature/dirparse/authcert_members.i \
|
||||
src/feature/dirparse/authcert_parse.h \
|
||||
src/feature/dirparse/microdesc_parse.h \
|
||||
src/feature/dirparse/ns_parse.h \
|
||||
src/feature/dirparse/parsecommon.h \
|
||||
src/feature/dirparse/policy_parse.h \
|
||||
src/feature/dirparse/routerparse.h \
|
||||
src/feature/dirparse/sigcommon.h \
|
||||
src/feature/dirparse/signing.h \
|
||||
src/feature/dirparse/unparseable.h \
|
||||
src/feature/hibernate/hibernate.h \
|
||||
src/feature/hs/hs_cache.h \
|
||||
src/feature/hs/hs_cell.h \
|
||||
@ -320,12 +342,10 @@ noinst_HEADERS += \
|
||||
src/feature/nodelist/node_st.h \
|
||||
src/feature/nodelist/nodelist.h \
|
||||
src/feature/nodelist/node_select.h \
|
||||
src/feature/nodelist/parsecommon.h \
|
||||
src/feature/nodelist/routerinfo.h \
|
||||
src/feature/nodelist/routerinfo_st.h \
|
||||
src/feature/nodelist/routerlist.h \
|
||||
src/feature/nodelist/routerlist_st.h \
|
||||
src/feature/nodelist/routerparse.h \
|
||||
src/feature/nodelist/routerset.h \
|
||||
src/feature/nodelist/fmt_routerstatus.h \
|
||||
src/feature/nodelist/routerstatus_st.h \
|
||||
@ -348,6 +368,7 @@ noinst_HEADERS += \
|
||||
src/feature/rend/rendclient.h \
|
||||
src/feature/rend/rendcommon.h \
|
||||
src/feature/rend/rendmid.h \
|
||||
src/feature/rend/rendparse.h \
|
||||
src/feature/rend/rendservice.h \
|
||||
src/feature/stats/geoip_stats.h \
|
||||
src/feature/stats/rephist.h \
|
||||
|
@ -96,15 +96,14 @@
|
||||
#include "feature/hs/hs_ident.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/relay/dns.h"
|
||||
#include "feature/relay/ext_orport.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
#include "feature/rend/rendclient.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "lib/geoip/geoip.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
#include "lib/crypt_ops/crypto_util.h"
|
||||
#include "lib/geoip/geoip.h"
|
||||
|
||||
#include "lib/sandbox/sandbox.h"
|
||||
#include "lib/net/buffers_net.h"
|
||||
|
@ -61,7 +61,6 @@
|
||||
#include "feature/nodelist/node_select.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/nodelist/routerset.h"
|
||||
#include "feature/relay/router.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
|
@ -20,13 +20,13 @@
|
||||
#include "core/or/or.h"
|
||||
#include "feature/client/bridges.h"
|
||||
#include "app/config/config.h"
|
||||
#include "core/or/policies.h"
|
||||
#include "feature/dirparse/policy_parse.h"
|
||||
#include "feature/nodelist/microdesc.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "core/or/policies.h"
|
||||
#include "feature/relay/router.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "lib/geoip/geoip.h"
|
||||
#include "ht.h"
|
||||
#include "lib/encoding/confline.h"
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "core/or/protover.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "core/or/versions.h"
|
||||
#include "lib/tls/tortls.h"
|
||||
|
||||
#ifndef HAVE_RUST
|
||||
|
@ -79,7 +79,6 @@
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/nodelist/describe.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "core/or/scheduler.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
|
||||
|
422
src/core/or/versions.c
Normal file
422
src/core/or/versions.c
Normal file
@ -0,0 +1,422 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 versions.c
|
||||
* \brief Code to manipulate, parse, and compare Tor versions.
|
||||
*/
|
||||
#include "core/or/or.h"
|
||||
|
||||
#include "core/or/protover.h"
|
||||
#include "core/or/versions.h"
|
||||
#include "lib/crypt_ops/crypto_util.h"
|
||||
|
||||
#include "core/or/tor_version_st.h"
|
||||
|
||||
/** Return VS_RECOMMENDED if <b>myversion</b> is contained in
|
||||
* <b>versionlist</b>. Else, return VS_EMPTY if versionlist has no
|
||||
* entries. Else, return VS_OLD if every member of
|
||||
* <b>versionlist</b> is newer than <b>myversion</b>. Else, return
|
||||
* VS_NEW_IN_SERIES if there is at least one member of <b>versionlist</b> in
|
||||
* the same series (major.minor.micro) as <b>myversion</b>, but no such member
|
||||
* is newer than <b>myversion.</b>. Else, return VS_NEW if every member of
|
||||
* <b>versionlist</b> is older than <b>myversion</b>. Else, return
|
||||
* VS_UNRECOMMENDED.
|
||||
*
|
||||
* (versionlist is a comma-separated list of version strings,
|
||||
* optionally prefixed with "Tor". Versions that can't be parsed are
|
||||
* ignored.)
|
||||
*/
|
||||
version_status_t
|
||||
tor_version_is_obsolete(const char *myversion, const char *versionlist)
|
||||
{
|
||||
tor_version_t mine, other;
|
||||
int found_newer = 0, found_older = 0, found_newer_in_series = 0,
|
||||
found_any_in_series = 0, r, same;
|
||||
version_status_t ret = VS_UNRECOMMENDED;
|
||||
smartlist_t *version_sl;
|
||||
|
||||
log_debug(LD_CONFIG,"Checking whether version '%s' is in '%s'",
|
||||
myversion, versionlist);
|
||||
|
||||
if (tor_version_parse(myversion, &mine)) {
|
||||
log_err(LD_BUG,"I couldn't parse my own version (%s)", myversion);
|
||||
tor_assert(0);
|
||||
}
|
||||
version_sl = smartlist_new();
|
||||
smartlist_split_string(version_sl, versionlist, ",", SPLIT_SKIP_SPACE, 0);
|
||||
|
||||
if (!strlen(versionlist)) { /* no authorities cared or agreed */
|
||||
ret = VS_EMPTY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(version_sl, const char *, cp) {
|
||||
if (!strcmpstart(cp, "Tor "))
|
||||
cp += 4;
|
||||
|
||||
if (tor_version_parse(cp, &other)) {
|
||||
/* Couldn't parse other; it can't be a match. */
|
||||
} else {
|
||||
same = tor_version_same_series(&mine, &other);
|
||||
if (same)
|
||||
found_any_in_series = 1;
|
||||
r = tor_version_compare(&mine, &other);
|
||||
if (r==0) {
|
||||
ret = VS_RECOMMENDED;
|
||||
goto done;
|
||||
} else if (r<0) {
|
||||
found_newer = 1;
|
||||
if (same)
|
||||
found_newer_in_series = 1;
|
||||
} else if (r>0) {
|
||||
found_older = 1;
|
||||
}
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(cp);
|
||||
|
||||
/* We didn't find the listed version. Is it new or old? */
|
||||
if (found_any_in_series && !found_newer_in_series && found_newer) {
|
||||
ret = VS_NEW_IN_SERIES;
|
||||
} else if (found_newer && !found_older) {
|
||||
ret = VS_OLD;
|
||||
} else if (found_older && !found_newer) {
|
||||
ret = VS_NEW;
|
||||
} else {
|
||||
ret = VS_UNRECOMMENDED;
|
||||
}
|
||||
|
||||
done:
|
||||
SMARTLIST_FOREACH(version_sl, char *, version, tor_free(version));
|
||||
smartlist_free(version_sl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Extract a Tor version from a <b>platform</b> line from a router
|
||||
* descriptor, and place the result in <b>router_version</b>.
|
||||
*
|
||||
* Return 1 on success, -1 on parsing failure, and 0 if the
|
||||
* platform line does not indicate some version of Tor.
|
||||
*
|
||||
* If <b>strict</b> is non-zero, finding any weird version components
|
||||
* (like negative numbers) counts as a parsing failure.
|
||||
*/
|
||||
int
|
||||
tor_version_parse_platform(const char *platform,
|
||||
tor_version_t *router_version,
|
||||
int strict)
|
||||
{
|
||||
char tmp[128];
|
||||
char *s, *s2, *start;
|
||||
|
||||
if (strcmpstart(platform,"Tor ")) /* nonstandard Tor; say 0. */
|
||||
return 0;
|
||||
|
||||
start = (char *)eat_whitespace(platform+3);
|
||||
if (!*start) return -1;
|
||||
s = (char *)find_whitespace(start); /* also finds '\0', which is fine */
|
||||
s2 = (char*)eat_whitespace(s);
|
||||
if (!strcmpstart(s2, "(r") || !strcmpstart(s2, "(git-"))
|
||||
s = (char*)find_whitespace(s2);
|
||||
|
||||
if ((size_t)(s-start+1) >= sizeof(tmp)) /* too big, no */
|
||||
return -1;
|
||||
strlcpy(tmp, start, s-start+1);
|
||||
|
||||
if (tor_version_parse(tmp, router_version)<0) {
|
||||
log_info(LD_DIR,"Router version '%s' unparseable.",tmp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strict) {
|
||||
if (router_version->major < 0 ||
|
||||
router_version->minor < 0 ||
|
||||
router_version->micro < 0 ||
|
||||
router_version->patchlevel < 0 ||
|
||||
router_version->svn_revision < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Parse the Tor version of the platform string <b>platform</b>,
|
||||
* and compare it to the version in <b>cutoff</b>. Return 1 if
|
||||
* the router is at least as new as the cutoff, else return 0.
|
||||
*/
|
||||
int
|
||||
tor_version_as_new_as(const char *platform, const char *cutoff)
|
||||
{
|
||||
tor_version_t cutoff_version, router_version;
|
||||
int r;
|
||||
tor_assert(platform);
|
||||
|
||||
if (tor_version_parse(cutoff, &cutoff_version)<0) {
|
||||
log_warn(LD_BUG,"cutoff version '%s' unparseable.",cutoff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = tor_version_parse_platform(platform, &router_version, 0);
|
||||
if (r == 0) {
|
||||
/* nonstandard Tor; be safe and say yes */
|
||||
return 1;
|
||||
} else if (r < 0) {
|
||||
/* unparseable version; be safe and say yes. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Here's why we don't need to do any special handling for svn revisions:
|
||||
* - If neither has an svn revision, we're fine.
|
||||
* - If the router doesn't have an svn revision, we can't assume that it
|
||||
* is "at least" any svn revision, so we need to return 0.
|
||||
* - If the target version doesn't have an svn revision, any svn revision
|
||||
* (or none at all) is good enough, so return 1.
|
||||
* - If both target and router have an svn revision, we compare them.
|
||||
*/
|
||||
|
||||
return tor_version_compare(&router_version, &cutoff_version) >= 0;
|
||||
}
|
||||
|
||||
/** Parse a tor version from <b>s</b>, and store the result in <b>out</b>.
|
||||
* Return 0 on success, -1 on failure. */
|
||||
int
|
||||
tor_version_parse(const char *s, tor_version_t *out)
|
||||
{
|
||||
char *eos=NULL;
|
||||
const char *cp=NULL;
|
||||
int ok = 1;
|
||||
/* Format is:
|
||||
* "Tor " ? NUM dot NUM [ dot NUM [ ( pre | rc | dot ) NUM ] ] [ - tag ]
|
||||
*/
|
||||
tor_assert(s);
|
||||
tor_assert(out);
|
||||
|
||||
memset(out, 0, sizeof(tor_version_t));
|
||||
out->status = VER_RELEASE;
|
||||
if (!strcasecmpstart(s, "Tor "))
|
||||
s += 4;
|
||||
|
||||
cp = s;
|
||||
|
||||
#define NUMBER(m) \
|
||||
do { \
|
||||
if (!cp || *cp < '0' || *cp > '9') \
|
||||
return -1; \
|
||||
out->m = (int)tor_parse_uint64(cp, 10, 0, INT32_MAX, &ok, &eos); \
|
||||
if (!ok) \
|
||||
return -1; \
|
||||
if (!eos || eos == cp) \
|
||||
return -1; \
|
||||
cp = eos; \
|
||||
} while (0)
|
||||
|
||||
#define DOT() \
|
||||
do { \
|
||||
if (*cp != '.') \
|
||||
return -1; \
|
||||
++cp; \
|
||||
} while (0)
|
||||
|
||||
NUMBER(major);
|
||||
DOT();
|
||||
NUMBER(minor);
|
||||
if (*cp == 0)
|
||||
return 0;
|
||||
else if (*cp == '-')
|
||||
goto status_tag;
|
||||
DOT();
|
||||
NUMBER(micro);
|
||||
|
||||
/* Get status */
|
||||
if (*cp == 0) {
|
||||
return 0;
|
||||
} else if (*cp == '.') {
|
||||
++cp;
|
||||
} else if (*cp == '-') {
|
||||
goto status_tag;
|
||||
} else if (0==strncmp(cp, "pre", 3)) {
|
||||
out->status = VER_PRE;
|
||||
cp += 3;
|
||||
} else if (0==strncmp(cp, "rc", 2)) {
|
||||
out->status = VER_RC;
|
||||
cp += 2;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
NUMBER(patchlevel);
|
||||
|
||||
status_tag:
|
||||
/* Get status tag. */
|
||||
if (*cp == '-' || *cp == '.')
|
||||
++cp;
|
||||
eos = (char*) find_whitespace(cp);
|
||||
if (eos-cp >= (int)sizeof(out->status_tag))
|
||||
strlcpy(out->status_tag, cp, sizeof(out->status_tag));
|
||||
else {
|
||||
memcpy(out->status_tag, cp, eos-cp);
|
||||
out->status_tag[eos-cp] = 0;
|
||||
}
|
||||
cp = eat_whitespace(eos);
|
||||
|
||||
if (!strcmpstart(cp, "(r")) {
|
||||
cp += 2;
|
||||
out->svn_revision = (int) strtol(cp,&eos,10);
|
||||
} else if (!strcmpstart(cp, "(git-")) {
|
||||
char *close_paren = strchr(cp, ')');
|
||||
int hexlen;
|
||||
char digest[DIGEST_LEN];
|
||||
if (! close_paren)
|
||||
return -1;
|
||||
cp += 5;
|
||||
if (close_paren-cp > HEX_DIGEST_LEN)
|
||||
return -1;
|
||||
hexlen = (int)(close_paren-cp);
|
||||
memwipe(digest, 0, sizeof(digest));
|
||||
if ( hexlen == 0 || (hexlen % 2) == 1)
|
||||
return -1;
|
||||
if (base16_decode(digest, hexlen/2, cp, hexlen) != hexlen/2)
|
||||
return -1;
|
||||
memcpy(out->git_tag, digest, hexlen/2);
|
||||
out->git_tag_len = hexlen/2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#undef NUMBER
|
||||
#undef DOT
|
||||
}
|
||||
|
||||
/** Compare two tor versions; Return <0 if a < b; 0 if a ==b, >0 if a >
|
||||
* b. */
|
||||
int
|
||||
tor_version_compare(tor_version_t *a, tor_version_t *b)
|
||||
{
|
||||
int i;
|
||||
tor_assert(a);
|
||||
tor_assert(b);
|
||||
|
||||
/* We take this approach to comparison to ensure the same (bogus!) behavior
|
||||
* on all inputs as we would have seen before bug #21278 was fixed. The
|
||||
* only important difference here is that this method doesn't cause
|
||||
* a signed integer underflow.
|
||||
*/
|
||||
#define CMP(field) do { \
|
||||
unsigned aval = (unsigned) a->field; \
|
||||
unsigned bval = (unsigned) b->field; \
|
||||
int result = (int) (aval - bval); \
|
||||
if (result < 0) \
|
||||
return -1; \
|
||||
else if (result > 0) \
|
||||
return 1; \
|
||||
} while (0)
|
||||
|
||||
CMP(major);
|
||||
CMP(minor);
|
||||
CMP(micro);
|
||||
CMP(status);
|
||||
CMP(patchlevel);
|
||||
if ((i = strcmp(a->status_tag, b->status_tag)))
|
||||
return i;
|
||||
CMP(svn_revision);
|
||||
CMP(git_tag_len);
|
||||
if (a->git_tag_len)
|
||||
return fast_memcmp(a->git_tag, b->git_tag, a->git_tag_len);
|
||||
else
|
||||
return 0;
|
||||
|
||||
#undef CMP
|
||||
}
|
||||
|
||||
/** Return true iff versions <b>a</b> and <b>b</b> belong to the same series.
|
||||
*/
|
||||
int
|
||||
tor_version_same_series(tor_version_t *a, tor_version_t *b)
|
||||
{
|
||||
tor_assert(a);
|
||||
tor_assert(b);
|
||||
return ((a->major == b->major) &&
|
||||
(a->minor == b->minor) &&
|
||||
(a->micro == b->micro));
|
||||
}
|
||||
|
||||
/** Helper: Given pointers to two strings describing tor versions, return -1
|
||||
* if _a precedes _b, 1 if _b precedes _a, and 0 if they are equivalent.
|
||||
* Used to sort a list of versions. */
|
||||
static int
|
||||
compare_tor_version_str_ptr_(const void **_a, const void **_b)
|
||||
{
|
||||
const char *a = *_a, *b = *_b;
|
||||
int ca, cb;
|
||||
tor_version_t va, vb;
|
||||
ca = tor_version_parse(a, &va);
|
||||
cb = tor_version_parse(b, &vb);
|
||||
/* If they both parse, compare them. */
|
||||
if (!ca && !cb)
|
||||
return tor_version_compare(&va,&vb);
|
||||
/* If one parses, it comes first. */
|
||||
if (!ca && cb)
|
||||
return -1;
|
||||
if (ca && !cb)
|
||||
return 1;
|
||||
/* If neither parses, compare strings. Also, the directory server admin
|
||||
** needs to be smacked upside the head. But Tor is tolerant and gentle. */
|
||||
return strcmp(a,b);
|
||||
}
|
||||
|
||||
/** Sort a list of string-representations of versions in ascending order. */
|
||||
void
|
||||
sort_version_list(smartlist_t *versions, int remove_duplicates)
|
||||
{
|
||||
smartlist_sort(versions, compare_tor_version_str_ptr_);
|
||||
|
||||
if (remove_duplicates)
|
||||
smartlist_uniq(versions, compare_tor_version_str_ptr_, tor_free_);
|
||||
}
|
||||
|
||||
/** Summarize the protocols listed in <b>protocols</b> into <b>out</b>,
|
||||
* falling back or correcting them based on <b>version</b> as appropriate.
|
||||
*/
|
||||
void
|
||||
summarize_protover_flags(protover_summary_flags_t *out,
|
||||
const char *protocols,
|
||||
const char *version)
|
||||
{
|
||||
tor_assert(out);
|
||||
memset(out, 0, sizeof(*out));
|
||||
if (protocols) {
|
||||
out->protocols_known = 1;
|
||||
out->supports_extend2_cells =
|
||||
protocol_list_supports_protocol(protocols, PRT_RELAY, 2);
|
||||
out->supports_ed25519_link_handshake_compat =
|
||||
protocol_list_supports_protocol(protocols, PRT_LINKAUTH, 3);
|
||||
out->supports_ed25519_link_handshake_any =
|
||||
protocol_list_supports_protocol_or_later(protocols, PRT_LINKAUTH, 3);
|
||||
out->supports_ed25519_hs_intro =
|
||||
protocol_list_supports_protocol(protocols, PRT_HSINTRO, 4);
|
||||
out->supports_v3_hsdir =
|
||||
protocol_list_supports_protocol(protocols, PRT_HSDIR,
|
||||
PROTOVER_HSDIR_V3);
|
||||
out->supports_v3_rendezvous_point =
|
||||
protocol_list_supports_protocol(protocols, PRT_HSREND,
|
||||
PROTOVER_HS_RENDEZVOUS_POINT_V3);
|
||||
}
|
||||
if (version && !strcmpstart(version, "Tor ")) {
|
||||
if (!out->protocols_known) {
|
||||
/* The version is a "Tor" version, and where there is no
|
||||
* list of protocol versions that we should be looking at instead. */
|
||||
|
||||
out->supports_extend2_cells =
|
||||
tor_version_as_new_as(version, "0.2.4.8-alpha");
|
||||
out->protocols_known = 1;
|
||||
} else {
|
||||
/* Bug #22447 forces us to filter on this version. */
|
||||
if (!tor_version_as_new_as(version, "0.3.0.8")) {
|
||||
out->supports_v3_hsdir = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
44
src/core/or/versions.h
Normal file
44
src/core/or/versions.h
Normal file
@ -0,0 +1,44 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 versions.h
|
||||
* \brief Header file for versions.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_VERSIONS_H
|
||||
#define TOR_VERSIONS_H
|
||||
|
||||
/** Possible statuses of a version of Tor, given opinions from the directory
|
||||
* servers. */
|
||||
typedef enum version_status_t {
|
||||
VS_RECOMMENDED=0, /**< This version is listed as recommended. */
|
||||
VS_OLD=1, /**< This version is older than any recommended version. */
|
||||
VS_NEW=2, /**< This version is newer than any recommended version. */
|
||||
VS_NEW_IN_SERIES=3, /**< This version is newer than any recommended version
|
||||
* in its series, but later recommended versions exist.
|
||||
*/
|
||||
VS_UNRECOMMENDED=4, /**< This version is not recommended (general case). */
|
||||
VS_EMPTY=5, /**< The version list was empty; no agreed-on versions. */
|
||||
VS_UNKNOWN, /**< We have no idea. */
|
||||
} version_status_t;
|
||||
|
||||
version_status_t tor_version_is_obsolete(const char *myversion,
|
||||
const char *versionlist);
|
||||
int tor_version_parse_platform(const char *platform,
|
||||
tor_version_t *version_out,
|
||||
int strict);
|
||||
int tor_version_as_new_as(const char *platform, const char *cutoff);
|
||||
int tor_version_parse(const char *s, tor_version_t *out);
|
||||
int tor_version_compare(tor_version_t *a, tor_version_t *b);
|
||||
int tor_version_same_series(tor_version_t *a, tor_version_t *b);
|
||||
void sort_version_list(smartlist_t *lst, int remove_duplicates);
|
||||
|
||||
void summarize_protover_flags(protover_summary_flags_t *out,
|
||||
const char *protocols,
|
||||
const char *version);
|
||||
|
||||
#endif /* !defined(TOR_VERSIONS_H) */
|
@ -134,9 +134,8 @@
|
||||
#include "feature/nodelist/microdesc.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/nickname.h"
|
||||
#include "feature/nodelist/node_select.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/nodelist/node_select.h"
|
||||
#include "feature/nodelist/routerset.h"
|
||||
#include "feature/relay/router.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "core/or/connection_or.h"
|
||||
#include "core/or/policies.h"
|
||||
#include "core/or/reasons.h"
|
||||
#include "core/or/versions.h"
|
||||
#include "core/proto/proto_control0.h"
|
||||
#include "core/proto/proto_http.h"
|
||||
#include "feature/client/addressmap.h"
|
||||
@ -77,12 +78,12 @@
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerinfo.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/relay/router.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
#include "feature/relay/selftest.h"
|
||||
#include "feature/rend/rendclient.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendparse.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "feature/stats/geoip_stats.h"
|
||||
#include "feature/stats/predict_ports.h"
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include "app/config/config.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/ns_parse.h"
|
||||
|
||||
#include "feature/nodelist/routerinfo_st.h"
|
||||
#include "feature/nodelist/vote_routerstatus_st.h"
|
||||
|
@ -6,29 +6,33 @@
|
||||
#define DIRVOTE_PRIVATE
|
||||
#include "core/or/or.h"
|
||||
#include "app/config/config.h"
|
||||
#include "feature/dirauth/dircollate.h"
|
||||
#include "feature/dirauth/recommend_pkg.h"
|
||||
#include "feature/dirauth/voteflags.h"
|
||||
#include "feature/dircommon/directory.h"
|
||||
#include "feature/dirclient/dirclient.h"
|
||||
#include "feature/dirauth/bwauth.h"
|
||||
#include "feature/dircache/dirserv.h"
|
||||
#include "feature/dirauth/guardfraction.h"
|
||||
#include "feature/nodelist/microdesc.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/parsecommon.h"
|
||||
#include "core/or/policies.h"
|
||||
#include "core/or/protover.h"
|
||||
#include "core/or/tor_version_st.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
#include "feature/relay/router.h"
|
||||
#include "feature/relay/routerkeys.h"
|
||||
#include "core/or/versions.h"
|
||||
#include "feature/dirauth/bwauth.h"
|
||||
#include "feature/dirauth/dircollate.h"
|
||||
#include "feature/dirauth/dsigs_parse.h"
|
||||
#include "feature/dirauth/guardfraction.h"
|
||||
#include "feature/dirauth/recommend_pkg.h"
|
||||
#include "feature/dirauth/voteflags.h"
|
||||
#include "feature/dircache/dirserv.h"
|
||||
#include "feature/dirclient/dirclient.h"
|
||||
#include "feature/dircommon/directory.h"
|
||||
#include "feature/dirparse/microdesc_parse.h"
|
||||
#include "feature/dirparse/ns_parse.h"
|
||||
#include "feature/dirparse/parsecommon.h"
|
||||
#include "feature/dirparse/signing.h"
|
||||
#include "feature/nodelist/authcert.h"
|
||||
#include "feature/nodelist/dirlist.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/nodelist/fmt_routerstatus.h"
|
||||
#include "feature/nodelist/microdesc.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/relay/router.h"
|
||||
#include "feature/relay/routerkeys.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
#include "feature/client/entrynodes.h" /* needed for guardfraction methods */
|
||||
#include "feature/nodelist/torcert.h"
|
||||
#include "feature/dircommon/voting_schedule.h"
|
||||
|
282
src/feature/dirauth/dsigs_parse.c
Normal file
282
src/feature/dirauth/dsigs_parse.c
Normal file
@ -0,0 +1,282 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 dsigs_parse.h
|
||||
* \brief Code to parse and validate detached-signature objects
|
||||
**/
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "feature/dirparse/parsecommon.h"
|
||||
#include "feature/dirparse/unparseable.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "lib/memarea/memarea.h"
|
||||
|
||||
#include "feature/dirauth/dsigs_parse.h"
|
||||
#include "feature/dirauth/ns_detached_signatures_st.h"
|
||||
#include "feature/nodelist/document_signature_st.h"
|
||||
|
||||
/** List of tokens recognized in detached networkstatus signature documents. */
|
||||
static token_rule_t networkstatus_detached_signature_token_table[] = {
|
||||
T1_START("consensus-digest", K_CONSENSUS_DIGEST, GE(1), NO_OBJ ),
|
||||
T("additional-digest", K_ADDITIONAL_DIGEST,GE(3), NO_OBJ ),
|
||||
T1("valid-after", K_VALID_AFTER, CONCAT_ARGS, NO_OBJ ),
|
||||
T1("fresh-until", K_FRESH_UNTIL, CONCAT_ARGS, NO_OBJ ),
|
||||
T1("valid-until", K_VALID_UNTIL, CONCAT_ARGS, NO_OBJ ),
|
||||
T("additional-signature", K_ADDITIONAL_SIGNATURE, GE(4), NEED_OBJ ),
|
||||
T1N("directory-signature", K_DIRECTORY_SIGNATURE, GE(2), NEED_OBJ ),
|
||||
END_OF_TABLE
|
||||
};
|
||||
|
||||
/** Return the common_digests_t that holds the digests of the
|
||||
* <b>flavor_name</b>-flavored networkstatus according to the detached
|
||||
* signatures document <b>sigs</b>, allocating a new common_digests_t as
|
||||
* needed. */
|
||||
static common_digests_t *
|
||||
detached_get_digests(ns_detached_signatures_t *sigs, const char *flavor_name)
|
||||
{
|
||||
common_digests_t *d = strmap_get(sigs->digests, flavor_name);
|
||||
if (!d) {
|
||||
d = tor_malloc_zero(sizeof(common_digests_t));
|
||||
strmap_set(sigs->digests, flavor_name, d);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
/** Return the list of signatures of the <b>flavor_name</b>-flavored
|
||||
* networkstatus according to the detached signatures document <b>sigs</b>,
|
||||
* allocating a new common_digests_t as needed. */
|
||||
static smartlist_t *
|
||||
detached_get_signatures(ns_detached_signatures_t *sigs,
|
||||
const char *flavor_name)
|
||||
{
|
||||
smartlist_t *sl = strmap_get(sigs->signatures, flavor_name);
|
||||
if (!sl) {
|
||||
sl = smartlist_new();
|
||||
strmap_set(sigs->signatures, flavor_name, sl);
|
||||
}
|
||||
return sl;
|
||||
}
|
||||
|
||||
/** Parse a detached v3 networkstatus signature document between <b>s</b> and
|
||||
* <b>eos</b> and return the result. Return -1 on failure. */
|
||||
ns_detached_signatures_t *
|
||||
networkstatus_parse_detached_signatures(const char *s, const char *eos)
|
||||
{
|
||||
/* XXXX there is too much duplicate shared between this function and
|
||||
* networkstatus_parse_vote_from_string(). */
|
||||
directory_token_t *tok;
|
||||
memarea_t *area = NULL;
|
||||
common_digests_t *digests;
|
||||
|
||||
smartlist_t *tokens = smartlist_new();
|
||||
ns_detached_signatures_t *sigs =
|
||||
tor_malloc_zero(sizeof(ns_detached_signatures_t));
|
||||
sigs->digests = strmap_new();
|
||||
sigs->signatures = strmap_new();
|
||||
|
||||
if (!eos)
|
||||
eos = s + strlen(s);
|
||||
|
||||
area = memarea_new();
|
||||
if (tokenize_string(area,s, eos, tokens,
|
||||
networkstatus_detached_signature_token_table, 0)) {
|
||||
log_warn(LD_DIR, "Error tokenizing detached networkstatus signatures");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Grab all the digest-like tokens. */
|
||||
SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) {
|
||||
const char *algname;
|
||||
digest_algorithm_t alg;
|
||||
const char *flavor;
|
||||
const char *hexdigest;
|
||||
size_t expected_length, digest_length;
|
||||
|
||||
tok = _tok;
|
||||
|
||||
if (tok->tp == K_CONSENSUS_DIGEST) {
|
||||
algname = "sha1";
|
||||
alg = DIGEST_SHA1;
|
||||
flavor = "ns";
|
||||
hexdigest = tok->args[0];
|
||||
} else if (tok->tp == K_ADDITIONAL_DIGEST) {
|
||||
int a = crypto_digest_algorithm_parse_name(tok->args[1]);
|
||||
if (a<0) {
|
||||
log_warn(LD_DIR, "Unrecognized algorithm name %s", tok->args[0]);
|
||||
continue;
|
||||
}
|
||||
alg = (digest_algorithm_t) a;
|
||||
flavor = tok->args[0];
|
||||
algname = tok->args[1];
|
||||
hexdigest = tok->args[2];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
digest_length = crypto_digest_algorithm_get_length(alg);
|
||||
expected_length = digest_length * 2; /* hex encoding */
|
||||
|
||||
if (strlen(hexdigest) != expected_length) {
|
||||
log_warn(LD_DIR, "Wrong length on consensus-digest in detached "
|
||||
"networkstatus signatures");
|
||||
goto err;
|
||||
}
|
||||
digests = detached_get_digests(sigs, flavor);
|
||||
tor_assert(digests);
|
||||
if (!tor_mem_is_zero(digests->d[alg], digest_length)) {
|
||||
log_warn(LD_DIR, "Multiple digests for %s with %s on detached "
|
||||
"signatures document", flavor, algname);
|
||||
continue;
|
||||
}
|
||||
if (base16_decode(digests->d[alg], digest_length,
|
||||
hexdigest, strlen(hexdigest)) != (int) digest_length) {
|
||||
log_warn(LD_DIR, "Bad encoding on consensus-digest in detached "
|
||||
"networkstatus signatures");
|
||||
goto err;
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(_tok);
|
||||
|
||||
tok = find_by_keyword(tokens, K_VALID_AFTER);
|
||||
if (parse_iso_time(tok->args[0], &sigs->valid_after)) {
|
||||
log_warn(LD_DIR, "Bad valid-after in detached networkstatus signatures");
|
||||
goto err;
|
||||
}
|
||||
|
||||
tok = find_by_keyword(tokens, K_FRESH_UNTIL);
|
||||
if (parse_iso_time(tok->args[0], &sigs->fresh_until)) {
|
||||
log_warn(LD_DIR, "Bad fresh-until in detached networkstatus signatures");
|
||||
goto err;
|
||||
}
|
||||
|
||||
tok = find_by_keyword(tokens, K_VALID_UNTIL);
|
||||
if (parse_iso_time(tok->args[0], &sigs->valid_until)) {
|
||||
log_warn(LD_DIR, "Bad valid-until in detached networkstatus signatures");
|
||||
goto err;
|
||||
}
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) {
|
||||
const char *id_hexdigest;
|
||||
const char *sk_hexdigest;
|
||||
const char *algname;
|
||||
const char *flavor;
|
||||
digest_algorithm_t alg;
|
||||
|
||||
char id_digest[DIGEST_LEN];
|
||||
char sk_digest[DIGEST_LEN];
|
||||
smartlist_t *siglist;
|
||||
document_signature_t *sig;
|
||||
int is_duplicate;
|
||||
|
||||
tok = _tok;
|
||||
if (tok->tp == K_DIRECTORY_SIGNATURE) {
|
||||
tor_assert(tok->n_args >= 2);
|
||||
flavor = "ns";
|
||||
algname = "sha1";
|
||||
id_hexdigest = tok->args[0];
|
||||
sk_hexdigest = tok->args[1];
|
||||
} else if (tok->tp == K_ADDITIONAL_SIGNATURE) {
|
||||
tor_assert(tok->n_args >= 4);
|
||||
flavor = tok->args[0];
|
||||
algname = tok->args[1];
|
||||
id_hexdigest = tok->args[2];
|
||||
sk_hexdigest = tok->args[3];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
int a = crypto_digest_algorithm_parse_name(algname);
|
||||
if (a<0) {
|
||||
log_warn(LD_DIR, "Unrecognized algorithm name %s", algname);
|
||||
continue;
|
||||
}
|
||||
alg = (digest_algorithm_t) a;
|
||||
}
|
||||
|
||||
if (!tok->object_type ||
|
||||
strcmp(tok->object_type, "SIGNATURE") ||
|
||||
tok->object_size < 128 || tok->object_size > 512) {
|
||||
log_warn(LD_DIR, "Bad object type or length on directory-signature");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (strlen(id_hexdigest) != HEX_DIGEST_LEN ||
|
||||
base16_decode(id_digest, sizeof(id_digest),
|
||||
id_hexdigest, HEX_DIGEST_LEN) != sizeof(id_digest)) {
|
||||
log_warn(LD_DIR, "Error decoding declared identity %s in "
|
||||
"network-status vote.", escaped(id_hexdigest));
|
||||
goto err;
|
||||
}
|
||||
if (strlen(sk_hexdigest) != HEX_DIGEST_LEN ||
|
||||
base16_decode(sk_digest, sizeof(sk_digest),
|
||||
sk_hexdigest, HEX_DIGEST_LEN) != sizeof(sk_digest)) {
|
||||
log_warn(LD_DIR, "Error decoding declared signing key digest %s in "
|
||||
"network-status vote.", escaped(sk_hexdigest));
|
||||
goto err;
|
||||
}
|
||||
|
||||
siglist = detached_get_signatures(sigs, flavor);
|
||||
is_duplicate = 0;
|
||||
SMARTLIST_FOREACH(siglist, document_signature_t *, dsig, {
|
||||
if (dsig->alg == alg &&
|
||||
tor_memeq(id_digest, dsig->identity_digest, DIGEST_LEN) &&
|
||||
tor_memeq(sk_digest, dsig->signing_key_digest, DIGEST_LEN)) {
|
||||
is_duplicate = 1;
|
||||
}
|
||||
});
|
||||
if (is_duplicate) {
|
||||
log_warn(LD_DIR, "Two signatures with identical keys and algorithm "
|
||||
"found.");
|
||||
continue;
|
||||
}
|
||||
|
||||
sig = tor_malloc_zero(sizeof(document_signature_t));
|
||||
sig->alg = alg;
|
||||
memcpy(sig->identity_digest, id_digest, DIGEST_LEN);
|
||||
memcpy(sig->signing_key_digest, sk_digest, DIGEST_LEN);
|
||||
if (tok->object_size >= INT_MAX || tok->object_size >= SIZE_T_CEILING) {
|
||||
tor_free(sig);
|
||||
goto err;
|
||||
}
|
||||
sig->signature = tor_memdup(tok->object_body, tok->object_size);
|
||||
sig->signature_len = (int) tok->object_size;
|
||||
|
||||
smartlist_add(siglist, sig);
|
||||
} SMARTLIST_FOREACH_END(_tok);
|
||||
|
||||
goto done;
|
||||
err:
|
||||
ns_detached_signatures_free(sigs);
|
||||
sigs = NULL;
|
||||
done:
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
|
||||
smartlist_free(tokens);
|
||||
if (area) {
|
||||
DUMP_AREA(area, "detached signatures");
|
||||
memarea_drop_all(area);
|
||||
}
|
||||
return sigs;
|
||||
}
|
||||
|
||||
/** Release all storage held in <b>s</b>. */
|
||||
void
|
||||
ns_detached_signatures_free_(ns_detached_signatures_t *s)
|
||||
{
|
||||
if (!s)
|
||||
return;
|
||||
if (s->signatures) {
|
||||
STRMAP_FOREACH(s->signatures, flavor, smartlist_t *, sigs) {
|
||||
SMARTLIST_FOREACH(sigs, document_signature_t *, sig,
|
||||
document_signature_free(sig));
|
||||
smartlist_free(sigs);
|
||||
} STRMAP_FOREACH_END;
|
||||
strmap_free(s->signatures, NULL);
|
||||
strmap_free(s->digests, tor_free_);
|
||||
}
|
||||
|
||||
tor_free(s);
|
||||
}
|
22
src/feature/dirauth/dsigs_parse.h
Normal file
22
src/feature/dirauth/dsigs_parse.h
Normal file
@ -0,0 +1,22 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 dsigs_parse.h
|
||||
* \brief Header file for dsigs_parse.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_DSIGS_PARSE_H
|
||||
#define TOR_DSIGS_PARSE_H
|
||||
|
||||
ns_detached_signatures_t *networkstatus_parse_detached_signatures(
|
||||
const char *s, const char *eos);
|
||||
|
||||
void ns_detached_signatures_free_(ns_detached_signatures_t *s);
|
||||
#define ns_detached_signatures_free(s) \
|
||||
FREE_AND_NULL(ns_detached_signatures_t, ns_detached_signatures_free_, (s))
|
||||
|
||||
#endif
|
@ -12,7 +12,7 @@
|
||||
#include "core/or/or.h"
|
||||
#include "feature/dirauth/guardfraction.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/ns_parse.h"
|
||||
|
||||
#include "feature/nodelist/vote_routerstatus_st.h"
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#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"
|
||||
@ -26,7 +27,7 @@
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerinfo.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/routerparse.h"
|
||||
#include "feature/nodelist/torcert.h"
|
||||
#include "feature/relay/router.h"
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "feature/dircache/consdiffmgr.h"
|
||||
#include "core/mainloop/cpuworker.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/ns_parse.h"
|
||||
#include "lib/evloop/compat_libevent.h"
|
||||
#include "lib/evloop/workqueue.h"
|
||||
#include "lib/compress/compress.h"
|
||||
|
@ -41,7 +41,7 @@
|
||||
#include "core/or/or.h"
|
||||
#include "feature/dircommon/consdiff.h"
|
||||
#include "lib/memarea/memarea.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/ns_parse.h"
|
||||
|
||||
static const char* ns_diff_version = "network-status-diff-version 1";
|
||||
static const char* hash_token = "hash";
|
||||
|
13
src/feature/dirparse/authcert_members.i
Normal file
13
src/feature/dirparse/authcert_members.i
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* List of tokens common to V3 authority certificates and V3 consensuses.
|
||||
*/
|
||||
T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION,
|
||||
GE(1), NO_OBJ ),
|
||||
T1("dir-identity-key", K_DIR_IDENTITY_KEY, NO_ARGS, NEED_KEY ),
|
||||
T1("dir-key-published",K_DIR_KEY_PUBLISHED, CONCAT_ARGS, NO_OBJ),
|
||||
T1("dir-key-expires", K_DIR_KEY_EXPIRES, CONCAT_ARGS, NO_OBJ),
|
||||
T1("dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY ),
|
||||
T1("dir-key-crosscert", K_DIR_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ),
|
||||
T1("dir-key-certification", K_DIR_KEY_CERTIFICATION,
|
||||
NO_ARGS, NEED_OBJ),
|
||||
T01("dir-address", K_DIR_ADDRESS, GE(1), NO_OBJ),
|
207
src/feature/dirparse/authcert_parse.c
Normal file
207
src/feature/dirparse/authcert_parse.c
Normal file
@ -0,0 +1,207 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 */
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "feature/dirparse/authcert_parse.h"
|
||||
#include "feature/dirparse/parsecommon.h"
|
||||
#include "feature/dirparse/sigcommon.h"
|
||||
#include "feature/dirparse/unparseable.h"
|
||||
#include "feature/nodelist/authcert.h"
|
||||
#include "lib/memarea/memarea.h"
|
||||
|
||||
#include "feature/nodelist/authority_cert_st.h"
|
||||
|
||||
/** List of tokens recognized in V3 authority certificates. */
|
||||
static token_rule_t dir_key_certificate_table[] = {
|
||||
#include "feature/dirparse/authcert_members.i"
|
||||
T1("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
|
||||
END_OF_TABLE
|
||||
};
|
||||
|
||||
/** Parse a key certificate from <b>s</b>; point <b>end-of-string</b> to
|
||||
* the first character after the certificate. */
|
||||
authority_cert_t *
|
||||
authority_cert_parse_from_string(const char *s, const char **end_of_string)
|
||||
{
|
||||
/** Reject any certificate at least this big; it is probably an overflow, an
|
||||
* attack, a bug, or some other nonsense. */
|
||||
#define MAX_CERT_SIZE (128*1024)
|
||||
|
||||
authority_cert_t *cert = NULL, *old_cert;
|
||||
smartlist_t *tokens = NULL;
|
||||
char digest[DIGEST_LEN];
|
||||
directory_token_t *tok;
|
||||
char fp_declared[DIGEST_LEN];
|
||||
char *eos;
|
||||
size_t len;
|
||||
int found;
|
||||
memarea_t *area = NULL;
|
||||
const char *s_dup = s;
|
||||
|
||||
s = eat_whitespace(s);
|
||||
eos = strstr(s, "\ndir-key-certification");
|
||||
if (! eos) {
|
||||
log_warn(LD_DIR, "No signature found on key certificate");
|
||||
return NULL;
|
||||
}
|
||||
eos = strstr(eos, "\n-----END SIGNATURE-----\n");
|
||||
if (! eos) {
|
||||
log_warn(LD_DIR, "No end-of-signature found on key certificate");
|
||||
return NULL;
|
||||
}
|
||||
eos = strchr(eos+2, '\n');
|
||||
tor_assert(eos);
|
||||
++eos;
|
||||
len = eos - s;
|
||||
|
||||
if (len > MAX_CERT_SIZE) {
|
||||
log_warn(LD_DIR, "Certificate is far too big (at %lu bytes long); "
|
||||
"rejecting", (unsigned long)len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tokens = smartlist_new();
|
||||
area = memarea_new();
|
||||
if (tokenize_string(area,s, eos, tokens, dir_key_certificate_table, 0) < 0) {
|
||||
log_warn(LD_DIR, "Error tokenizing key certificate");
|
||||
goto err;
|
||||
}
|
||||
if (router_get_hash_impl(s, strlen(s), digest, "dir-key-certificate-version",
|
||||
"\ndir-key-certification", '\n', DIGEST_SHA1) < 0)
|
||||
goto err;
|
||||
tok = smartlist_get(tokens, 0);
|
||||
if (tok->tp != K_DIR_KEY_CERTIFICATE_VERSION || strcmp(tok->args[0], "3")) {
|
||||
log_warn(LD_DIR,
|
||||
"Key certificate does not begin with a recognized version (3).");
|
||||
goto err;
|
||||
}
|
||||
|
||||
cert = tor_malloc_zero(sizeof(authority_cert_t));
|
||||
memcpy(cert->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
|
||||
|
||||
tok = find_by_keyword(tokens, K_DIR_SIGNING_KEY);
|
||||
tor_assert(tok->key);
|
||||
cert->signing_key = tok->key;
|
||||
tok->key = NULL;
|
||||
if (crypto_pk_get_digest(cert->signing_key, cert->signing_key_digest))
|
||||
goto err;
|
||||
|
||||
tok = find_by_keyword(tokens, K_DIR_IDENTITY_KEY);
|
||||
tor_assert(tok->key);
|
||||
cert->identity_key = tok->key;
|
||||
tok->key = NULL;
|
||||
|
||||
tok = find_by_keyword(tokens, K_FINGERPRINT);
|
||||
tor_assert(tok->n_args);
|
||||
if (base16_decode(fp_declared, DIGEST_LEN, tok->args[0],
|
||||
strlen(tok->args[0])) != DIGEST_LEN) {
|
||||
log_warn(LD_DIR, "Couldn't decode key certificate fingerprint %s",
|
||||
escaped(tok->args[0]));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (crypto_pk_get_digest(cert->identity_key,
|
||||
cert->cache_info.identity_digest))
|
||||
goto err;
|
||||
|
||||
if (tor_memneq(cert->cache_info.identity_digest, fp_declared, DIGEST_LEN)) {
|
||||
log_warn(LD_DIR, "Digest of certificate key didn't match declared "
|
||||
"fingerprint");
|
||||
goto err;
|
||||
}
|
||||
|
||||
tok = find_opt_by_keyword(tokens, K_DIR_ADDRESS);
|
||||
if (tok) {
|
||||
struct in_addr in;
|
||||
char *address = NULL;
|
||||
tor_assert(tok->n_args);
|
||||
/* XXX++ use some tor_addr parse function below instead. -RD */
|
||||
if (tor_addr_port_split(LOG_WARN, tok->args[0], &address,
|
||||
&cert->dir_port) < 0 ||
|
||||
tor_inet_aton(address, &in) == 0) {
|
||||
log_warn(LD_DIR, "Couldn't parse dir-address in certificate");
|
||||
tor_free(address);
|
||||
goto err;
|
||||
}
|
||||
cert->addr = ntohl(in.s_addr);
|
||||
tor_free(address);
|
||||
}
|
||||
|
||||
tok = find_by_keyword(tokens, K_DIR_KEY_PUBLISHED);
|
||||
if (parse_iso_time(tok->args[0], &cert->cache_info.published_on) < 0) {
|
||||
goto err;
|
||||
}
|
||||
tok = find_by_keyword(tokens, K_DIR_KEY_EXPIRES);
|
||||
if (parse_iso_time(tok->args[0], &cert->expires) < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
tok = smartlist_get(tokens, smartlist_len(tokens)-1);
|
||||
if (tok->tp != K_DIR_KEY_CERTIFICATION) {
|
||||
log_warn(LD_DIR, "Certificate didn't end with dir-key-certification.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* If we already have this cert, don't bother checking the signature. */
|
||||
old_cert = authority_cert_get_by_digests(
|
||||
cert->cache_info.identity_digest,
|
||||
cert->signing_key_digest);
|
||||
found = 0;
|
||||
if (old_cert) {
|
||||
/* XXXX We could just compare signed_descriptor_digest, but that wouldn't
|
||||
* buy us much. */
|
||||
if (old_cert->cache_info.signed_descriptor_len == len &&
|
||||
old_cert->cache_info.signed_descriptor_body &&
|
||||
tor_memeq(s, old_cert->cache_info.signed_descriptor_body, len)) {
|
||||
log_debug(LD_DIR, "We already checked the signature on this "
|
||||
"certificate; no need to do so again.");
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (check_signature_token(digest, DIGEST_LEN, tok, cert->identity_key, 0,
|
||||
"key certificate")) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
tok = find_by_keyword(tokens, K_DIR_KEY_CROSSCERT);
|
||||
if (check_signature_token(cert->cache_info.identity_digest,
|
||||
DIGEST_LEN,
|
||||
tok,
|
||||
cert->signing_key,
|
||||
CST_NO_CHECK_OBJTYPE,
|
||||
"key cross-certification")) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
cert->cache_info.signed_descriptor_len = len;
|
||||
cert->cache_info.signed_descriptor_body = tor_malloc(len+1);
|
||||
memcpy(cert->cache_info.signed_descriptor_body, s, len);
|
||||
cert->cache_info.signed_descriptor_body[len] = 0;
|
||||
cert->cache_info.saved_location = SAVED_NOWHERE;
|
||||
|
||||
if (end_of_string) {
|
||||
*end_of_string = eat_whitespace(eos);
|
||||
}
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
|
||||
smartlist_free(tokens);
|
||||
if (area) {
|
||||
DUMP_AREA(area, "authority cert");
|
||||
memarea_drop_all(area);
|
||||
}
|
||||
return cert;
|
||||
err:
|
||||
dump_desc(s_dup, "authority cert");
|
||||
authority_cert_free(cert);
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
|
||||
smartlist_free(tokens);
|
||||
if (area) {
|
||||
DUMP_AREA(area, "authority cert");
|
||||
memarea_drop_all(area);
|
||||
}
|
||||
return NULL;
|
||||
}
|
18
src/feature/dirparse/authcert_parse.h
Normal file
18
src/feature/dirparse/authcert_parse.h
Normal file
@ -0,0 +1,18 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 authcert_parse.h
|
||||
* \brief Header file for authcert_parse.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_AUTHCERT_PARSE_H
|
||||
#define TOR_AUTHCERT_PARSE_H
|
||||
|
||||
authority_cert_t *authority_cert_parse_from_string(const char *s,
|
||||
const char **end_of_string);
|
||||
|
||||
#endif /* !defined(TOR_AUTHCERT_PARSE_H) */
|
267
src/feature/dirparse/microdesc_parse.c
Normal file
267
src/feature/dirparse/microdesc_parse.c
Normal file
@ -0,0 +1,267 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 microdesc_parse.c
|
||||
* \brief Code to parse and validate microdescriptors.
|
||||
**/
|
||||
|
||||
#include "core/or/or.h"
|
||||
|
||||
#include "app/config/config.h"
|
||||
#include "core/or/policies.h"
|
||||
#include "feature/dirparse/microdesc_parse.h"
|
||||
#include "feature/dirparse/parsecommon.h"
|
||||
#include "feature/dirparse/routerparse.h"
|
||||
#include "feature/nodelist/microdesc.h"
|
||||
#include "feature/nodelist/nickname.h"
|
||||
#include "feature/relay/router.h"
|
||||
#include "lib/crypt_ops/crypto_curve25519.h"
|
||||
#include "lib/crypt_ops/crypto_ed25519.h"
|
||||
#include "lib/crypt_ops/crypto_format.h"
|
||||
#include "lib/memarea/memarea.h"
|
||||
|
||||
#include "feature/nodelist/microdesc_st.h"
|
||||
|
||||
/** List of tokens recognized in microdescriptors */
|
||||
static token_rule_t microdesc_token_table[] = {
|
||||
T1_START("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024),
|
||||
T01("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ),
|
||||
T0N("id", K_ID, GE(2), NO_OBJ ),
|
||||
T0N("a", K_A, GE(1), NO_OBJ ),
|
||||
T01("family", K_FAMILY, ARGS, NO_OBJ ),
|
||||
T01("p", K_P, CONCAT_ARGS, NO_OBJ ),
|
||||
T01("p6", K_P6, CONCAT_ARGS, NO_OBJ ),
|
||||
A01("@last-listed", A_LAST_LISTED, CONCAT_ARGS, NO_OBJ ),
|
||||
END_OF_TABLE
|
||||
};
|
||||
|
||||
/** Assuming that s starts with a microdesc, return the start of the
|
||||
* *NEXT* one. Return NULL on "not found." */
|
||||
static const char *
|
||||
find_start_of_next_microdesc(const char *s, const char *eos)
|
||||
{
|
||||
int started_with_annotations;
|
||||
s = eat_whitespace_eos(s, eos);
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
#define CHECK_LENGTH() STMT_BEGIN \
|
||||
if (s+32 > eos) \
|
||||
return NULL; \
|
||||
STMT_END
|
||||
|
||||
#define NEXT_LINE() STMT_BEGIN \
|
||||
s = memchr(s, '\n', eos-s); \
|
||||
if (!s || s+1 >= eos) \
|
||||
return NULL; \
|
||||
s++; \
|
||||
STMT_END
|
||||
|
||||
CHECK_LENGTH();
|
||||
|
||||
started_with_annotations = (*s == '@');
|
||||
|
||||
if (started_with_annotations) {
|
||||
/* Start by advancing to the first non-annotation line. */
|
||||
while (*s == '@')
|
||||
NEXT_LINE();
|
||||
}
|
||||
CHECK_LENGTH();
|
||||
|
||||
/* Now we should be pointed at an onion-key line. If we are, then skip
|
||||
* it. */
|
||||
if (!strcmpstart(s, "onion-key"))
|
||||
NEXT_LINE();
|
||||
|
||||
/* Okay, now we're pointed at the first line of the microdescriptor which is
|
||||
not an annotation or onion-key. The next line that _is_ an annotation or
|
||||
onion-key is the start of the next microdescriptor. */
|
||||
while (s+32 < eos) {
|
||||
if (*s == '@' || !strcmpstart(s, "onion-key"))
|
||||
return s;
|
||||
NEXT_LINE();
|
||||
}
|
||||
return NULL;
|
||||
|
||||
#undef CHECK_LENGTH
|
||||
#undef NEXT_LINE
|
||||
}
|
||||
|
||||
/** Parse as many microdescriptors as are found from the string starting at
|
||||
* <b>s</b> and ending at <b>eos</b>. If allow_annotations is set, read any
|
||||
* annotations we recognize and ignore ones we don't.
|
||||
*
|
||||
* If <b>saved_location</b> isn't SAVED_IN_CACHE, make a local copy of each
|
||||
* descriptor in the body field of each microdesc_t.
|
||||
*
|
||||
* Return all newly parsed microdescriptors in a newly allocated
|
||||
* smartlist_t. If <b>invalid_disgests_out</b> is provided, add a SHA256
|
||||
* microdesc digest to it for every microdesc that we found to be badly
|
||||
* formed. (This may cause duplicates) */
|
||||
smartlist_t *
|
||||
microdescs_parse_from_string(const char *s, const char *eos,
|
||||
int allow_annotations,
|
||||
saved_location_t where,
|
||||
smartlist_t *invalid_digests_out)
|
||||
{
|
||||
smartlist_t *tokens;
|
||||
smartlist_t *result;
|
||||
microdesc_t *md = NULL;
|
||||
memarea_t *area;
|
||||
const char *start = s;
|
||||
const char *start_of_next_microdesc;
|
||||
int flags = allow_annotations ? TS_ANNOTATIONS_OK : 0;
|
||||
const int copy_body = (where != SAVED_IN_CACHE);
|
||||
|
||||
directory_token_t *tok;
|
||||
|
||||
if (!eos)
|
||||
eos = s + strlen(s);
|
||||
|
||||
s = eat_whitespace_eos(s, eos);
|
||||
area = memarea_new();
|
||||
result = smartlist_new();
|
||||
tokens = smartlist_new();
|
||||
|
||||
while (s < eos) {
|
||||
int okay = 0;
|
||||
|
||||
start_of_next_microdesc = find_start_of_next_microdesc(s, eos);
|
||||
if (!start_of_next_microdesc)
|
||||
start_of_next_microdesc = eos;
|
||||
|
||||
md = tor_malloc_zero(sizeof(microdesc_t));
|
||||
{
|
||||
const char *cp = tor_memstr(s, start_of_next_microdesc-s,
|
||||
"onion-key");
|
||||
const int no_onion_key = (cp == NULL);
|
||||
if (no_onion_key) {
|
||||
cp = s; /* So that we have *some* junk to put in the body */
|
||||
}
|
||||
|
||||
md->bodylen = start_of_next_microdesc - cp;
|
||||
md->saved_location = where;
|
||||
if (copy_body)
|
||||
md->body = tor_memdup_nulterm(cp, md->bodylen);
|
||||
else
|
||||
md->body = (char*)cp;
|
||||
md->off = cp - start;
|
||||
crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256);
|
||||
if (no_onion_key) {
|
||||
log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Malformed or truncated descriptor");
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
if (tokenize_string(area, s, start_of_next_microdesc, tokens,
|
||||
microdesc_token_table, flags)) {
|
||||
log_warn(LD_DIR, "Unparseable microdescriptor");
|
||||
goto next;
|
||||
}
|
||||
|
||||
if ((tok = find_opt_by_keyword(tokens, A_LAST_LISTED))) {
|
||||
if (parse_iso_time(tok->args[0], &md->last_listed)) {
|
||||
log_warn(LD_DIR, "Bad last-listed time in microdescriptor");
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
tok = find_by_keyword(tokens, K_ONION_KEY);
|
||||
if (!crypto_pk_public_exponent_ok(tok->key)) {
|
||||
log_warn(LD_DIR,
|
||||
"Relay's onion key had invalid exponent.");
|
||||
goto next;
|
||||
}
|
||||
router_set_rsa_onion_pkey(tok->key, &md->onion_pkey,
|
||||
&md->onion_pkey_len);
|
||||
crypto_pk_free(tok->key);
|
||||
|
||||
if ((tok = find_opt_by_keyword(tokens, K_ONION_KEY_NTOR))) {
|
||||
curve25519_public_key_t k;
|
||||
tor_assert(tok->n_args >= 1);
|
||||
if (curve25519_public_from_base64(&k, tok->args[0]) < 0) {
|
||||
log_warn(LD_DIR, "Bogus ntor-onion-key in microdesc");
|
||||
goto next;
|
||||
}
|
||||
md->onion_curve25519_pkey =
|
||||
tor_memdup(&k, sizeof(curve25519_public_key_t));
|
||||
}
|
||||
|
||||
smartlist_t *id_lines = find_all_by_keyword(tokens, K_ID);
|
||||
if (id_lines) {
|
||||
SMARTLIST_FOREACH_BEGIN(id_lines, directory_token_t *, t) {
|
||||
tor_assert(t->n_args >= 2);
|
||||
if (!strcmp(t->args[0], "ed25519")) {
|
||||
if (md->ed25519_identity_pkey) {
|
||||
log_warn(LD_DIR, "Extra ed25519 key in microdesc");
|
||||
smartlist_free(id_lines);
|
||||
goto next;
|
||||
}
|
||||
ed25519_public_key_t k;
|
||||
if (ed25519_public_from_base64(&k, t->args[1])<0) {
|
||||
log_warn(LD_DIR, "Bogus ed25519 key in microdesc");
|
||||
smartlist_free(id_lines);
|
||||
goto next;
|
||||
}
|
||||
md->ed25519_identity_pkey = tor_memdup(&k, sizeof(k));
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(t);
|
||||
smartlist_free(id_lines);
|
||||
}
|
||||
|
||||
{
|
||||
smartlist_t *a_lines = find_all_by_keyword(tokens, K_A);
|
||||
if (a_lines) {
|
||||
find_single_ipv6_orport(a_lines, &md->ipv6_addr, &md->ipv6_orport);
|
||||
smartlist_free(a_lines);
|
||||
}
|
||||
}
|
||||
|
||||
if ((tok = find_opt_by_keyword(tokens, K_FAMILY))) {
|
||||
int i;
|
||||
md->family = smartlist_new();
|
||||
for (i=0;i<tok->n_args;++i) {
|
||||
if (!is_legal_nickname_or_hexdigest(tok->args[i])) {
|
||||
log_warn(LD_DIR, "Illegal nickname %s in family line",
|
||||
escaped(tok->args[i]));
|
||||
goto next;
|
||||
}
|
||||
smartlist_add_strdup(md->family, tok->args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((tok = find_opt_by_keyword(tokens, K_P))) {
|
||||
md->exit_policy = parse_short_policy(tok->args[0]);
|
||||
}
|
||||
if ((tok = find_opt_by_keyword(tokens, K_P6))) {
|
||||
md->ipv6_exit_policy = parse_short_policy(tok->args[0]);
|
||||
}
|
||||
|
||||
smartlist_add(result, md);
|
||||
okay = 1;
|
||||
|
||||
md = NULL;
|
||||
next:
|
||||
if (! okay && invalid_digests_out) {
|
||||
smartlist_add(invalid_digests_out,
|
||||
tor_memdup(md->digest, DIGEST256_LEN));
|
||||
}
|
||||
microdesc_free(md);
|
||||
md = NULL;
|
||||
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
|
||||
memarea_clear(area);
|
||||
smartlist_clear(tokens);
|
||||
s = start_of_next_microdesc;
|
||||
}
|
||||
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
|
||||
memarea_drop_all(area);
|
||||
smartlist_free(tokens);
|
||||
|
||||
return result;
|
||||
}
|
20
src/feature/dirparse/microdesc_parse.h
Normal file
20
src/feature/dirparse/microdesc_parse.h
Normal file
@ -0,0 +1,20 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 microdesc_parse.h
|
||||
* \brief Header file for microdesc_parse.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_MICRODESC_PARSE_H
|
||||
#define TOR_MICRODESC_PARSE_H
|
||||
|
||||
smartlist_t *microdescs_parse_from_string(const char *s, const char *eos,
|
||||
int allow_annotations,
|
||||
saved_location_t where,
|
||||
smartlist_t *invalid_digests_out);
|
||||
|
||||
#endif
|
1685
src/feature/dirparse/ns_parse.c
Normal file
1685
src/feature/dirparse/ns_parse.c
Normal file
File diff suppressed because it is too large
Load Diff
45
src/feature/dirparse/ns_parse.h
Normal file
45
src/feature/dirparse/ns_parse.h
Normal file
@ -0,0 +1,45 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 ns_parse.h
|
||||
* \brief Header file for ns_parse.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_NS_PARSE_H
|
||||
#define TOR_NS_PARSE_H
|
||||
|
||||
int router_get_networkstatus_v3_hashes(const char *s,
|
||||
common_digests_t *digests);
|
||||
int router_get_networkstatus_v3_signed_boundaries(const char *s,
|
||||
const char **start_out,
|
||||
const char **end_out);
|
||||
int router_get_networkstatus_v3_sha3_as_signed(uint8_t *digest_out,
|
||||
const char *s);
|
||||
int compare_vote_routerstatus_entries(const void **_a, const void **_b);
|
||||
|
||||
int networkstatus_verify_bw_weights(networkstatus_t *ns, int);
|
||||
enum networkstatus_type_t;
|
||||
networkstatus_t *networkstatus_parse_vote_from_string(const char *s,
|
||||
const char **eos_out,
|
||||
enum networkstatus_type_t ns_type);
|
||||
|
||||
#ifdef NS_PARSE_PRIVATE
|
||||
STATIC int routerstatus_parse_guardfraction(const char *guardfraction_str,
|
||||
networkstatus_t *vote,
|
||||
vote_routerstatus_t *vote_rs,
|
||||
routerstatus_t *rs);
|
||||
struct memarea_t;
|
||||
STATIC routerstatus_t *routerstatus_parse_entry_from_string(
|
||||
struct memarea_t *area,
|
||||
const char **s, smartlist_t *tokens,
|
||||
networkstatus_t *vote,
|
||||
vote_routerstatus_t *vote_rs,
|
||||
int consensus_method,
|
||||
consensus_flavor_t flav);
|
||||
#endif
|
||||
|
||||
#endif
|
@ -6,7 +6,7 @@
|
||||
* \brief Common code to parse and validate various type of descriptors.
|
||||
**/
|
||||
|
||||
#include "feature/nodelist/parsecommon.h"
|
||||
#include "feature/dirparse/parsecommon.h"
|
||||
#include "lib/log/log.h"
|
||||
#include "lib/log/util_bug.h"
|
||||
#include "lib/encoding/binascii.h"
|
||||
@ -51,7 +51,7 @@ token_clear(directory_token_t *tok)
|
||||
int
|
||||
tokenize_string(memarea_t *area,
|
||||
const char *start, const char *end, smartlist_t *out,
|
||||
token_rule_t *table, int flags)
|
||||
const token_rule_t *table, int flags)
|
||||
{
|
||||
const char **s;
|
||||
directory_token_t *tok = NULL;
|
||||
@ -257,7 +257,7 @@ token_check_object(memarea_t *area, const char *kwd,
|
||||
*/
|
||||
directory_token_t *
|
||||
get_next_token(memarea_t *area,
|
||||
const char **s, const char *eos, token_rule_t *table)
|
||||
const char **s, const char *eos, const token_rule_t *table)
|
||||
{
|
||||
/** Reject any object at least this big; it is probably an overflow, an
|
||||
* attack, a bug, or some other nonsense. */
|
@ -302,12 +302,12 @@ void token_clear(directory_token_t *tok);
|
||||
int tokenize_string(struct memarea_t *area,
|
||||
const char *start, const char *end,
|
||||
struct smartlist_t *out,
|
||||
token_rule_t *table,
|
||||
const token_rule_t *table,
|
||||
int flags);
|
||||
directory_token_t *get_next_token(struct memarea_t *area,
|
||||
const char **s,
|
||||
const char *eos,
|
||||
token_rule_t *table);
|
||||
const token_rule_t *table);
|
||||
|
||||
directory_token_t *find_by_keyword_(struct smartlist_t *s,
|
||||
directory_keyword keyword,
|
218
src/feature/dirparse/policy_parse.c
Normal file
218
src/feature/dirparse/policy_parse.c
Normal file
@ -0,0 +1,218 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 policy_parse.c
|
||||
* \brief Code to parse address policies.
|
||||
**/
|
||||
|
||||
#define EXPOSE_ROUTERDESC_TOKEN_TABLE
|
||||
|
||||
#include "core/or/or.h"
|
||||
|
||||
#include "core/or/policies.h"
|
||||
#include "feature/dirparse/parsecommon.h"
|
||||
#include "feature/dirparse/policy_parse.h"
|
||||
#include "feature/dirparse/routerparse.h"
|
||||
#include "feature/dirparse/unparseable.h"
|
||||
#include "lib/memarea/memarea.h"
|
||||
|
||||
#include "core/or/addr_policy_st.h"
|
||||
|
||||
static addr_policy_t *router_parse_addr_policy_private(directory_token_t *tok);
|
||||
|
||||
/** Parse the addr policy in the string <b>s</b> and return it. If
|
||||
* assume_action is nonnegative, then insert its action (ADDR_POLICY_ACCEPT or
|
||||
* ADDR_POLICY_REJECT) for items that specify no action.
|
||||
*
|
||||
* Returns NULL on policy errors.
|
||||
*
|
||||
* Set *<b>malformed_list</b> to true if the entire policy list should be
|
||||
* discarded. Otherwise, set it to false, and only this item should be ignored
|
||||
* on error - the rest of the policy list can continue to be processed and
|
||||
* used.
|
||||
*
|
||||
* The addr_policy_t returned by this function can have its address set to
|
||||
* AF_UNSPEC for '*'. Use policy_expand_unspec() to turn this into a pair
|
||||
* of AF_INET and AF_INET6 items.
|
||||
*/
|
||||
MOCK_IMPL(addr_policy_t *,
|
||||
router_parse_addr_policy_item_from_string,(const char *s, int assume_action,
|
||||
int *malformed_list))
|
||||
{
|
||||
directory_token_t *tok = NULL;
|
||||
const char *cp, *eos;
|
||||
/* Longest possible policy is
|
||||
* "accept6 [ffff:ffff:..255]/128:10000-65535",
|
||||
* which contains a max-length IPv6 address, plus 26 characters.
|
||||
* But note that there can be an arbitrary amount of space between the
|
||||
* accept and the address:mask/port element.
|
||||
* We don't need to multiply TOR_ADDR_BUF_LEN by 2, as there is only one
|
||||
* IPv6 address. But making the buffer shorter might cause valid long lines,
|
||||
* which parsed in previous versions, to fail to parse in new versions.
|
||||
* (These lines would have to have excessive amounts of whitespace.) */
|
||||
char line[TOR_ADDR_BUF_LEN*2 + 32];
|
||||
addr_policy_t *r;
|
||||
memarea_t *area = NULL;
|
||||
|
||||
tor_assert(malformed_list);
|
||||
*malformed_list = 0;
|
||||
|
||||
s = eat_whitespace(s);
|
||||
/* We can only do assume_action on []-quoted IPv6, as "a" (accept)
|
||||
* and ":" (port separator) are ambiguous */
|
||||
if ((*s == '*' || *s == '[' || TOR_ISDIGIT(*s)) && assume_action >= 0) {
|
||||
if (tor_snprintf(line, sizeof(line), "%s %s",
|
||||
assume_action == ADDR_POLICY_ACCEPT?"accept":"reject", s)<0) {
|
||||
log_warn(LD_DIR, "Policy %s is too long.", escaped(s));
|
||||
return NULL;
|
||||
}
|
||||
cp = line;
|
||||
tor_strlower(line);
|
||||
} else { /* assume an already well-formed address policy line */
|
||||
cp = s;
|
||||
}
|
||||
|
||||
eos = cp + strlen(cp);
|
||||
area = memarea_new();
|
||||
tok = get_next_token(area, &cp, eos, routerdesc_token_table);
|
||||
if (tok->tp == ERR_) {
|
||||
log_warn(LD_DIR, "Error reading address policy: %s", tok->error);
|
||||
goto err;
|
||||
}
|
||||
if (tok->tp != K_ACCEPT && tok->tp != K_ACCEPT6 &&
|
||||
tok->tp != K_REJECT && tok->tp != K_REJECT6) {
|
||||
log_warn(LD_DIR, "Expected 'accept' or 'reject'.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Use the extended interpretation of accept/reject *,
|
||||
* expanding it into an IPv4 wildcard and an IPv6 wildcard.
|
||||
* Also permit *4 and *6 for IPv4 and IPv6 only wildcards. */
|
||||
r = router_parse_addr_policy(tok, TAPMP_EXTENDED_STAR);
|
||||
if (!r) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Ensure that accept6/reject6 fields are followed by IPv6 addresses.
|
||||
* AF_UNSPEC addresses are only permitted on the accept/reject field type.
|
||||
* Unlike descriptors, torrcs exit policy accept/reject can be followed by
|
||||
* either an IPv4 or IPv6 address. */
|
||||
if ((tok->tp == K_ACCEPT6 || tok->tp == K_REJECT6) &&
|
||||
tor_addr_family(&r->addr) != AF_INET6) {
|
||||
/* This is a non-fatal error, just ignore this one entry. */
|
||||
*malformed_list = 0;
|
||||
log_warn(LD_DIR, "IPv4 address '%s' with accept6/reject6 field type in "
|
||||
"exit policy. Ignoring, but continuing to parse rules. (Use "
|
||||
"accept/reject with IPv4 addresses.)",
|
||||
tok->n_args == 1 ? tok->args[0] : "");
|
||||
addr_policy_free(r);
|
||||
r = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
goto done;
|
||||
err:
|
||||
*malformed_list = 1;
|
||||
r = NULL;
|
||||
done:
|
||||
token_clear(tok);
|
||||
if (area) {
|
||||
DUMP_AREA(area, "policy item");
|
||||
memarea_drop_all(area);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Given a K_ACCEPT[6] or K_REJECT[6] token and a router, create and return
|
||||
* a new exit_policy_t corresponding to the token. If TAPMP_EXTENDED_STAR
|
||||
* is set in fmt_flags, K_ACCEPT6 and K_REJECT6 tokens followed by *
|
||||
* expand to IPv6-only policies, otherwise they expand to IPv4 and IPv6
|
||||
* policies */
|
||||
addr_policy_t *
|
||||
router_parse_addr_policy(directory_token_t *tok, unsigned fmt_flags)
|
||||
{
|
||||
addr_policy_t newe;
|
||||
char *arg;
|
||||
|
||||
tor_assert(tok->tp == K_REJECT || tok->tp == K_REJECT6 ||
|
||||
tok->tp == K_ACCEPT || tok->tp == K_ACCEPT6);
|
||||
|
||||
if (tok->n_args != 1)
|
||||
return NULL;
|
||||
arg = tok->args[0];
|
||||
|
||||
if (!strcmpstart(arg,"private"))
|
||||
return router_parse_addr_policy_private(tok);
|
||||
|
||||
memset(&newe, 0, sizeof(newe));
|
||||
|
||||
if (tok->tp == K_REJECT || tok->tp == K_REJECT6)
|
||||
newe.policy_type = ADDR_POLICY_REJECT;
|
||||
else
|
||||
newe.policy_type = ADDR_POLICY_ACCEPT;
|
||||
|
||||
/* accept6/reject6 * produces an IPv6 wildcard address only.
|
||||
* (accept/reject * produces rules for IPv4 and IPv6 wildcard addresses.) */
|
||||
if ((fmt_flags & TAPMP_EXTENDED_STAR)
|
||||
&& (tok->tp == K_ACCEPT6 || tok->tp == K_REJECT6)) {
|
||||
fmt_flags |= TAPMP_STAR_IPV6_ONLY;
|
||||
}
|
||||
|
||||
if (tor_addr_parse_mask_ports(arg, fmt_flags, &newe.addr, &newe.maskbits,
|
||||
&newe.prt_min, &newe.prt_max) < 0) {
|
||||
log_warn(LD_DIR,"Couldn't parse line %s. Dropping", escaped(arg));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return addr_policy_get_canonical_entry(&newe);
|
||||
}
|
||||
|
||||
/** Parse an exit policy line of the format "accept[6]/reject[6] private:...".
|
||||
* This didn't exist until Tor 0.1.1.15, so nobody should generate it in
|
||||
* router descriptors until earlier versions are obsolete.
|
||||
*
|
||||
* accept/reject and accept6/reject6 private all produce rules for both
|
||||
* IPv4 and IPv6 addresses.
|
||||
*/
|
||||
static addr_policy_t *
|
||||
router_parse_addr_policy_private(directory_token_t *tok)
|
||||
{
|
||||
const char *arg;
|
||||
uint16_t port_min, port_max;
|
||||
addr_policy_t result;
|
||||
|
||||
arg = tok->args[0];
|
||||
if (strcmpstart(arg, "private"))
|
||||
return NULL;
|
||||
|
||||
arg += strlen("private");
|
||||
arg = (char*) eat_whitespace(arg);
|
||||
if (!arg || *arg != ':')
|
||||
return NULL;
|
||||
|
||||
if (parse_port_range(arg+1, &port_min, &port_max)<0)
|
||||
return NULL;
|
||||
|
||||
memset(&result, 0, sizeof(result));
|
||||
if (tok->tp == K_REJECT || tok->tp == K_REJECT6)
|
||||
result.policy_type = ADDR_POLICY_REJECT;
|
||||
else
|
||||
result.policy_type = ADDR_POLICY_ACCEPT;
|
||||
result.is_private = 1;
|
||||
result.prt_min = port_min;
|
||||
result.prt_max = port_max;
|
||||
|
||||
if (tok->tp == K_ACCEPT6 || tok->tp == K_REJECT6) {
|
||||
log_warn(LD_GENERAL,
|
||||
"'%s' expands into rules which apply to all private IPv4 and "
|
||||
"IPv6 addresses. (Use accept/reject private:* for IPv4 and "
|
||||
"IPv6.)", tok->n_args == 1 ? tok->args[0] : "");
|
||||
}
|
||||
|
||||
return addr_policy_get_canonical_entry(&result);
|
||||
}
|
||||
|
25
src/feature/dirparse/policy_parse.h
Normal file
25
src/feature/dirparse/policy_parse.h
Normal file
@ -0,0 +1,25 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 policy_parse.h
|
||||
* \brief Header file for policy_parse.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_POLICY_PARSE_H
|
||||
#define TOR_POLICY_PARSE_H
|
||||
|
||||
#include "lib/testsupport/testsupport.h"
|
||||
|
||||
struct directory_token_t;
|
||||
|
||||
MOCK_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string,
|
||||
(const char *s, int assume_action, int *malformed_list));
|
||||
|
||||
addr_policy_t *router_parse_addr_policy(struct directory_token_t *tok,
|
||||
unsigned fmt_flags);
|
||||
|
||||
#endif /* !defined(TOR_POLICY_PARSE_H) */
|
1242
src/feature/dirparse/routerparse.c
Normal file
1242
src/feature/dirparse/routerparse.c
Normal file
File diff suppressed because it is too large
Load Diff
49
src/feature/dirparse/routerparse.h
Normal file
49
src/feature/dirparse/routerparse.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 routerparse.h
|
||||
* \brief Header file for routerparse.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_ROUTERPARSE_H
|
||||
#define TOR_ROUTERPARSE_H
|
||||
|
||||
int router_get_router_hash(const char *s, size_t s_len, char *digest);
|
||||
int router_get_extrainfo_hash(const char *s, size_t s_len, char *digest);
|
||||
|
||||
int router_parse_list_from_string(const char **s, const char *eos,
|
||||
smartlist_t *dest,
|
||||
saved_location_t saved_location,
|
||||
int is_extrainfo,
|
||||
int allow_annotations,
|
||||
const char *prepend_annotations,
|
||||
smartlist_t *invalid_digests_out);
|
||||
|
||||
routerinfo_t *router_parse_entry_from_string(const char *s, const char *end,
|
||||
int cache_copy,
|
||||
int allow_annotations,
|
||||
const char *prepend_annotations,
|
||||
int *can_dl_again_out);
|
||||
struct digest_ri_map_t;
|
||||
extrainfo_t *extrainfo_parse_entry_from_string(const char *s, const char *end,
|
||||
int cache_copy, struct digest_ri_map_t *routermap,
|
||||
int *can_dl_again_out);
|
||||
|
||||
int find_single_ipv6_orport(const smartlist_t *list,
|
||||
tor_addr_t *addr_out,
|
||||
uint16_t *port_out);
|
||||
|
||||
void routerparse_init(void);
|
||||
void routerparse_free_all(void);
|
||||
|
||||
#ifdef EXPOSE_ROUTERDESC_TOKEN_TABLE
|
||||
extern const struct token_rule_t routerdesc_token_table[];
|
||||
#endif
|
||||
|
||||
#define ED_DESC_SIGNATURE_PREFIX "Tor router descriptor signature v1"
|
||||
|
||||
#endif /* !defined(TOR_ROUTERPARSE_H) */
|
185
src/feature/dirparse/sigcommon.c
Normal file
185
src/feature/dirparse/sigcommon.c
Normal file
@ -0,0 +1,185 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 sigcommon.c
|
||||
* \brief Shared hashing, signing, and signature-checking code for directory
|
||||
* objects.
|
||||
**/
|
||||
|
||||
#define SIGCOMMON_PRIVATE
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "feature/dirparse/parsecommon.h"
|
||||
#include "feature/dirparse/sigcommon.h"
|
||||
|
||||
/** Helper function for <b>router_get_hash_impl</b>: given <b>s</b>,
|
||||
* <b>s_len</b>, <b>start_str</b>, <b>end_str</b>, and <b>end_c</b> with the
|
||||
* same semantics as in that function, set *<b>start_out</b> (inclusive) and
|
||||
* *<b>end_out</b> (exclusive) to the boundaries of the string to be hashed.
|
||||
*
|
||||
* Return 0 on success and -1 on failure.
|
||||
*/
|
||||
int
|
||||
router_get_hash_impl_helper(const char *s, size_t s_len,
|
||||
const char *start_str,
|
||||
const char *end_str, char end_c,
|
||||
int log_severity,
|
||||
const char **start_out, const char **end_out)
|
||||
{
|
||||
const char *start, *end;
|
||||
start = tor_memstr(s, s_len, start_str);
|
||||
if (!start) {
|
||||
log_fn(log_severity,LD_DIR,
|
||||
"couldn't find start of hashed material \"%s\"",start_str);
|
||||
return -1;
|
||||
}
|
||||
if (start != s && *(start-1) != '\n') {
|
||||
log_fn(log_severity,LD_DIR,
|
||||
"first occurrence of \"%s\" is not at the start of a line",
|
||||
start_str);
|
||||
return -1;
|
||||
}
|
||||
end = tor_memstr(start+strlen(start_str),
|
||||
s_len - (start-s) - strlen(start_str), end_str);
|
||||
if (!end) {
|
||||
log_fn(log_severity,LD_DIR,
|
||||
"couldn't find end of hashed material \"%s\"",end_str);
|
||||
return -1;
|
||||
}
|
||||
end = memchr(end+strlen(end_str), end_c, s_len - (end-s) - strlen(end_str));
|
||||
if (!end) {
|
||||
log_fn(log_severity,LD_DIR,
|
||||
"couldn't find EOL");
|
||||
return -1;
|
||||
}
|
||||
++end;
|
||||
|
||||
*start_out = start;
|
||||
*end_out = end;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Compute the digest of the substring of <b>s</b> taken from the first
|
||||
* occurrence of <b>start_str</b> through the first instance of c after the
|
||||
* first subsequent occurrence of <b>end_str</b>; store the 20-byte or 32-byte
|
||||
* result in <b>digest</b>; return 0 on success.
|
||||
*
|
||||
* If no such substring exists, return -1.
|
||||
*/
|
||||
int
|
||||
router_get_hash_impl(const char *s, size_t s_len, char *digest,
|
||||
const char *start_str,
|
||||
const char *end_str, char end_c,
|
||||
digest_algorithm_t alg)
|
||||
{
|
||||
const char *start=NULL, *end=NULL;
|
||||
if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,LOG_WARN,
|
||||
&start,&end)<0)
|
||||
return -1;
|
||||
|
||||
return router_compute_hash_final(digest, start, end-start, alg);
|
||||
}
|
||||
|
||||
/** Compute the digest of the <b>len</b>-byte directory object at
|
||||
* <b>start</b>, using <b>alg</b>. Store the result in <b>digest</b>, which
|
||||
* must be long enough to hold it. */
|
||||
MOCK_IMPL(STATIC int,
|
||||
router_compute_hash_final,(char *digest,
|
||||
const char *start, size_t len,
|
||||
digest_algorithm_t alg))
|
||||
{
|
||||
if (alg == DIGEST_SHA1) {
|
||||
if (crypto_digest(digest, start, len) < 0) {
|
||||
log_warn(LD_BUG,"couldn't compute digest");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (crypto_digest256(digest, start, len, alg) < 0) {
|
||||
log_warn(LD_BUG,"couldn't compute digest");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** As router_get_hash_impl, but compute all hashes. */
|
||||
int
|
||||
router_get_hashes_impl(const char *s, size_t s_len, common_digests_t *digests,
|
||||
const char *start_str,
|
||||
const char *end_str, char end_c)
|
||||
{
|
||||
const char *start=NULL, *end=NULL;
|
||||
if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,LOG_WARN,
|
||||
&start,&end)<0)
|
||||
return -1;
|
||||
|
||||
if (crypto_common_digests(digests, start, end-start)) {
|
||||
log_warn(LD_BUG,"couldn't compute digests");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MOCK_IMPL(STATIC int,
|
||||
signed_digest_equals, (const uint8_t *d1, const uint8_t *d2, size_t len))
|
||||
{
|
||||
return tor_memeq(d1, d2, len);
|
||||
}
|
||||
|
||||
/** Check whether the object body of the token in <b>tok</b> has a good
|
||||
* signature for <b>digest</b> using key <b>pkey</b>.
|
||||
* If <b>CST_NO_CHECK_OBJTYPE</b> is set, do not check
|
||||
* the object type of the signature object. Use <b>doctype</b> as the type of
|
||||
* the document when generating log messages. Return 0 on success, negative
|
||||
* on failure.
|
||||
*/
|
||||
int
|
||||
check_signature_token(const char *digest,
|
||||
ssize_t digest_len,
|
||||
directory_token_t *tok,
|
||||
crypto_pk_t *pkey,
|
||||
int flags,
|
||||
const char *doctype)
|
||||
{
|
||||
char *signed_digest;
|
||||
size_t keysize;
|
||||
const int check_objtype = ! (flags & CST_NO_CHECK_OBJTYPE);
|
||||
|
||||
tor_assert(pkey);
|
||||
tor_assert(tok);
|
||||
tor_assert(digest);
|
||||
tor_assert(doctype);
|
||||
|
||||
if (check_objtype) {
|
||||
if (strcmp(tok->object_type, "SIGNATURE")) {
|
||||
log_warn(LD_DIR, "Bad object type on %s signature", doctype);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
keysize = crypto_pk_keysize(pkey);
|
||||
signed_digest = tor_malloc(keysize);
|
||||
if (crypto_pk_public_checksig(pkey, signed_digest, keysize,
|
||||
tok->object_body, tok->object_size)
|
||||
< digest_len) {
|
||||
log_warn(LD_DIR, "Error reading %s: invalid signature.", doctype);
|
||||
tor_free(signed_digest);
|
||||
return -1;
|
||||
}
|
||||
// log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
|
||||
// hex_str(signed_digest,4));
|
||||
if (! signed_digest_equals((const uint8_t *)digest,
|
||||
(const uint8_t *)signed_digest, digest_len)) {
|
||||
log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype);
|
||||
tor_free(signed_digest);
|
||||
return -1;
|
||||
}
|
||||
tor_free(signed_digest);
|
||||
return 0;
|
||||
}
|
48
src/feature/dirparse/sigcommon.h
Normal file
48
src/feature/dirparse/sigcommon.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 sigcommon.h
|
||||
* \brief Header file for sigcommon.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_SIGCOMMON_H
|
||||
#define TOR_SIGCOMMON_H
|
||||
|
||||
/* TODO: Rename all of these functions */
|
||||
int router_get_hash_impl(const char *s, size_t s_len, char *digest,
|
||||
const char *start_str, const char *end_str,
|
||||
char end_char,
|
||||
digest_algorithm_t alg);
|
||||
|
||||
#define CST_NO_CHECK_OBJTYPE (1<<0)
|
||||
struct directory_token_t;
|
||||
int check_signature_token(const char *digest,
|
||||
ssize_t digest_len,
|
||||
struct directory_token_t *tok,
|
||||
crypto_pk_t *pkey,
|
||||
int flags,
|
||||
const char *doctype);
|
||||
|
||||
int router_get_hash_impl_helper(const char *s, size_t s_len,
|
||||
const char *start_str,
|
||||
const char *end_str, char end_c,
|
||||
int log_severity,
|
||||
const char **start_out, const char **end_out);
|
||||
int router_get_hashes_impl(const char *s, size_t s_len,
|
||||
common_digests_t *digests,
|
||||
const char *start_str, const char *end_str,
|
||||
char end_char);
|
||||
|
||||
#ifdef SIGCOMMON_PRIVATE
|
||||
MOCK_DECL(STATIC int, signed_digest_equals,
|
||||
(const uint8_t *d1, const uint8_t *d2, size_t len));
|
||||
MOCK_DECL(STATIC int, router_compute_hash_final,(char *digest,
|
||||
const char *start, size_t len,
|
||||
digest_algorithm_t alg));
|
||||
#endif
|
||||
|
||||
#endif /* !defined(TOR_SIGCOMMON_H) */
|
98
src/feature/dirparse/signing.c
Normal file
98
src/feature/dirparse/signing.c
Normal file
@ -0,0 +1,98 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 signing.c
|
||||
* \brief Code to sign directory objects.
|
||||
**/
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "feature/dirparse/signing.h"
|
||||
|
||||
/** Helper: used to generate signatures for routers, directories and
|
||||
* network-status objects. Given a <b>digest_len</b>-byte digest in
|
||||
* <b>digest</b> and a secret <b>private_key</b>, generate an PKCS1-padded
|
||||
* signature, BASE64-encode it, surround it with -----BEGIN/END----- pairs,
|
||||
* and return the new signature on success or NULL on failure.
|
||||
*/
|
||||
char *
|
||||
router_get_dirobj_signature(const char *digest,
|
||||
size_t digest_len,
|
||||
const crypto_pk_t *private_key)
|
||||
{
|
||||
char *signature;
|
||||
size_t i, keysize;
|
||||
int siglen;
|
||||
char *buf = NULL;
|
||||
size_t buf_len;
|
||||
/* overestimate of BEGIN/END lines total len. */
|
||||
#define BEGIN_END_OVERHEAD_LEN 64
|
||||
|
||||
keysize = crypto_pk_keysize(private_key);
|
||||
signature = tor_malloc(keysize);
|
||||
siglen = crypto_pk_private_sign(private_key, signature, keysize,
|
||||
digest, digest_len);
|
||||
if (siglen < 0) {
|
||||
log_warn(LD_BUG,"Couldn't sign digest.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* The *2 here is a ridiculous overestimate of base-64 overhead. */
|
||||
buf_len = (siglen * 2) + BEGIN_END_OVERHEAD_LEN;
|
||||
buf = tor_malloc(buf_len);
|
||||
|
||||
if (strlcpy(buf, "-----BEGIN SIGNATURE-----\n", buf_len) >= buf_len)
|
||||
goto truncated;
|
||||
|
||||
i = strlen(buf);
|
||||
if (base64_encode(buf+i, buf_len-i, signature, siglen,
|
||||
BASE64_ENCODE_MULTILINE) < 0) {
|
||||
log_warn(LD_BUG,"couldn't base64-encode signature");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (strlcat(buf, "-----END SIGNATURE-----\n", buf_len) >= buf_len)
|
||||
goto truncated;
|
||||
|
||||
tor_free(signature);
|
||||
return buf;
|
||||
|
||||
truncated:
|
||||
log_warn(LD_BUG,"tried to exceed string length.");
|
||||
err:
|
||||
tor_free(signature);
|
||||
tor_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Helper: used to generate signatures for routers, directories and
|
||||
* network-status objects. Given a digest in <b>digest</b> and a secret
|
||||
* <b>private_key</b>, generate a PKCS1-padded signature, BASE64-encode it,
|
||||
* surround it with -----BEGIN/END----- pairs, and write it to the
|
||||
* <b>buf_len</b>-byte buffer at <b>buf</b>. Return 0 on success, -1 on
|
||||
* failure.
|
||||
*/
|
||||
int
|
||||
router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest,
|
||||
size_t digest_len, crypto_pk_t *private_key)
|
||||
{
|
||||
size_t sig_len, s_len;
|
||||
char *sig = router_get_dirobj_signature(digest, digest_len, private_key);
|
||||
if (!sig) {
|
||||
log_warn(LD_BUG, "No signature generated");
|
||||
return -1;
|
||||
}
|
||||
sig_len = strlen(sig);
|
||||
s_len = strlen(buf);
|
||||
if (sig_len + s_len + 1 > buf_len) {
|
||||
log_warn(LD_BUG, "Not enough room for signature");
|
||||
tor_free(sig);
|
||||
return -1;
|
||||
}
|
||||
memcpy(buf+s_len, sig, sig_len+1);
|
||||
tor_free(sig);
|
||||
return 0;
|
||||
}
|
23
src/feature/dirparse/signing.h
Normal file
23
src/feature/dirparse/signing.h
Normal file
@ -0,0 +1,23 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 signing.h
|
||||
* \brief Header file for signing.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_SIGNING_H
|
||||
#define TOR_SIGNING_H
|
||||
|
||||
#define DIROBJ_MAX_SIG_LEN 256
|
||||
char *router_get_dirobj_signature(const char *digest,
|
||||
size_t digest_len,
|
||||
const crypto_pk_t *private_key);
|
||||
int router_append_dirobj_signature(char *buf, size_t buf_len,
|
||||
const char *digest,
|
||||
size_t digest_len,
|
||||
crypto_pk_t *private_key);
|
||||
#endif
|
591
src/feature/dirparse/unparseable.c
Normal file
591
src/feature/dirparse/unparseable.c
Normal file
@ -0,0 +1,591 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 */
|
||||
|
||||
#define UNPARSEABLE_PRIVATE
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "app/config/config.h"
|
||||
#include "feature/dirparse/unparseable.h"
|
||||
#include "lib/sandbox/sandbox.h"
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
/* Dump mechanism for unparseable descriptors */
|
||||
|
||||
/** List of dumped descriptors for FIFO cleanup purposes */
|
||||
STATIC smartlist_t *descs_dumped = NULL;
|
||||
/** Total size of dumped descriptors for FIFO cleanup */
|
||||
STATIC uint64_t len_descs_dumped = 0;
|
||||
/** Directory to stash dumps in */
|
||||
static int have_dump_desc_dir = 0;
|
||||
static int problem_with_dump_desc_dir = 0;
|
||||
|
||||
#define DESC_DUMP_DATADIR_SUBDIR "unparseable-descs"
|
||||
#define DESC_DUMP_BASE_FILENAME "unparseable-desc"
|
||||
|
||||
/** Find the dump directory and check if we'll be able to create it */
|
||||
void
|
||||
dump_desc_init(void)
|
||||
{
|
||||
char *dump_desc_dir;
|
||||
|
||||
dump_desc_dir = get_datadir_fname(DESC_DUMP_DATADIR_SUBDIR);
|
||||
|
||||
/*
|
||||
* We just check for it, don't create it at this point; we'll
|
||||
* create it when we need it if it isn't already there.
|
||||
*/
|
||||
if (check_private_dir(dump_desc_dir, CPD_CHECK, get_options()->User) < 0) {
|
||||
/* Error, log and flag it as having a problem */
|
||||
log_notice(LD_DIR,
|
||||
"Doesn't look like we'll be able to create descriptor dump "
|
||||
"directory %s; dumps will be disabled.",
|
||||
dump_desc_dir);
|
||||
problem_with_dump_desc_dir = 1;
|
||||
tor_free(dump_desc_dir);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if it exists */
|
||||
switch (file_status(dump_desc_dir)) {
|
||||
case FN_DIR:
|
||||
/* We already have a directory */
|
||||
have_dump_desc_dir = 1;
|
||||
break;
|
||||
case FN_NOENT:
|
||||
/* Nothing, we'll need to create it later */
|
||||
have_dump_desc_dir = 0;
|
||||
break;
|
||||
case FN_ERROR:
|
||||
/* Log and flag having a problem */
|
||||
log_notice(LD_DIR,
|
||||
"Couldn't check whether descriptor dump directory %s already"
|
||||
" exists: %s",
|
||||
dump_desc_dir, strerror(errno));
|
||||
problem_with_dump_desc_dir = 1;
|
||||
break;
|
||||
case FN_FILE:
|
||||
case FN_EMPTY:
|
||||
default:
|
||||
/* Something else was here! */
|
||||
log_notice(LD_DIR,
|
||||
"Descriptor dump directory %s already exists and isn't a "
|
||||
"directory",
|
||||
dump_desc_dir);
|
||||
problem_with_dump_desc_dir = 1;
|
||||
}
|
||||
|
||||
if (have_dump_desc_dir && !problem_with_dump_desc_dir) {
|
||||
dump_desc_populate_fifo_from_directory(dump_desc_dir);
|
||||
}
|
||||
|
||||
tor_free(dump_desc_dir);
|
||||
}
|
||||
|
||||
/** Create the dump directory if needed and possible */
|
||||
static void
|
||||
dump_desc_create_dir(void)
|
||||
{
|
||||
char *dump_desc_dir;
|
||||
|
||||
/* If the problem flag is set, skip it */
|
||||
if (problem_with_dump_desc_dir) return;
|
||||
|
||||
/* Do we need it? */
|
||||
if (!have_dump_desc_dir) {
|
||||
dump_desc_dir = get_datadir_fname(DESC_DUMP_DATADIR_SUBDIR);
|
||||
|
||||
if (check_private_dir(dump_desc_dir, CPD_CREATE,
|
||||
get_options()->User) < 0) {
|
||||
log_notice(LD_DIR,
|
||||
"Failed to create descriptor dump directory %s",
|
||||
dump_desc_dir);
|
||||
problem_with_dump_desc_dir = 1;
|
||||
}
|
||||
|
||||
/* Okay, we created it */
|
||||
have_dump_desc_dir = 1;
|
||||
|
||||
tor_free(dump_desc_dir);
|
||||
}
|
||||
}
|
||||
|
||||
/** Dump desc FIFO/cleanup; take ownership of the given filename, add it to
|
||||
* the FIFO, and clean up the oldest entries to the extent they exceed the
|
||||
* configured cap. If any old entries with a matching hash existed, they
|
||||
* just got overwritten right before this was called and we should adjust
|
||||
* the total size counter without deleting them.
|
||||
*/
|
||||
static void
|
||||
dump_desc_fifo_add_and_clean(char *filename, const uint8_t *digest_sha256,
|
||||
size_t len)
|
||||
{
|
||||
dumped_desc_t *ent = NULL, *tmp;
|
||||
uint64_t max_len;
|
||||
|
||||
tor_assert(filename != NULL);
|
||||
tor_assert(digest_sha256 != NULL);
|
||||
|
||||
if (descs_dumped == NULL) {
|
||||
/* We better have no length, then */
|
||||
tor_assert(len_descs_dumped == 0);
|
||||
/* Make a smartlist */
|
||||
descs_dumped = smartlist_new();
|
||||
}
|
||||
|
||||
/* Make a new entry to put this one in */
|
||||
ent = tor_malloc_zero(sizeof(*ent));
|
||||
ent->filename = filename;
|
||||
ent->len = len;
|
||||
ent->when = time(NULL);
|
||||
memcpy(ent->digest_sha256, digest_sha256, DIGEST256_LEN);
|
||||
|
||||
/* Do we need to do some cleanup? */
|
||||
max_len = get_options()->MaxUnparseableDescSizeToLog;
|
||||
/* Iterate over the list until we've freed enough space */
|
||||
while (len > max_len - len_descs_dumped &&
|
||||
smartlist_len(descs_dumped) > 0) {
|
||||
/* Get the oldest thing on the list */
|
||||
tmp = (dumped_desc_t *)(smartlist_get(descs_dumped, 0));
|
||||
|
||||
/*
|
||||
* Check if it matches the filename we just added, so we don't delete
|
||||
* something we just emitted if we get repeated identical descriptors.
|
||||
*/
|
||||
if (strcmp(tmp->filename, filename) != 0) {
|
||||
/* Delete it and adjust the length counter */
|
||||
tor_unlink(tmp->filename);
|
||||
tor_assert(len_descs_dumped >= tmp->len);
|
||||
len_descs_dumped -= tmp->len;
|
||||
log_info(LD_DIR,
|
||||
"Deleting old unparseable descriptor dump %s due to "
|
||||
"space limits",
|
||||
tmp->filename);
|
||||
} else {
|
||||
/*
|
||||
* Don't delete, but do adjust the counter since we will bump it
|
||||
* later
|
||||
*/
|
||||
tor_assert(len_descs_dumped >= tmp->len);
|
||||
len_descs_dumped -= tmp->len;
|
||||
log_info(LD_DIR,
|
||||
"Replacing old descriptor dump %s with new identical one",
|
||||
tmp->filename);
|
||||
}
|
||||
|
||||
/* Free it and remove it from the list */
|
||||
smartlist_del_keeporder(descs_dumped, 0);
|
||||
tor_free(tmp->filename);
|
||||
tor_free(tmp);
|
||||
}
|
||||
|
||||
/* Append our entry to the end of the list and bump the counter */
|
||||
smartlist_add(descs_dumped, ent);
|
||||
len_descs_dumped += len;
|
||||
}
|
||||
|
||||
/** Check if we already have a descriptor for this hash and move it to the
|
||||
* head of the queue if so. Return 1 if one existed and 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
dump_desc_fifo_bump_hash(const uint8_t *digest_sha256)
|
||||
{
|
||||
dumped_desc_t *match = NULL;
|
||||
|
||||
tor_assert(digest_sha256);
|
||||
|
||||
if (descs_dumped) {
|
||||
/* Find a match if one exists */
|
||||
SMARTLIST_FOREACH_BEGIN(descs_dumped, dumped_desc_t *, ent) {
|
||||
if (ent &&
|
||||
tor_memeq(ent->digest_sha256, digest_sha256, DIGEST256_LEN)) {
|
||||
/*
|
||||
* Save a pointer to the match and remove it from its current
|
||||
* position.
|
||||
*/
|
||||
match = ent;
|
||||
SMARTLIST_DEL_CURRENT_KEEPORDER(descs_dumped, ent);
|
||||
break;
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(ent);
|
||||
|
||||
if (match) {
|
||||
/* Update the timestamp */
|
||||
match->when = time(NULL);
|
||||
/* Add it back at the end of the list */
|
||||
smartlist_add(descs_dumped, match);
|
||||
|
||||
/* Indicate we found one */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Clean up on exit; just memory, leave the dumps behind
|
||||
*/
|
||||
void
|
||||
dump_desc_fifo_cleanup(void)
|
||||
{
|
||||
if (descs_dumped) {
|
||||
/* Free each descriptor */
|
||||
SMARTLIST_FOREACH_BEGIN(descs_dumped, dumped_desc_t *, ent) {
|
||||
tor_assert(ent);
|
||||
tor_free(ent->filename);
|
||||
tor_free(ent);
|
||||
} SMARTLIST_FOREACH_END(ent);
|
||||
/* Free the list */
|
||||
smartlist_free(descs_dumped);
|
||||
descs_dumped = NULL;
|
||||
len_descs_dumped = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle one file for dump_desc_populate_fifo_from_directory(); make sure
|
||||
* the filename is sensibly formed and matches the file content, and either
|
||||
* return a dumped_desc_t for it or remove the file and return NULL.
|
||||
*/
|
||||
MOCK_IMPL(STATIC dumped_desc_t *,
|
||||
dump_desc_populate_one_file, (const char *dirname, const char *f))
|
||||
{
|
||||
dumped_desc_t *ent = NULL;
|
||||
char *path = NULL, *desc = NULL;
|
||||
const char *digest_str;
|
||||
char digest[DIGEST256_LEN], content_digest[DIGEST256_LEN];
|
||||
/* Expected prefix before digest in filenames */
|
||||
const char *f_pfx = DESC_DUMP_BASE_FILENAME ".";
|
||||
/*
|
||||
* Stat while reading; this is important in case the file
|
||||
* contains a NUL character.
|
||||
*/
|
||||
struct stat st;
|
||||
|
||||
/* Sanity-check args */
|
||||
tor_assert(dirname != NULL);
|
||||
tor_assert(f != NULL);
|
||||
|
||||
/* Form the full path */
|
||||
tor_asprintf(&path, "%s" PATH_SEPARATOR "%s", dirname, f);
|
||||
|
||||
/* Check that f has the form DESC_DUMP_BASE_FILENAME.<digest256> */
|
||||
|
||||
if (!strcmpstart(f, f_pfx)) {
|
||||
/* It matches the form, but is the digest parseable as such? */
|
||||
digest_str = f + strlen(f_pfx);
|
||||
if (base16_decode(digest, DIGEST256_LEN,
|
||||
digest_str, strlen(digest_str)) != DIGEST256_LEN) {
|
||||
/* We failed to decode it */
|
||||
digest_str = NULL;
|
||||
}
|
||||
} else {
|
||||
/* No match */
|
||||
digest_str = NULL;
|
||||
}
|
||||
|
||||
if (!digest_str) {
|
||||
/* We couldn't get a sensible digest */
|
||||
log_notice(LD_DIR,
|
||||
"Removing unrecognized filename %s from unparseable "
|
||||
"descriptors directory", f);
|
||||
tor_unlink(path);
|
||||
/* We're done */
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* The filename has the form DESC_DUMP_BASE_FILENAME "." <digest256> and
|
||||
* we've decoded the digest. Next, check that we can read it and the
|
||||
* content matches this digest. We are relying on the fact that if the
|
||||
* file contains a '\0', read_file_to_str() will allocate space for and
|
||||
* read the entire file and return the correct size in st.
|
||||
*/
|
||||
desc = read_file_to_str(path, RFTS_IGNORE_MISSING|RFTS_BIN, &st);
|
||||
if (!desc) {
|
||||
/* We couldn't read it */
|
||||
log_notice(LD_DIR,
|
||||
"Failed to read %s from unparseable descriptors directory; "
|
||||
"attempting to remove it.", f);
|
||||
tor_unlink(path);
|
||||
/* We're done */
|
||||
goto done;
|
||||
}
|
||||
|
||||
#if SIZE_MAX > UINT64_MAX
|
||||
if (BUG((uint64_t)st.st_size > (uint64_t)SIZE_MAX)) {
|
||||
/* LCOV_EXCL_START
|
||||
* Should be impossible since RFTS above should have failed to read the
|
||||
* huge file into RAM. */
|
||||
goto done;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
#endif /* SIZE_MAX > UINT64_MAX */
|
||||
if (BUG(st.st_size < 0)) {
|
||||
/* LCOV_EXCL_START
|
||||
* Should be impossible, since the OS isn't supposed to be b0rken. */
|
||||
goto done;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
/* (Now we can be sure that st.st_size is safe to cast to a size_t.) */
|
||||
|
||||
/*
|
||||
* We got one; now compute its digest and check that it matches the
|
||||
* filename.
|
||||
*/
|
||||
if (crypto_digest256((char *)content_digest, desc, (size_t) st.st_size,
|
||||
DIGEST_SHA256) < 0) {
|
||||
/* Weird, but okay */
|
||||
log_info(LD_DIR,
|
||||
"Unable to hash content of %s from unparseable descriptors "
|
||||
"directory", f);
|
||||
tor_unlink(path);
|
||||
/* We're done */
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Compare the digests */
|
||||
if (tor_memneq(digest, content_digest, DIGEST256_LEN)) {
|
||||
/* No match */
|
||||
log_info(LD_DIR,
|
||||
"Hash of %s from unparseable descriptors directory didn't "
|
||||
"match its filename; removing it", f);
|
||||
tor_unlink(path);
|
||||
/* We're done */
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Okay, it's a match, we should prepare ent */
|
||||
ent = tor_malloc_zero(sizeof(dumped_desc_t));
|
||||
ent->filename = path;
|
||||
memcpy(ent->digest_sha256, digest, DIGEST256_LEN);
|
||||
ent->len = (size_t) st.st_size;
|
||||
ent->when = st.st_mtime;
|
||||
/* Null out path so we don't free it out from under ent */
|
||||
path = NULL;
|
||||
|
||||
done:
|
||||
/* Free allocations if we had them */
|
||||
tor_free(desc);
|
||||
tor_free(path);
|
||||
|
||||
return ent;
|
||||
}
|
||||
|
||||
/** Sort helper for dump_desc_populate_fifo_from_directory(); compares
|
||||
* the when field of dumped_desc_ts in a smartlist to put the FIFO in
|
||||
* the correct order after reconstructing it from the directory.
|
||||
*/
|
||||
static int
|
||||
dump_desc_compare_fifo_entries(const void **a_v, const void **b_v)
|
||||
{
|
||||
const dumped_desc_t **a = (const dumped_desc_t **)a_v;
|
||||
const dumped_desc_t **b = (const dumped_desc_t **)b_v;
|
||||
|
||||
if ((a != NULL) && (*a != NULL)) {
|
||||
if ((b != NULL) && (*b != NULL)) {
|
||||
/* We have sensible dumped_desc_ts to compare */
|
||||
if ((*a)->when < (*b)->when) {
|
||||
return -1;
|
||||
} else if ((*a)->when == (*b)->when) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* We shouldn't see this, but what the hell, NULLs precede everythin
|
||||
* else
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Scan the contents of the directory, and update FIFO/counters; this will
|
||||
* consistency-check descriptor dump filenames against hashes of descriptor
|
||||
* dump file content, and remove any inconsistent/unreadable dumps, and then
|
||||
* reconstruct the dump FIFO as closely as possible for the last time the
|
||||
* tor process shut down. If a previous dump was repeated more than once and
|
||||
* moved ahead in the FIFO, the mtime will not have been updated and the
|
||||
* reconstructed order will be wrong, but will always be a permutation of
|
||||
* the original.
|
||||
*/
|
||||
STATIC void
|
||||
dump_desc_populate_fifo_from_directory(const char *dirname)
|
||||
{
|
||||
smartlist_t *files = NULL;
|
||||
dumped_desc_t *ent = NULL;
|
||||
|
||||
tor_assert(dirname != NULL);
|
||||
|
||||
/* Get a list of files */
|
||||
files = tor_listdir(dirname);
|
||||
if (!files) {
|
||||
log_notice(LD_DIR,
|
||||
"Unable to get contents of unparseable descriptor dump "
|
||||
"directory %s",
|
||||
dirname);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate through the list and decide which files should go in the
|
||||
* FIFO and which should be purged.
|
||||
*/
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(files, char *, f) {
|
||||
/* Try to get a FIFO entry */
|
||||
ent = dump_desc_populate_one_file(dirname, f);
|
||||
if (ent) {
|
||||
/*
|
||||
* We got one; add it to the FIFO. No need for duplicate checking
|
||||
* here since we just verified the name and digest match.
|
||||
*/
|
||||
|
||||
/* Make sure we have a list to add it to */
|
||||
if (!descs_dumped) {
|
||||
descs_dumped = smartlist_new();
|
||||
len_descs_dumped = 0;
|
||||
}
|
||||
|
||||
/* Add it and adjust the counter */
|
||||
smartlist_add(descs_dumped, ent);
|
||||
len_descs_dumped += ent->len;
|
||||
}
|
||||
/*
|
||||
* If we didn't, we will have unlinked the file if necessary and
|
||||
* possible, and emitted a log message about it, so just go on to
|
||||
* the next.
|
||||
*/
|
||||
} SMARTLIST_FOREACH_END(f);
|
||||
|
||||
/* Did we get anything? */
|
||||
if (descs_dumped != NULL) {
|
||||
/* Sort the FIFO in order of increasing timestamp */
|
||||
smartlist_sort(descs_dumped, dump_desc_compare_fifo_entries);
|
||||
|
||||
/* Log some stats */
|
||||
log_info(LD_DIR,
|
||||
"Reloaded unparseable descriptor dump FIFO with %d dump(s) "
|
||||
"totaling %"PRIu64 " bytes",
|
||||
smartlist_len(descs_dumped), (len_descs_dumped));
|
||||
}
|
||||
|
||||
/* Free the original list */
|
||||
SMARTLIST_FOREACH(files, char *, f, tor_free(f));
|
||||
smartlist_free(files);
|
||||
}
|
||||
|
||||
/** For debugging purposes, dump unparseable descriptor *<b>desc</b> of
|
||||
* type *<b>type</b> to file $DATADIR/unparseable-desc. Do not write more
|
||||
* than one descriptor to disk per minute. If there is already such a
|
||||
* file in the data directory, overwrite it. */
|
||||
MOCK_IMPL(void,
|
||||
dump_desc,(const char *desc, const char *type))
|
||||
{
|
||||
tor_assert(desc);
|
||||
tor_assert(type);
|
||||
size_t len;
|
||||
/* The SHA256 of the string */
|
||||
uint8_t digest_sha256[DIGEST256_LEN];
|
||||
char digest_sha256_hex[HEX_DIGEST256_LEN+1];
|
||||
/* Filename to log it to */
|
||||
char *debugfile, *debugfile_base;
|
||||
|
||||
/* Get the hash for logging purposes anyway */
|
||||
len = strlen(desc);
|
||||
if (crypto_digest256((char *)digest_sha256, desc, len,
|
||||
DIGEST_SHA256) < 0) {
|
||||
log_info(LD_DIR,
|
||||
"Unable to parse descriptor of type %s, and unable to even hash"
|
||||
" it!", type);
|
||||
goto err;
|
||||
}
|
||||
|
||||
base16_encode(digest_sha256_hex, sizeof(digest_sha256_hex),
|
||||
(const char *)digest_sha256, sizeof(digest_sha256));
|
||||
|
||||
/*
|
||||
* We mention type and hash in the main log; don't clutter up the files
|
||||
* with anything but the exact dump.
|
||||
*/
|
||||
tor_asprintf(&debugfile_base,
|
||||
DESC_DUMP_BASE_FILENAME ".%s", digest_sha256_hex);
|
||||
debugfile = get_datadir_fname2(DESC_DUMP_DATADIR_SUBDIR, debugfile_base);
|
||||
|
||||
/*
|
||||
* Check if the sandbox is active or will become active; see comment
|
||||
* below at the log message for why.
|
||||
*/
|
||||
if (!(sandbox_is_active() || get_options()->Sandbox)) {
|
||||
if (len <= get_options()->MaxUnparseableDescSizeToLog) {
|
||||
if (!dump_desc_fifo_bump_hash(digest_sha256)) {
|
||||
/* Create the directory if needed */
|
||||
dump_desc_create_dir();
|
||||
/* Make sure we've got it */
|
||||
if (have_dump_desc_dir && !problem_with_dump_desc_dir) {
|
||||
/* Write it, and tell the main log about it */
|
||||
write_str_to_file(debugfile, desc, 1);
|
||||
log_info(LD_DIR,
|
||||
"Unable to parse descriptor of type %s with hash %s and "
|
||||
"length %lu. See file %s in data directory for details.",
|
||||
type, digest_sha256_hex, (unsigned long)len,
|
||||
debugfile_base);
|
||||
dump_desc_fifo_add_and_clean(debugfile, digest_sha256, len);
|
||||
/* Since we handed ownership over, don't free debugfile later */
|
||||
debugfile = NULL;
|
||||
} else {
|
||||
/* Problem with the subdirectory */
|
||||
log_info(LD_DIR,
|
||||
"Unable to parse descriptor of type %s with hash %s and "
|
||||
"length %lu. Descriptor not dumped because we had a "
|
||||
"problem creating the " DESC_DUMP_DATADIR_SUBDIR
|
||||
" subdirectory",
|
||||
type, digest_sha256_hex, (unsigned long)len);
|
||||
/* We do have to free debugfile in this case */
|
||||
}
|
||||
} else {
|
||||
/* We already had one with this hash dumped */
|
||||
log_info(LD_DIR,
|
||||
"Unable to parse descriptor of type %s with hash %s and "
|
||||
"length %lu. Descriptor not dumped because one with that "
|
||||
"hash has already been dumped.",
|
||||
type, digest_sha256_hex, (unsigned long)len);
|
||||
/* We do have to free debugfile in this case */
|
||||
}
|
||||
} else {
|
||||
/* Just log that it happened without dumping */
|
||||
log_info(LD_DIR,
|
||||
"Unable to parse descriptor of type %s with hash %s and "
|
||||
"length %lu. Descriptor not dumped because it exceeds maximum"
|
||||
" log size all by itself.",
|
||||
type, digest_sha256_hex, (unsigned long)len);
|
||||
/* We do have to free debugfile in this case */
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Not logging because the sandbox is active and seccomp2 apparently
|
||||
* doesn't have a sensible way to allow filenames according to a pattern
|
||||
* match. (If we ever figure out how to say "allow writes to /regex/",
|
||||
* remove this checK).
|
||||
*/
|
||||
log_info(LD_DIR,
|
||||
"Unable to parse descriptor of type %s with hash %s and "
|
||||
"length %lu. Descriptor not dumped because the sandbox is "
|
||||
"configured",
|
||||
type, digest_sha256_hex, (unsigned long)len);
|
||||
}
|
||||
|
||||
tor_free(debugfile_base);
|
||||
tor_free(debugfile);
|
||||
|
||||
err:
|
||||
return;
|
||||
}
|
56
src/feature/dirparse/unparseable.h
Normal file
56
src/feature/dirparse/unparseable.h
Normal file
@ -0,0 +1,56 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 unparseable.h
|
||||
* \brief Header file for unparseable.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_UNPARSEABLE_H
|
||||
#define TOR_UNPARSEABLE_H
|
||||
|
||||
#include "lib/cc/torint.h"
|
||||
|
||||
MOCK_DECL(void,dump_desc,(const char *desc, const char *type));
|
||||
void dump_desc_fifo_cleanup(void);
|
||||
void dump_desc_init(void);
|
||||
|
||||
#undef DEBUG_AREA_ALLOC
|
||||
#ifdef DEBUG_AREA_ALLOC
|
||||
#define DUMP_AREA(a,name) STMT_BEGIN \
|
||||
size_t alloc=0, used=0; \
|
||||
memarea_get_stats((a),&alloc,&used); \
|
||||
log_debug(LD_MM, "Area for %s has %lu allocated; using %lu.", \
|
||||
name, (unsigned long)alloc, (unsigned long)used); \
|
||||
STMT_END
|
||||
#else /* !(defined(DEBUG_AREA_ALLOC)) */
|
||||
#define DUMP_AREA(a,name) STMT_NIL
|
||||
#endif /* defined(DEBUG_AREA_ALLOC) */
|
||||
|
||||
#ifdef UNPARSEABLE_PRIVATE
|
||||
|
||||
/*
|
||||
* One entry in the list of dumped descriptors; filename dumped to, length,
|
||||
* SHA-256 and timestamp.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
char *filename;
|
||||
size_t len;
|
||||
uint8_t digest_sha256[DIGEST256_LEN];
|
||||
time_t when;
|
||||
} dumped_desc_t;
|
||||
struct smartlist_t;
|
||||
|
||||
EXTERN(uint64_t, len_descs_dumped)
|
||||
EXTERN(struct smartlist_t *, descs_dumped)
|
||||
|
||||
MOCK_DECL(STATIC dumped_desc_t *, dump_desc_populate_one_file,
|
||||
(const char *dirname, const char *f));
|
||||
STATIC void dump_desc_populate_fifo_from_directory(const char *dirname);
|
||||
#endif
|
||||
|
||||
#endif /* !defined(TOR_UNPARSEABLE_H) */
|
@ -61,7 +61,7 @@
|
||||
#include "core/or/circuitbuild.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "lib/crypt_ops/crypto_util.h"
|
||||
#include "feature/nodelist/parsecommon.h"
|
||||
#include "feature/dirparse/parsecommon.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/hs/hs_cache.h"
|
||||
#include "feature/hs/hs_config.h"
|
||||
|
@ -24,17 +24,17 @@
|
||||
#include "core/or/policies.h"
|
||||
#include "feature/client/bridges.h"
|
||||
#include "feature/dirauth/authmode.h"
|
||||
#include "feature/dircommon/directory.h"
|
||||
#include "feature/dirclient/dirclient.h"
|
||||
#include "feature/dirclient/dlstatus.h"
|
||||
#include "feature/dircommon/directory.h"
|
||||
#include "feature/dircommon/fp_pair.h"
|
||||
#include "feature/dirparse/authcert_parse.h"
|
||||
#include "feature/nodelist/authcert.h"
|
||||
#include "feature/nodelist/dirlist.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/node_select.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
|
||||
#include "core/or/connection_st.h"
|
||||
|
@ -12,20 +12,20 @@
|
||||
|
||||
#include "lib/fdio/fdio.h"
|
||||
|
||||
#include "core/or/circuitbuild.h"
|
||||
#include "app/config/config.h"
|
||||
#include "feature/dircommon/directory.h"
|
||||
#include "core/or/circuitbuild.h"
|
||||
#include "core/or/policies.h"
|
||||
#include "feature/client/entrynodes.h"
|
||||
#include "feature/dircache/dirserv.h"
|
||||
#include "feature/dirclient/dlstatus.h"
|
||||
#include "feature/client/entrynodes.h"
|
||||
#include "feature/dircommon/directory.h"
|
||||
#include "feature/dirparse/microdesc_parse.h"
|
||||
#include "feature/nodelist/dirlist.h"
|
||||
#include "feature/nodelist/microdesc.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "core/or/policies.h"
|
||||
#include "feature/relay/router.h"
|
||||
#include "feature/nodelist/dirlist.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/relay/router.h"
|
||||
|
||||
#include "feature/nodelist/microdesc_st.h"
|
||||
#include "feature/nodelist/networkstatus_st.h"
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "core/or/protover.h"
|
||||
#include "core/or/relay.h"
|
||||
#include "core/or/scheduler.h"
|
||||
#include "core/or/versions.h"
|
||||
#include "feature/client/bridges.h"
|
||||
#include "feature/client/entrynodes.h"
|
||||
#include "feature/client/transports.h"
|
||||
@ -64,6 +65,7 @@
|
||||
#include "feature/dirclient/dlstatus.h"
|
||||
#include "feature/dircommon/directory.h"
|
||||
#include "feature/dircommon/voting_schedule.h"
|
||||
#include "feature/dirparse/ns_parse.h"
|
||||
#include "feature/hibernate/hibernate.h"
|
||||
#include "feature/nodelist/authcert.h"
|
||||
#include "feature/nodelist/dirlist.h"
|
||||
@ -74,7 +76,6 @@
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerinfo.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/nodelist/torcert.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
@ -2705,25 +2706,6 @@ networkstatus_check_required_protocols(const networkstatus_t *ns,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Release all storage held in <b>s</b>. */
|
||||
void
|
||||
ns_detached_signatures_free_(ns_detached_signatures_t *s)
|
||||
{
|
||||
if (!s)
|
||||
return;
|
||||
if (s->signatures) {
|
||||
STRMAP_FOREACH(s->signatures, flavor, smartlist_t *, sigs) {
|
||||
SMARTLIST_FOREACH(sigs, document_signature_t *, sig,
|
||||
document_signature_free(sig));
|
||||
smartlist_free(sigs);
|
||||
} STRMAP_FOREACH_END;
|
||||
strmap_free(s->signatures, NULL);
|
||||
strmap_free(s->digests, tor_free_);
|
||||
}
|
||||
|
||||
tor_free(s);
|
||||
}
|
||||
|
||||
/** Free all storage held locally in this module. */
|
||||
void
|
||||
networkstatus_free_all(void)
|
||||
|
@ -24,9 +24,6 @@ void routerstatus_free_(routerstatus_t *rs);
|
||||
void networkstatus_vote_free_(networkstatus_t *ns);
|
||||
#define networkstatus_vote_free(ns) \
|
||||
FREE_AND_NULL(networkstatus_t, networkstatus_vote_free_, (ns))
|
||||
void ns_detached_signatures_free_(ns_detached_signatures_t *s);
|
||||
#define ns_detached_signatures_free(s) \
|
||||
FREE_AND_NULL(ns_detached_signatures_t, ns_detached_signatures_free_, (s))
|
||||
networkstatus_voter_info_t *networkstatus_get_voter_by_id(
|
||||
networkstatus_t *vote,
|
||||
const char *identity);
|
||||
|
@ -61,7 +61,6 @@
|
||||
#include "feature/nodelist/node_select.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/nodelist/routerset.h"
|
||||
#include "feature/nodelist/torcert.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
|
@ -84,7 +84,7 @@
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerinfo.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/routerparse.h"
|
||||
#include "feature/nodelist/routerset.h"
|
||||
#include "feature/nodelist/torcert.h"
|
||||
#include "feature/relay/routermode.h"
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,161 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 routerparse.h
|
||||
* \brief Header file for routerparse.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_ROUTERPARSE_H
|
||||
#define TOR_ROUTERPARSE_H
|
||||
|
||||
/** Possible statuses of a version of Tor, given opinions from the directory
|
||||
* servers. */
|
||||
typedef enum version_status_t {
|
||||
VS_RECOMMENDED=0, /**< This version is listed as recommended. */
|
||||
VS_OLD=1, /**< This version is older than any recommended version. */
|
||||
VS_NEW=2, /**< This version is newer than any recommended version. */
|
||||
VS_NEW_IN_SERIES=3, /**< This version is newer than any recommended version
|
||||
* in its series, but later recommended versions exist.
|
||||
*/
|
||||
VS_UNRECOMMENDED=4, /**< This version is not recommended (general case). */
|
||||
VS_EMPTY=5, /**< The version list was empty; no agreed-on versions. */
|
||||
VS_UNKNOWN, /**< We have no idea. */
|
||||
} version_status_t;
|
||||
|
||||
enum networkstatus_type_t;
|
||||
|
||||
int router_get_router_hash(const char *s, size_t s_len, char *digest);
|
||||
int router_get_dir_hash(const char *s, char *digest);
|
||||
int router_get_networkstatus_v3_hashes(const char *s,
|
||||
common_digests_t *digests);
|
||||
int router_get_networkstatus_v3_signed_boundaries(const char *s,
|
||||
const char **start_out,
|
||||
const char **end_out);
|
||||
int router_get_networkstatus_v3_sha3_as_signed(uint8_t *digest_out,
|
||||
const char *s);
|
||||
int router_get_extrainfo_hash(const char *s, size_t s_len, char *digest);
|
||||
#define DIROBJ_MAX_SIG_LEN 256
|
||||
char *router_get_dirobj_signature(const char *digest,
|
||||
size_t digest_len,
|
||||
const crypto_pk_t *private_key);
|
||||
int router_append_dirobj_signature(char *buf, size_t buf_len,
|
||||
const char *digest,
|
||||
size_t digest_len,
|
||||
crypto_pk_t *private_key);
|
||||
int router_parse_list_from_string(const char **s, const char *eos,
|
||||
smartlist_t *dest,
|
||||
saved_location_t saved_location,
|
||||
int is_extrainfo,
|
||||
int allow_annotations,
|
||||
const char *prepend_annotations,
|
||||
smartlist_t *invalid_digests_out);
|
||||
|
||||
routerinfo_t *router_parse_entry_from_string(const char *s, const char *end,
|
||||
int cache_copy,
|
||||
int allow_annotations,
|
||||
const char *prepend_annotations,
|
||||
int *can_dl_again_out);
|
||||
struct digest_ri_map_t;
|
||||
extrainfo_t *extrainfo_parse_entry_from_string(const char *s, const char *end,
|
||||
int cache_copy, struct digest_ri_map_t *routermap,
|
||||
int *can_dl_again_out);
|
||||
MOCK_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string,
|
||||
(const char *s, int assume_action, int *malformed_list));
|
||||
version_status_t tor_version_is_obsolete(const char *myversion,
|
||||
const char *versionlist);
|
||||
int tor_version_parse_platform(const char *platform,
|
||||
tor_version_t *version_out,
|
||||
int strict);
|
||||
int tor_version_as_new_as(const char *platform, const char *cutoff);
|
||||
int tor_version_parse(const char *s, tor_version_t *out);
|
||||
int tor_version_compare(tor_version_t *a, tor_version_t *b);
|
||||
int tor_version_same_series(tor_version_t *a, tor_version_t *b);
|
||||
void sort_version_list(smartlist_t *lst, int remove_duplicates);
|
||||
void assert_addr_policy_ok(smartlist_t *t);
|
||||
void dump_distinct_digest_count(int severity);
|
||||
|
||||
int compare_vote_routerstatus_entries(const void **_a, const void **_b);
|
||||
int networkstatus_verify_bw_weights(networkstatus_t *ns, int);
|
||||
networkstatus_t *networkstatus_parse_vote_from_string(const char *s,
|
||||
const char **eos_out,
|
||||
enum networkstatus_type_t ns_type);
|
||||
ns_detached_signatures_t *networkstatus_parse_detached_signatures(
|
||||
const char *s, const char *eos);
|
||||
|
||||
smartlist_t *microdescs_parse_from_string(const char *s, const char *eos,
|
||||
int allow_annotations,
|
||||
saved_location_t where,
|
||||
smartlist_t *invalid_digests_out);
|
||||
|
||||
authority_cert_t *authority_cert_parse_from_string(const char *s,
|
||||
const char **end_of_string);
|
||||
int rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
|
||||
char *desc_id_out,
|
||||
char **intro_points_encrypted_out,
|
||||
size_t *intro_points_encrypted_size_out,
|
||||
size_t *encoded_size_out,
|
||||
const char **next_out, const char *desc,
|
||||
int as_hsdir);
|
||||
int rend_decrypt_introduction_points(char **ipos_decrypted,
|
||||
size_t *ipos_decrypted_size,
|
||||
const char *descriptor_cookie,
|
||||
const char *ipos_encrypted,
|
||||
size_t ipos_encrypted_size);
|
||||
int rend_parse_introduction_points(rend_service_descriptor_t *parsed,
|
||||
const char *intro_points_encoded,
|
||||
size_t intro_points_encoded_size);
|
||||
int rend_parse_client_keys(strmap_t *parsed_clients, const char *str);
|
||||
|
||||
void routerparse_init(void);
|
||||
void routerparse_free_all(void);
|
||||
|
||||
#ifdef ROUTERPARSE_PRIVATE
|
||||
/*
|
||||
* One entry in the list of dumped descriptors; filename dumped to, length,
|
||||
* SHA-256 and timestamp.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
char *filename;
|
||||
size_t len;
|
||||
uint8_t digest_sha256[DIGEST256_LEN];
|
||||
time_t when;
|
||||
} dumped_desc_t;
|
||||
|
||||
EXTERN(uint64_t, len_descs_dumped)
|
||||
EXTERN(smartlist_t *, descs_dumped)
|
||||
STATIC int routerstatus_parse_guardfraction(const char *guardfraction_str,
|
||||
networkstatus_t *vote,
|
||||
vote_routerstatus_t *vote_rs,
|
||||
routerstatus_t *rs);
|
||||
MOCK_DECL(STATIC dumped_desc_t *, dump_desc_populate_one_file,
|
||||
(const char *dirname, const char *f));
|
||||
STATIC void dump_desc_populate_fifo_from_directory(const char *dirname);
|
||||
STATIC void dump_desc_fifo_cleanup(void);
|
||||
struct memarea_t;
|
||||
STATIC routerstatus_t *routerstatus_parse_entry_from_string(
|
||||
struct memarea_t *area,
|
||||
const char **s, smartlist_t *tokens,
|
||||
networkstatus_t *vote,
|
||||
vote_routerstatus_t *vote_rs,
|
||||
int consensus_method,
|
||||
consensus_flavor_t flav);
|
||||
MOCK_DECL(STATIC void,dump_desc,(const char *desc, const char *type));
|
||||
MOCK_DECL(STATIC int, router_compute_hash_final,(char *digest,
|
||||
const char *start, size_t len,
|
||||
digest_algorithm_t alg));
|
||||
MOCK_DECL(STATIC int, signed_digest_equals,
|
||||
(const uint8_t *d1, const uint8_t *d2, size_t len));
|
||||
|
||||
STATIC void summarize_protover_flags(protover_summary_flags_t *out,
|
||||
const char *protocols,
|
||||
const char *version);
|
||||
#endif /* defined(ROUTERPARSE_PRIVATE) */
|
||||
|
||||
#define ED_DESC_SIGNATURE_PREFIX "Tor router descriptor signature v1"
|
||||
|
||||
#endif /* !defined(TOR_ROUTERPARSE_H) */
|
@ -30,9 +30,9 @@ n * Copyright (c) 2001-2004, Roger Dingledine.
|
||||
#include "core/or/or.h"
|
||||
#include "core/or/policies.h"
|
||||
#include "feature/client/bridges.h"
|
||||
#include "feature/dirparse/policy_parse.h"
|
||||
#include "feature/nodelist/nickname.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/nodelist/routerset.h"
|
||||
#include "lib/geoip/geoip.h"
|
||||
|
||||
|
@ -21,6 +21,9 @@
|
||||
#include "feature/dircache/dirserv.h"
|
||||
#include "feature/dirclient/dirclient.h"
|
||||
#include "feature/dircommon/directory.h"
|
||||
#include "feature/dirparse/authcert_parse.h"
|
||||
#include "feature/dirparse/routerparse.h"
|
||||
#include "feature/dirparse/signing.h"
|
||||
#include "feature/hibernate/hibernate.h"
|
||||
#include "feature/keymgt/loadkey.h"
|
||||
#include "feature/nodelist/authcert.h"
|
||||
@ -29,7 +32,6 @@
|
||||
#include "feature/nodelist/nickname.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/nodelist/torcert.h"
|
||||
#include "feature/relay/dns.h"
|
||||
#include "feature/relay/router.h"
|
||||
|
@ -12,8 +12,8 @@
|
||||
#include "app/config/config.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendparse.h"
|
||||
|
||||
#include "core/or/extend_info_st.h"
|
||||
#include "feature/rend/rend_intro_point_st.h"
|
||||
|
@ -25,12 +25,13 @@
|
||||
#include "feature/rend/rendclient.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendmid.h"
|
||||
#include "feature/rend/rendparse.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
#include "feature/hs_common/replaycache.h"
|
||||
#include "feature/relay/router.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/signing.h"
|
||||
|
||||
#include "core/or/cpath_build_state_st.h"
|
||||
#include "core/or/crypt_path_st.h"
|
||||
|
600
src/feature/rend/rendparse.c
Normal file
600
src/feature/rend/rendparse.c
Normal file
@ -0,0 +1,600 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 rendparse.c
|
||||
* \brief Code to parse and validate v2 hidden service descriptors.
|
||||
**/
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "feature/dirparse/parsecommon.h"
|
||||
#include "feature/dirparse/sigcommon.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendparse.h"
|
||||
#include "lib/memarea/memarea.h"
|
||||
|
||||
#include "core/or/extend_info_st.h"
|
||||
#include "feature/rend/rend_authorized_client_st.h"
|
||||
#include "feature/rend/rend_intro_point_st.h"
|
||||
#include "feature/rend/rend_service_descriptor_st.h"
|
||||
|
||||
/** List of tokens recognized in rendezvous service descriptors */
|
||||
static token_rule_t desc_token_table[] = {
|
||||
T1_START("rendezvous-service-descriptor", R_RENDEZVOUS_SERVICE_DESCRIPTOR,
|
||||
EQ(1), NO_OBJ),
|
||||
T1("version", R_VERSION, EQ(1), NO_OBJ),
|
||||
T1("permanent-key", R_PERMANENT_KEY, NO_ARGS, NEED_KEY_1024),
|
||||
T1("secret-id-part", R_SECRET_ID_PART, EQ(1), NO_OBJ),
|
||||
T1("publication-time", R_PUBLICATION_TIME, CONCAT_ARGS, NO_OBJ),
|
||||
T1("protocol-versions", R_PROTOCOL_VERSIONS, EQ(1), NO_OBJ),
|
||||
T01("introduction-points", R_INTRODUCTION_POINTS, NO_ARGS, NEED_OBJ),
|
||||
T1_END("signature", R_SIGNATURE, NO_ARGS, NEED_OBJ),
|
||||
END_OF_TABLE
|
||||
};
|
||||
|
||||
/** List of tokens recognized in the (encrypted) list of introduction points of
|
||||
* rendezvous service descriptors */
|
||||
static token_rule_t ipo_token_table[] = {
|
||||
T1_START("introduction-point", R_IPO_IDENTIFIER, EQ(1), NO_OBJ),
|
||||
T1("ip-address", R_IPO_IP_ADDRESS, EQ(1), NO_OBJ),
|
||||
T1("onion-port", R_IPO_ONION_PORT, EQ(1), NO_OBJ),
|
||||
T1("onion-key", R_IPO_ONION_KEY, NO_ARGS, NEED_KEY_1024),
|
||||
T1("service-key", R_IPO_SERVICE_KEY, NO_ARGS, NEED_KEY_1024),
|
||||
END_OF_TABLE
|
||||
};
|
||||
|
||||
/** List of tokens recognized in the (possibly encrypted) list of introduction
|
||||
* points of rendezvous service descriptors */
|
||||
static token_rule_t client_keys_token_table[] = {
|
||||
T1_START("client-name", C_CLIENT_NAME, CONCAT_ARGS, NO_OBJ),
|
||||
T1("descriptor-cookie", C_DESCRIPTOR_COOKIE, EQ(1), NO_OBJ),
|
||||
T01("client-key", C_CLIENT_KEY, NO_ARGS, NEED_SKEY_1024),
|
||||
END_OF_TABLE
|
||||
};
|
||||
|
||||
/** Parse and validate the ASCII-encoded v2 descriptor in <b>desc</b>,
|
||||
* write the parsed descriptor to the newly allocated *<b>parsed_out</b>, the
|
||||
* binary descriptor ID of length DIGEST_LEN to <b>desc_id_out</b>, the
|
||||
* encrypted introduction points to the newly allocated
|
||||
* *<b>intro_points_encrypted_out</b>, their encrypted size to
|
||||
* *<b>intro_points_encrypted_size_out</b>, the size of the encoded descriptor
|
||||
* to *<b>encoded_size_out</b>, and a pointer to the possibly next
|
||||
* descriptor to *<b>next_out</b>; return 0 for success (including validation)
|
||||
* and -1 for failure.
|
||||
*
|
||||
* If <b>as_hsdir</b> is 1, we're parsing this as an HSDir, and we should
|
||||
* be strict about time formats.
|
||||
*/
|
||||
int
|
||||
rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
|
||||
char *desc_id_out,
|
||||
char **intro_points_encrypted_out,
|
||||
size_t *intro_points_encrypted_size_out,
|
||||
size_t *encoded_size_out,
|
||||
const char **next_out, const char *desc,
|
||||
int as_hsdir)
|
||||
{
|
||||
rend_service_descriptor_t *result =
|
||||
tor_malloc_zero(sizeof(rend_service_descriptor_t));
|
||||
char desc_hash[DIGEST_LEN];
|
||||
const char *eos;
|
||||
smartlist_t *tokens = smartlist_new();
|
||||
directory_token_t *tok;
|
||||
char secret_id_part[DIGEST_LEN];
|
||||
int i, version, num_ok=1;
|
||||
smartlist_t *versions;
|
||||
char public_key_hash[DIGEST_LEN];
|
||||
char test_desc_id[DIGEST_LEN];
|
||||
memarea_t *area = NULL;
|
||||
const int strict_time_fmt = as_hsdir;
|
||||
|
||||
tor_assert(desc);
|
||||
/* Check if desc starts correctly. */
|
||||
if (strcmpstart(desc, "rendezvous-service-descriptor ")) {
|
||||
log_info(LD_REND, "Descriptor does not start correctly.");
|
||||
goto err;
|
||||
}
|
||||
/* Compute descriptor hash for later validation. */
|
||||
if (router_get_hash_impl(desc, strlen(desc), desc_hash,
|
||||
"rendezvous-service-descriptor ",
|
||||
"\nsignature", '\n', DIGEST_SHA1) < 0) {
|
||||
log_warn(LD_REND, "Couldn't compute descriptor hash.");
|
||||
goto err;
|
||||
}
|
||||
/* Determine end of string. */
|
||||
eos = strstr(desc, "\nrendezvous-service-descriptor ");
|
||||
if (!eos)
|
||||
eos = desc + strlen(desc);
|
||||
else
|
||||
eos = eos + 1;
|
||||
/* Check length. */
|
||||
if (eos-desc > REND_DESC_MAX_SIZE) {
|
||||
/* XXXX+ If we are parsing this descriptor as a server, this
|
||||
* should be a protocol warning. */
|
||||
log_warn(LD_REND, "Descriptor length is %d which exceeds "
|
||||
"maximum rendezvous descriptor size of %d bytes.",
|
||||
(int)(eos-desc), REND_DESC_MAX_SIZE);
|
||||
goto err;
|
||||
}
|
||||
/* Tokenize descriptor. */
|
||||
area = memarea_new();
|
||||
if (tokenize_string(area, desc, eos, tokens, desc_token_table, 0)) {
|
||||
log_warn(LD_REND, "Error tokenizing descriptor.");
|
||||
goto err;
|
||||
}
|
||||
/* Set next to next descriptor, if available. */
|
||||
*next_out = eos;
|
||||
/* Set length of encoded descriptor. */
|
||||
*encoded_size_out = eos - desc;
|
||||
/* Check min allowed length of token list. */
|
||||
if (smartlist_len(tokens) < 7) {
|
||||
log_warn(LD_REND, "Impossibly short descriptor.");
|
||||
goto err;
|
||||
}
|
||||
/* Parse base32-encoded descriptor ID. */
|
||||
tok = find_by_keyword(tokens, R_RENDEZVOUS_SERVICE_DESCRIPTOR);
|
||||
tor_assert(tok == smartlist_get(tokens, 0));
|
||||
tor_assert(tok->n_args == 1);
|
||||
if (!rend_valid_descriptor_id(tok->args[0])) {
|
||||
log_warn(LD_REND, "Invalid descriptor ID: '%s'", tok->args[0]);
|
||||
goto err;
|
||||
}
|
||||
if (base32_decode(desc_id_out, DIGEST_LEN,
|
||||
tok->args[0], REND_DESC_ID_V2_LEN_BASE32) < 0) {
|
||||
log_warn(LD_REND, "Descriptor ID contains illegal characters: %s",
|
||||
tok->args[0]);
|
||||
goto err;
|
||||
}
|
||||
/* Parse descriptor version. */
|
||||
tok = find_by_keyword(tokens, R_VERSION);
|
||||
tor_assert(tok->n_args == 1);
|
||||
result->version =
|
||||
(int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &num_ok, NULL);
|
||||
if (result->version != 2 || !num_ok) {
|
||||
/* If it's <2, it shouldn't be under this format. If the number
|
||||
* is greater than 2, we bumped it because we broke backward
|
||||
* compatibility. See how version numbers in our other formats
|
||||
* work. */
|
||||
log_warn(LD_REND, "Unrecognized descriptor version: %s",
|
||||
escaped(tok->args[0]));
|
||||
goto err;
|
||||
}
|
||||
/* Parse public key. */
|
||||
tok = find_by_keyword(tokens, R_PERMANENT_KEY);
|
||||
result->pk = tok->key;
|
||||
tok->key = NULL; /* Prevent free */
|
||||
/* Parse secret ID part. */
|
||||
tok = find_by_keyword(tokens, R_SECRET_ID_PART);
|
||||
tor_assert(tok->n_args == 1);
|
||||
if (strlen(tok->args[0]) != REND_SECRET_ID_PART_LEN_BASE32 ||
|
||||
strspn(tok->args[0], BASE32_CHARS) != REND_SECRET_ID_PART_LEN_BASE32) {
|
||||
log_warn(LD_REND, "Invalid secret ID part: '%s'", tok->args[0]);
|
||||
goto err;
|
||||
}
|
||||
if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) < 0) {
|
||||
log_warn(LD_REND, "Secret ID part contains illegal characters: %s",
|
||||
tok->args[0]);
|
||||
goto err;
|
||||
}
|
||||
/* Parse publication time -- up-to-date check is done when storing the
|
||||
* descriptor. */
|
||||
tok = find_by_keyword(tokens, R_PUBLICATION_TIME);
|
||||
tor_assert(tok->n_args == 1);
|
||||
if (parse_iso_time_(tok->args[0], &result->timestamp,
|
||||
strict_time_fmt, 0) < 0) {
|
||||
log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]);
|
||||
goto err;
|
||||
}
|
||||
/* Parse protocol versions. */
|
||||
tok = find_by_keyword(tokens, R_PROTOCOL_VERSIONS);
|
||||
tor_assert(tok->n_args == 1);
|
||||
versions = smartlist_new();
|
||||
smartlist_split_string(versions, tok->args[0], ",",
|
||||
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
||||
for (i = 0; i < smartlist_len(versions); i++) {
|
||||
version = (int) tor_parse_long(smartlist_get(versions, i),
|
||||
10, 0, INT_MAX, &num_ok, NULL);
|
||||
if (!num_ok) /* It's a string; let's ignore it. */
|
||||
continue;
|
||||
if (version >= REND_PROTOCOL_VERSION_BITMASK_WIDTH)
|
||||
/* Avoid undefined left-shift behaviour. */
|
||||
continue;
|
||||
result->protocols |= 1 << version;
|
||||
}
|
||||
SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp));
|
||||
smartlist_free(versions);
|
||||
/* Parse encrypted introduction points. Don't verify. */
|
||||
tok = find_opt_by_keyword(tokens, R_INTRODUCTION_POINTS);
|
||||
if (tok) {
|
||||
if (strcmp(tok->object_type, "MESSAGE")) {
|
||||
log_warn(LD_DIR, "Bad object type: introduction points should be of "
|
||||
"type MESSAGE");
|
||||
goto err;
|
||||
}
|
||||
*intro_points_encrypted_out = tor_memdup(tok->object_body,
|
||||
tok->object_size);
|
||||
*intro_points_encrypted_size_out = tok->object_size;
|
||||
} else {
|
||||
*intro_points_encrypted_out = NULL;
|
||||
*intro_points_encrypted_size_out = 0;
|
||||
}
|
||||
/* Parse and verify signature. */
|
||||
tok = find_by_keyword(tokens, R_SIGNATURE);
|
||||
if (check_signature_token(desc_hash, DIGEST_LEN, tok, result->pk, 0,
|
||||
"v2 rendezvous service descriptor") < 0)
|
||||
goto err;
|
||||
/* Verify that descriptor ID belongs to public key and secret ID part. */
|
||||
if (crypto_pk_get_digest(result->pk, public_key_hash) < 0) {
|
||||
log_warn(LD_REND, "Unable to compute rend descriptor public key digest");
|
||||
goto err;
|
||||
}
|
||||
rend_get_descriptor_id_bytes(test_desc_id, public_key_hash,
|
||||
secret_id_part);
|
||||
if (tor_memneq(desc_id_out, test_desc_id, DIGEST_LEN)) {
|
||||
log_warn(LD_REND, "Parsed descriptor ID does not match "
|
||||
"computed descriptor ID.");
|
||||
goto err;
|
||||
}
|
||||
goto done;
|
||||
err:
|
||||
rend_service_descriptor_free(result);
|
||||
result = NULL;
|
||||
done:
|
||||
if (tokens) {
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
|
||||
smartlist_free(tokens);
|
||||
}
|
||||
if (area)
|
||||
memarea_drop_all(area);
|
||||
*parsed_out = result;
|
||||
if (result)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Decrypt the encrypted introduction points in <b>ipos_encrypted</b> of
|
||||
* length <b>ipos_encrypted_size</b> using <b>descriptor_cookie</b> and
|
||||
* write the result to a newly allocated string that is pointed to by
|
||||
* <b>ipos_decrypted</b> and its length to <b>ipos_decrypted_size</b>.
|
||||
* Return 0 if decryption was successful and -1 otherwise. */
|
||||
int
|
||||
rend_decrypt_introduction_points(char **ipos_decrypted,
|
||||
size_t *ipos_decrypted_size,
|
||||
const char *descriptor_cookie,
|
||||
const char *ipos_encrypted,
|
||||
size_t ipos_encrypted_size)
|
||||
{
|
||||
tor_assert(ipos_encrypted);
|
||||
tor_assert(descriptor_cookie);
|
||||
if (ipos_encrypted_size < 2) {
|
||||
log_warn(LD_REND, "Size of encrypted introduction points is too "
|
||||
"small.");
|
||||
return -1;
|
||||
}
|
||||
if (ipos_encrypted[0] == (int)REND_BASIC_AUTH) {
|
||||
char iv[CIPHER_IV_LEN], client_id[REND_BASIC_AUTH_CLIENT_ID_LEN],
|
||||
session_key[CIPHER_KEY_LEN], *dec;
|
||||
int declen, client_blocks;
|
||||
size_t pos = 0, len, client_entries_len;
|
||||
crypto_digest_t *digest;
|
||||
crypto_cipher_t *cipher;
|
||||
client_blocks = (int) ipos_encrypted[1];
|
||||
client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE *
|
||||
REND_BASIC_AUTH_CLIENT_ENTRY_LEN;
|
||||
if (ipos_encrypted_size < 2 + client_entries_len + CIPHER_IV_LEN + 1) {
|
||||
log_warn(LD_REND, "Size of encrypted introduction points is too "
|
||||
"small.");
|
||||
return -1;
|
||||
}
|
||||
memcpy(iv, ipos_encrypted + 2 + client_entries_len, CIPHER_IV_LEN);
|
||||
digest = crypto_digest_new();
|
||||
crypto_digest_add_bytes(digest, descriptor_cookie, REND_DESC_COOKIE_LEN);
|
||||
crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN);
|
||||
crypto_digest_get_digest(digest, client_id,
|
||||
REND_BASIC_AUTH_CLIENT_ID_LEN);
|
||||
crypto_digest_free(digest);
|
||||
for (pos = 2; pos < 2 + client_entries_len;
|
||||
pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN) {
|
||||
if (tor_memeq(ipos_encrypted + pos, client_id,
|
||||
REND_BASIC_AUTH_CLIENT_ID_LEN)) {
|
||||
/* Attempt to decrypt introduction points. */
|
||||
cipher = crypto_cipher_new(descriptor_cookie);
|
||||
if (crypto_cipher_decrypt(cipher, session_key, ipos_encrypted
|
||||
+ pos + REND_BASIC_AUTH_CLIENT_ID_LEN,
|
||||
CIPHER_KEY_LEN) < 0) {
|
||||
log_warn(LD_REND, "Could not decrypt session key for client.");
|
||||
crypto_cipher_free(cipher);
|
||||
return -1;
|
||||
}
|
||||
crypto_cipher_free(cipher);
|
||||
|
||||
len = ipos_encrypted_size - 2 - client_entries_len - CIPHER_IV_LEN;
|
||||
dec = tor_malloc_zero(len + 1);
|
||||
declen = crypto_cipher_decrypt_with_iv(session_key, dec, len,
|
||||
ipos_encrypted + 2 + client_entries_len,
|
||||
ipos_encrypted_size - 2 - client_entries_len);
|
||||
|
||||
if (declen < 0) {
|
||||
log_warn(LD_REND, "Could not decrypt introduction point string.");
|
||||
tor_free(dec);
|
||||
return -1;
|
||||
}
|
||||
if (fast_memcmpstart(dec, declen, "introduction-point ")) {
|
||||
log_warn(LD_REND, "Decrypted introduction points don't "
|
||||
"look like we could parse them.");
|
||||
tor_free(dec);
|
||||
continue;
|
||||
}
|
||||
*ipos_decrypted = dec;
|
||||
*ipos_decrypted_size = declen;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
log_warn(LD_REND, "Could not decrypt introduction points. Please "
|
||||
"check your authorization for this service!");
|
||||
return -1;
|
||||
} else if (ipos_encrypted[0] == (int)REND_STEALTH_AUTH) {
|
||||
char *dec;
|
||||
int declen;
|
||||
if (ipos_encrypted_size < CIPHER_IV_LEN + 2) {
|
||||
log_warn(LD_REND, "Size of encrypted introduction points is too "
|
||||
"small.");
|
||||
return -1;
|
||||
}
|
||||
dec = tor_malloc_zero(ipos_encrypted_size - CIPHER_IV_LEN - 1 + 1);
|
||||
|
||||
declen = crypto_cipher_decrypt_with_iv(descriptor_cookie, dec,
|
||||
ipos_encrypted_size -
|
||||
CIPHER_IV_LEN - 1,
|
||||
ipos_encrypted + 1,
|
||||
ipos_encrypted_size - 1);
|
||||
|
||||
if (declen < 0) {
|
||||
log_warn(LD_REND, "Decrypting introduction points failed!");
|
||||
tor_free(dec);
|
||||
return -1;
|
||||
}
|
||||
*ipos_decrypted = dec;
|
||||
*ipos_decrypted_size = declen;
|
||||
return 0;
|
||||
} else {
|
||||
log_warn(LD_REND, "Unknown authorization type number: %d",
|
||||
ipos_encrypted[0]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Parse the encoded introduction points in <b>intro_points_encoded</b> of
|
||||
* length <b>intro_points_encoded_size</b> and write the result to the
|
||||
* descriptor in <b>parsed</b>; return the number of successfully parsed
|
||||
* introduction points or -1 in case of a failure. */
|
||||
int
|
||||
rend_parse_introduction_points(rend_service_descriptor_t *parsed,
|
||||
const char *intro_points_encoded,
|
||||
size_t intro_points_encoded_size)
|
||||
{
|
||||
const char *current_ipo, *end_of_intro_points;
|
||||
smartlist_t *tokens = NULL;
|
||||
directory_token_t *tok;
|
||||
rend_intro_point_t *intro;
|
||||
extend_info_t *info;
|
||||
int result, num_ok=1;
|
||||
memarea_t *area = NULL;
|
||||
tor_assert(parsed);
|
||||
/** Function may only be invoked once. */
|
||||
tor_assert(!parsed->intro_nodes);
|
||||
if (!intro_points_encoded || intro_points_encoded_size == 0) {
|
||||
log_warn(LD_REND, "Empty or zero size introduction point list");
|
||||
goto err;
|
||||
}
|
||||
/* Consider one intro point after the other. */
|
||||
current_ipo = intro_points_encoded;
|
||||
end_of_intro_points = intro_points_encoded + intro_points_encoded_size;
|
||||
tokens = smartlist_new();
|
||||
parsed->intro_nodes = smartlist_new();
|
||||
area = memarea_new();
|
||||
|
||||
while (!fast_memcmpstart(current_ipo, end_of_intro_points-current_ipo,
|
||||
"introduction-point ")) {
|
||||
/* Determine end of string. */
|
||||
const char *eos = tor_memstr(current_ipo, end_of_intro_points-current_ipo,
|
||||
"\nintroduction-point ");
|
||||
if (!eos)
|
||||
eos = end_of_intro_points;
|
||||
else
|
||||
eos = eos+1;
|
||||
tor_assert(eos <= intro_points_encoded+intro_points_encoded_size);
|
||||
/* Free tokens and clear token list. */
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
|
||||
smartlist_clear(tokens);
|
||||
memarea_clear(area);
|
||||
/* Tokenize string. */
|
||||
if (tokenize_string(area, current_ipo, eos, tokens, ipo_token_table, 0)) {
|
||||
log_warn(LD_REND, "Error tokenizing introduction point");
|
||||
goto err;
|
||||
}
|
||||
/* Advance to next introduction point, if available. */
|
||||
current_ipo = eos;
|
||||
/* Check minimum allowed length of introduction point. */
|
||||
if (smartlist_len(tokens) < 5) {
|
||||
log_warn(LD_REND, "Impossibly short introduction point.");
|
||||
goto err;
|
||||
}
|
||||
/* Allocate new intro point and extend info. */
|
||||
intro = tor_malloc_zero(sizeof(rend_intro_point_t));
|
||||
info = intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
|
||||
/* Parse identifier. */
|
||||
tok = find_by_keyword(tokens, R_IPO_IDENTIFIER);
|
||||
if (base32_decode(info->identity_digest, DIGEST_LEN,
|
||||
tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) < 0) {
|
||||
log_warn(LD_REND, "Identity digest contains illegal characters: %s",
|
||||
tok->args[0]);
|
||||
rend_intro_point_free(intro);
|
||||
goto err;
|
||||
}
|
||||
/* Write identifier to nickname. */
|
||||
info->nickname[0] = '$';
|
||||
base16_encode(info->nickname + 1, sizeof(info->nickname) - 1,
|
||||
info->identity_digest, DIGEST_LEN);
|
||||
/* Parse IP address. */
|
||||
tok = find_by_keyword(tokens, R_IPO_IP_ADDRESS);
|
||||
if (tor_addr_parse(&info->addr, tok->args[0])<0) {
|
||||
log_warn(LD_REND, "Could not parse introduction point address.");
|
||||
rend_intro_point_free(intro);
|
||||
goto err;
|
||||
}
|
||||
if (tor_addr_family(&info->addr) != AF_INET) {
|
||||
log_warn(LD_REND, "Introduction point address was not ipv4.");
|
||||
rend_intro_point_free(intro);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Parse onion port. */
|
||||
tok = find_by_keyword(tokens, R_IPO_ONION_PORT);
|
||||
info->port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535,
|
||||
&num_ok,NULL);
|
||||
if (!info->port || !num_ok) {
|
||||
log_warn(LD_REND, "Introduction point onion port %s is invalid",
|
||||
escaped(tok->args[0]));
|
||||
rend_intro_point_free(intro);
|
||||
goto err;
|
||||
}
|
||||
/* Parse onion key. */
|
||||
tok = find_by_keyword(tokens, R_IPO_ONION_KEY);
|
||||
if (!crypto_pk_public_exponent_ok(tok->key)) {
|
||||
log_warn(LD_REND,
|
||||
"Introduction point's onion key had invalid exponent.");
|
||||
rend_intro_point_free(intro);
|
||||
goto err;
|
||||
}
|
||||
info->onion_key = tok->key;
|
||||
tok->key = NULL; /* Prevent free */
|
||||
/* Parse service key. */
|
||||
tok = find_by_keyword(tokens, R_IPO_SERVICE_KEY);
|
||||
if (!crypto_pk_public_exponent_ok(tok->key)) {
|
||||
log_warn(LD_REND,
|
||||
"Introduction point key had invalid exponent.");
|
||||
rend_intro_point_free(intro);
|
||||
goto err;
|
||||
}
|
||||
intro->intro_key = tok->key;
|
||||
tok->key = NULL; /* Prevent free */
|
||||
/* Add extend info to list of introduction points. */
|
||||
smartlist_add(parsed->intro_nodes, intro);
|
||||
}
|
||||
result = smartlist_len(parsed->intro_nodes);
|
||||
goto done;
|
||||
|
||||
err:
|
||||
result = -1;
|
||||
|
||||
done:
|
||||
/* Free tokens and clear token list. */
|
||||
if (tokens) {
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
|
||||
smartlist_free(tokens);
|
||||
}
|
||||
if (area)
|
||||
memarea_drop_all(area);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Parse the content of a client_key file in <b>ckstr</b> and add
|
||||
* rend_authorized_client_t's for each parsed client to
|
||||
* <b>parsed_clients</b>. Return the number of parsed clients as result
|
||||
* or -1 for failure. */
|
||||
int
|
||||
rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr)
|
||||
{
|
||||
int result = -1;
|
||||
smartlist_t *tokens;
|
||||
directory_token_t *tok;
|
||||
const char *current_entry = NULL;
|
||||
memarea_t *area = NULL;
|
||||
char *err_msg = NULL;
|
||||
if (!ckstr || strlen(ckstr) == 0)
|
||||
return -1;
|
||||
tokens = smartlist_new();
|
||||
/* Begin parsing with first entry, skipping comments or whitespace at the
|
||||
* beginning. */
|
||||
area = memarea_new();
|
||||
current_entry = eat_whitespace(ckstr);
|
||||
while (!strcmpstart(current_entry, "client-name ")) {
|
||||
rend_authorized_client_t *parsed_entry;
|
||||
/* Determine end of string. */
|
||||
const char *eos = strstr(current_entry, "\nclient-name ");
|
||||
if (!eos)
|
||||
eos = current_entry + strlen(current_entry);
|
||||
else
|
||||
eos = eos + 1;
|
||||
/* Free tokens and clear token list. */
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
|
||||
smartlist_clear(tokens);
|
||||
memarea_clear(area);
|
||||
/* Tokenize string. */
|
||||
if (tokenize_string(area, current_entry, eos, tokens,
|
||||
client_keys_token_table, 0)) {
|
||||
log_warn(LD_REND, "Error tokenizing client keys file.");
|
||||
goto err;
|
||||
}
|
||||
/* Advance to next entry, if available. */
|
||||
current_entry = eos;
|
||||
/* Check minimum allowed length of token list. */
|
||||
if (smartlist_len(tokens) < 2) {
|
||||
log_warn(LD_REND, "Impossibly short client key entry.");
|
||||
goto err;
|
||||
}
|
||||
/* Parse client name. */
|
||||
tok = find_by_keyword(tokens, C_CLIENT_NAME);
|
||||
tor_assert(tok == smartlist_get(tokens, 0));
|
||||
tor_assert(tok->n_args == 1);
|
||||
|
||||
if (!rend_valid_client_name(tok->args[0])) {
|
||||
log_warn(LD_CONFIG, "Illegal client name: %s. (Length must be "
|
||||
"between 1 and %d, and valid characters are "
|
||||
"[A-Za-z0-9+-_].)", tok->args[0], REND_CLIENTNAME_MAX_LEN);
|
||||
goto err;
|
||||
}
|
||||
/* Check if client name is duplicate. */
|
||||
if (strmap_get(parsed_clients, tok->args[0])) {
|
||||
log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains a "
|
||||
"duplicate client name: '%s'. Ignoring.", tok->args[0]);
|
||||
goto err;
|
||||
}
|
||||
parsed_entry = tor_malloc_zero(sizeof(rend_authorized_client_t));
|
||||
parsed_entry->client_name = tor_strdup(tok->args[0]);
|
||||
strmap_set(parsed_clients, parsed_entry->client_name, parsed_entry);
|
||||
/* Parse client key. */
|
||||
tok = find_opt_by_keyword(tokens, C_CLIENT_KEY);
|
||||
if (tok) {
|
||||
parsed_entry->client_key = tok->key;
|
||||
tok->key = NULL; /* Prevent free */
|
||||
}
|
||||
|
||||
/* Parse descriptor cookie. */
|
||||
tok = find_by_keyword(tokens, C_DESCRIPTOR_COOKIE);
|
||||
tor_assert(tok->n_args == 1);
|
||||
if (rend_auth_decode_cookie(tok->args[0], parsed_entry->descriptor_cookie,
|
||||
NULL, &err_msg) < 0) {
|
||||
tor_assert(err_msg);
|
||||
log_warn(LD_REND, "%s", err_msg);
|
||||
tor_free(err_msg);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
result = strmap_size(parsed_clients);
|
||||
goto done;
|
||||
err:
|
||||
result = -1;
|
||||
done:
|
||||
/* Free tokens and clear token list. */
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
|
||||
smartlist_free(tokens);
|
||||
if (area)
|
||||
memarea_drop_all(area);
|
||||
return result;
|
||||
}
|
32
src/feature/rend/rendparse.h
Normal file
32
src/feature/rend/rendparse.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* 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 rend_parse.h
|
||||
* \brief Header file for rend_parse.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_REND_PARSE_H
|
||||
#define TOR_REND_PARSE_H
|
||||
|
||||
int rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
|
||||
char *desc_id_out,
|
||||
char **intro_points_encrypted_out,
|
||||
size_t *intro_points_encrypted_size_out,
|
||||
size_t *encoded_size_out,
|
||||
const char **next_out, const char *desc,
|
||||
int as_hsdir);
|
||||
int rend_decrypt_introduction_points(char **ipos_decrypted,
|
||||
size_t *ipos_decrypted_size,
|
||||
const char *descriptor_cookie,
|
||||
const char *ipos_encrypted,
|
||||
size_t ipos_encrypted_size);
|
||||
int rend_parse_introduction_points(rend_service_descriptor_t *parsed,
|
||||
const char *intro_points_encoded,
|
||||
size_t intro_points_encoded_size);
|
||||
int rend_parse_client_keys(strmap_t *parsed_clients, const char *str);
|
||||
|
||||
#endif
|
@ -31,10 +31,10 @@
|
||||
#include "feature/nodelist/nickname.h"
|
||||
#include "feature/nodelist/node_select.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/nodelist/routerset.h"
|
||||
#include "feature/rend/rendclient.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendparse.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "feature/stats/predict_ports.h"
|
||||
#include "lib/crypt_ops/crypto_dh.h"
|
||||
|
@ -1,8 +1,10 @@
|
||||
/* Copyright (c) 2016-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
#define ROUTERPARSE_PRIVATE
|
||||
#define SIGCOMMON_PRIVATE
|
||||
#include "core/or/or.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/ns_parse.h"
|
||||
#include "feature/dirparse/sigcommon.h"
|
||||
#include "feature/dirparse/unparseable.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "lib/crypt_ops/crypto_ed25519.h"
|
||||
#include "feature/nodelist/networkstatus_st.h"
|
||||
|
@ -1,8 +1,10 @@
|
||||
/* Copyright (c) 2016-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
#define ROUTERPARSE_PRIVATE
|
||||
#define SIGCOMMON_PRIVATE
|
||||
#include "core/or/or.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/routerparse.h"
|
||||
#include "feature/dirparse/sigcommon.h"
|
||||
#include "feature/dirparse/unparseable.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/torcert.h"
|
||||
#include "feature/keymgt/loadkey.h"
|
||||
|
@ -1,8 +1,10 @@
|
||||
/* Copyright (c) 2016-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
#define ROUTERPARSE_PRIVATE
|
||||
#define SIGCOMMON_PRIVATE
|
||||
#include "core/or/or.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/routerparse.h"
|
||||
#include "feature/dirparse/sigcommon.h"
|
||||
#include "feature/dirparse/unparseable.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/relay/routerkeys.h"
|
||||
#include "test/fuzz/fuzzing.h"
|
||||
|
@ -1,9 +1,9 @@
|
||||
/* Copyright (c) 2016-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
#define ROUTERPARSE_PRIVATE
|
||||
#include "core/or/or.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/unparseable.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendparse.h"
|
||||
#include "lib/crypt_ops/crypto_ed25519.h"
|
||||
#include "test/fuzz/fuzzing.h"
|
||||
|
||||
|
@ -1,14 +1,13 @@
|
||||
/* Copyright (c) 2017-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#define ROUTERPARSE_PRIVATE
|
||||
#define HS_DESCRIPTOR_PRIVATE
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "trunnel/ed25519_cert.h" /* Trunnel interface. */
|
||||
#include "lib/crypt_ops/crypto_ed25519.h"
|
||||
#include "feature/hs/hs_descriptor.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/unparseable.h"
|
||||
|
||||
#include "test/fuzz/fuzzing.h"
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
/* Copyright (c) 2016-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
#define ROUTERPARSE_PRIVATE
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/unparseable.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendparse.h"
|
||||
#include "lib/crypt_ops/crypto_ed25519.h"
|
||||
|
||||
#include "feature/rend/rend_service_descriptor_st.h"
|
||||
|
@ -1,8 +1,9 @@
|
||||
/* Copyright (c) 2016-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
#define ROUTERPARSE_PRIVATE
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/microdesc_parse.h"
|
||||
#include "feature/dirparse/unparseable.h"
|
||||
#include "feature/nodelist/microdesc.h"
|
||||
#include "lib/crypt_ops/crypto_ed25519.h"
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
/* Copyright (c) 2016-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
#define ROUTERPARSE_PRIVATE
|
||||
#define NS_PARSE_PRIVATE
|
||||
#define NETWORKSTATUS_PRIVATE
|
||||
#include "core/or/or.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/ns_parse.h"
|
||||
#include "feature/dirparse/unparseable.h"
|
||||
#include "lib/memarea/memarea.h"
|
||||
#include "feature/nodelist/microdesc.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "core/or/connection_edge.h"
|
||||
#include "feature/rend/rendcommon.h"
|
||||
#include "feature/rend/rendcache.h"
|
||||
#include "feature/rend/rendparse.h"
|
||||
#include "test/test.h"
|
||||
#include "core/mainloop/mainloop.h"
|
||||
#include "lib/memarea/memarea.h"
|
||||
@ -54,7 +55,6 @@
|
||||
#include "core/crypto/onion_tap.h"
|
||||
#include "core/or/policies.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "app/config/statefile.h"
|
||||
#include "lib/crypt_ops/crypto_curve25519.h"
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "core/mainloop/cpuworker.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/ns_parse.h"
|
||||
#include "lib/evloop/workqueue.h"
|
||||
#include "lib/compress/compress.h"
|
||||
#include "lib/encoding/confline.h"
|
||||
|
@ -16,11 +16,12 @@
|
||||
#define DLSTATUS_PRIVATE
|
||||
#define HIBERNATE_PRIVATE
|
||||
#define NETWORKSTATUS_PRIVATE
|
||||
#define NS_PARSE_PRIVATE
|
||||
#define NODE_SELECT_PRIVATE
|
||||
#define RELAY_PRIVATE
|
||||
#define ROUTERLIST_PRIVATE
|
||||
#define ROUTERPARSE_PRIVATE
|
||||
#define ROUTER_PRIVATE
|
||||
#define UNPARSEABLE_PRIVATE
|
||||
#define VOTEFLAGS_PRIVATE
|
||||
|
||||
#include "core/or/or.h"
|
||||
@ -28,11 +29,13 @@
|
||||
#include "app/config/confparse.h"
|
||||
#include "core/mainloop/connection.h"
|
||||
#include "core/or/relay.h"
|
||||
#include "core/or/versions.h"
|
||||
#include "feature/client/bridges.h"
|
||||
#include "feature/client/entrynodes.h"
|
||||
#include "feature/control/control.h"
|
||||
#include "feature/dirauth/bwauth.h"
|
||||
#include "feature/dirauth/dirvote.h"
|
||||
#include "feature/dirauth/dsigs_parse.h"
|
||||
#include "feature/dirauth/process_descs.h"
|
||||
#include "feature/dirauth/recommend_pkg.h"
|
||||
#include "feature/dirauth/shared_random_state.h"
|
||||
@ -51,7 +54,10 @@
|
||||
#include "feature/nodelist/nickname.h"
|
||||
#include "feature/nodelist/node_select.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/authcert_parse.h"
|
||||
#include "feature/dirparse/ns_parse.h"
|
||||
#include "feature/dirparse/routerparse.h"
|
||||
#include "feature/dirparse/unparseable.h"
|
||||
#include "feature/nodelist/routerset.h"
|
||||
#include "feature/nodelist/torcert.h"
|
||||
#include "feature/relay/router.h"
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include "feature/dirauth/dirvote.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/dirparse/authcert_parse.h"
|
||||
#include "feature/dirparse/ns_parse.h"
|
||||
#include "test/test_dir_common.h"
|
||||
#include "feature/dircommon/voting_schedule.h"
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
|
||||
#define TEST_DIR_ROUTER_ID_1 3
|
||||
#define TEST_DIR_ROUTER_ID_2 5
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "test/test_helpers.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/client/entrynodes.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/authcert_parse.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "core/proto/proto_http.h"
|
||||
#include "lib/geoip/geoip.h"
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "core/or/policies.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/nodelist/routerset.h"
|
||||
#include "app/config/statefile.h"
|
||||
|
||||
|
@ -2,15 +2,15 @@
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#define GUARDFRACTION_PRIVATE
|
||||
#define ROUTERPARSE_PRIVATE
|
||||
#define NETWORKSTATUS_PRIVATE
|
||||
#define NS_PARSE_PRIVATE
|
||||
|
||||
#include "orconfig.h"
|
||||
#include "core/or/or.h"
|
||||
#include "app/config/config.h"
|
||||
#include "feature/dirauth/guardfraction.h"
|
||||
#include "feature/client/entrynodes.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/ns_parse.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
|
||||
#include "feature/nodelist/networkstatus_st.h"
|
||||
|
@ -21,7 +21,6 @@
|
||||
#define STATEFILE_PRIVATE
|
||||
#define TOR_CHANNEL_INTERNAL_
|
||||
#define HS_CLIENT_PRIVATE
|
||||
#define ROUTERPARSE_PRIVATE
|
||||
|
||||
#include "test/test.h"
|
||||
#include "test/test_helpers.h"
|
||||
@ -31,33 +30,33 @@
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "app/config/config.h"
|
||||
#include "app/config/statefile.h"
|
||||
#include "core/crypto/hs_ntor.h"
|
||||
#include "core/mainloop/connection.h"
|
||||
#include "core/mainloop/mainloop.h"
|
||||
#include "core/or/circuitbuild.h"
|
||||
#include "core/or/circuitlist.h"
|
||||
#include "core/or/circuituse.h"
|
||||
#include "core/mainloop/connection.h"
|
||||
#include "core/or/connection_edge.h"
|
||||
#include "core/or/edge_connection_st.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "lib/fs/dir.h"
|
||||
#include "feature/dirauth/dirvote.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "core/or/relay.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "core/or/versions.h"
|
||||
#include "feature/dirauth/dirvote.h"
|
||||
#include "feature/dirauth/shared_random_state.h"
|
||||
#include "feature/dircommon/voting_schedule.h"
|
||||
#include "feature/hs/hs_circuit.h"
|
||||
#include "feature/hs/hs_circuitmap.h"
|
||||
#include "feature/hs/hs_client.h"
|
||||
#include "feature/hs/hs_common.h"
|
||||
#include "feature/hs/hs_config.h"
|
||||
#include "feature/hs/hs_ident.h"
|
||||
#include "feature/hs/hs_intropoint.h"
|
||||
#include "core/crypto/hs_ntor.h"
|
||||
#include "feature/hs/hs_circuit.h"
|
||||
#include "feature/hs/hs_circuitmap.h"
|
||||
#include "feature/hs/hs_service.h"
|
||||
#include "feature/hs/hs_client.h"
|
||||
#include "core/mainloop/mainloop.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/rend/rendservice.h"
|
||||
#include "app/config/statefile.h"
|
||||
#include "feature/dirauth/shared_random_state.h"
|
||||
#include "feature/dircommon/voting_schedule.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "lib/fs/dir.h"
|
||||
|
||||
#include "core/or/cpath_build_state_st.h"
|
||||
#include "core/or/crypt_path_st.h"
|
||||
|
@ -4,13 +4,14 @@
|
||||
#include "orconfig.h"
|
||||
#include "core/or/or.h"
|
||||
|
||||
#include "app/config/config.h"
|
||||
#define DIRVOTE_PRIVATE
|
||||
#include "app/config/config.h"
|
||||
#include "feature/dirauth/dirvote.h"
|
||||
#include "feature/dirparse/microdesc_parse.h"
|
||||
#include "feature/dirparse/routerparse.h"
|
||||
#include "feature/nodelist/microdesc.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/nodelist/torcert.h"
|
||||
|
||||
#include "feature/nodelist/microdesc_st.h"
|
||||
|
@ -1,19 +1,20 @@
|
||||
/* Copyright (c) 2013-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#include "core/or/or.h"
|
||||
#define CONFIG_PRIVATE
|
||||
#include "app/config/config.h"
|
||||
#include "feature/relay/router.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#define POLICIES_PRIVATE
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "app/config/config.h"
|
||||
#include "core/or/policies.h"
|
||||
#include "feature/dirparse/policy_parse.h"
|
||||
#include "feature/relay/router.h"
|
||||
#include "lib/encoding/confline.h"
|
||||
#include "test/test.h"
|
||||
|
||||
#include "core/or/addr_policy_st.h"
|
||||
#include "feature/nodelist/node_st.h"
|
||||
#include "core/or/port_cfg_st.h"
|
||||
#include "feature/nodelist/node_st.h"
|
||||
#include "feature/nodelist/routerinfo_st.h"
|
||||
#include "feature/nodelist/routerstatus_st.h"
|
||||
|
||||
|
@ -33,7 +33,8 @@
|
||||
#include "feature/nodelist/node_select.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/nodelist/routerset.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/authcert_parse.h"
|
||||
#include "feature/dirparse/ns_parse.h"
|
||||
#include "feature/dirauth/shared_random.h"
|
||||
#include "app/config/statefile.h"
|
||||
|
||||
|
@ -4,11 +4,11 @@
|
||||
#define ROUTERSET_PRIVATE
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "lib/geoip/geoip.h"
|
||||
#include "feature/nodelist/routerset.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "core/or/policies.h"
|
||||
#include "feature/dirparse/policy_parse.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerset.h"
|
||||
#include "lib/geoip/geoip.h"
|
||||
|
||||
#include "core/or/addr_policy_st.h"
|
||||
#include "core/or/extend_info_st.h"
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "feature/relay/routerkeys.h"
|
||||
#include "feature/nodelist/authcert.h"
|
||||
#include "feature/nodelist/dirlist.h"
|
||||
#include "feature/nodelist/routerparse.h"
|
||||
#include "feature/dirparse/authcert_parse.h"
|
||||
#include "feature/hs_common/shared_random_client.h"
|
||||
#include "feature/dircommon/voting_schedule.h"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user