diff options
author | Nick Mathewson <nickm@torproject.org> | 2018-09-30 18:27:23 -0500 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2018-10-01 00:04:58 -0500 |
commit | 2f5dc486993b88eb23de7f06043991f08e4d0d73 (patch) | |
tree | d56ea5c1cd515f0ce635812f6ec6974d8b337d4a /src | |
parent | fec3b3bb9389d9d9f927c370d560fc50ec65c93b (diff) | |
download | tor-2f5dc486993b88eb23de7f06043991f08e4d0d73.tar.gz tor-2f5dc486993b88eb23de7f06043991f08e4d0d73.zip |
Extract the version-managing code from routerparse.c
Leave the versions.h include in routerparse.h for now; I'll remove
it later.
Diffstat (limited to 'src')
-rw-r--r-- | src/core/include.am | 2 | ||||
-rw-r--r-- | src/core/or/versions.c | 377 | ||||
-rw-r--r-- | src/core/or/versions.h | 40 | ||||
-rw-r--r-- | src/feature/dirparse/routerparse.c | 364 | ||||
-rw-r--r-- | src/feature/dirparse/routerparse.h | 25 |
5 files changed, 421 insertions, 387 deletions
diff --git a/src/core/include.am b/src/core/include.am index 45f4cb5c4e..c1f63c751e 100644 --- a/src/core/include.am +++ b/src/core/include.am @@ -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 \ @@ -241,6 +242,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 \ diff --git a/src/core/or/versions.c b/src/core/or/versions.c new file mode 100644 index 0000000000..2d24862981 --- /dev/null +++ b/src/core/or/versions.c @@ -0,0 +1,377 @@ +/* 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/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_); +} diff --git a/src/core/or/versions.h b/src/core/or/versions.h new file mode 100644 index 0000000000..a2353bcae3 --- /dev/null +++ b/src/core/or/versions.h @@ -0,0 +1,40 @@ +/* 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); + +#endif /* !defined(TOR_VERSIONS_H) */ diff --git a/src/feature/dirparse/routerparse.c b/src/feature/dirparse/routerparse.c index 83890cdb97..5ff5fdf231 100644 --- a/src/feature/dirparse/routerparse.c +++ b/src/feature/dirparse/routerparse.c @@ -108,9 +108,6 @@ #undef log #include <math.h> -//#ifdef HAVE_SYS_STAT_H -//#include <sys/stat.h> -//#endif /****************************************************************************/ @@ -586,85 +583,6 @@ router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest, return 0; } -/** 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; -} - MOCK_IMPL(STATIC int, signed_digest_equals, (const uint8_t *d1, const uint8_t *d2, size_t len)) { @@ -4276,288 +4194,6 @@ microdescs_parse_from_string(const char *s, const char *eos, return result; } -/** 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_); -} - /** 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 diff --git a/src/feature/dirparse/routerparse.h b/src/feature/dirparse/routerparse.h index 51d39c6175..6f1af4016b 100644 --- a/src/feature/dirparse/routerparse.h +++ b/src/feature/dirparse/routerparse.h @@ -12,19 +12,7 @@ #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; +#include "core/or/versions.h" enum networkstatus_type_t; @@ -65,16 +53,7 @@ extrainfo_t *extrainfo_parse_entry_from_string(const char *s, const char *end, 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); |