Commit 67351f67 authored by Nick Mathewson's avatar Nick Mathewson 🎨
Browse files

Merge remote-tracking branch 'tor-github/pr/380'

parents 391756f2 a1504f13
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"
......
/* 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;
}
}
}
}
/* Copyright (c) 2001 Matej Pfajfar.