diff options
author | Nick Mathewson <nickm@torproject.org> | 2017-02-15 07:48:42 -0500 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2017-02-15 07:48:42 -0500 |
commit | 76d79d597aeba1d9182414acf038ed376cd5139c (patch) | |
tree | 4a666199c7c3d186060a162d86a9d82b0044ce3e /src/or/routerparse.c | |
parent | dec7dc3d823a8a9cc1d9d75d1b803a6e6b308a8e (diff) | |
parent | 5d88267bf47fb532b53691ab428cbfd9db3881cf (diff) | |
download | tor-76d79d597aeba1d9182414acf038ed376cd5139c.tar.gz tor-76d79d597aeba1d9182414acf038ed376cd5139c.zip |
Merge branch 'maint-0.2.9'
Diffstat (limited to 'src/or/routerparse.c')
-rw-r--r-- | src/or/routerparse.c | 121 |
1 files changed, 85 insertions, 36 deletions
diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 58b9a22438..22c9a61080 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -4785,40 +4785,78 @@ microdescs_parse_from_string(const char *s, const char *eos, return result; } -/** 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. +/** 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_as_new_as(const char *platform, const char *cutoff) +tor_version_parse_platform(const char *platform, + tor_version_t *router_version, + int strict) { - tor_version_t cutoff_version, router_version; - char *s, *s2, *start; char tmp[128]; + char *s, *s2, *start; - tor_assert(platform); - - if (tor_version_parse(cutoff, &cutoff_version)<0) { - log_warn(LD_BUG,"cutoff version '%s' unparseable.",cutoff); + if (strcmpstart(platform,"Tor ")) /* nonstandard Tor; say 0. */ return 0; - } - if (strcmpstart(platform,"Tor ")) /* nonstandard Tor; be safe and say yes */ - return 1; start = (char *)eat_whitespace(platform+3); - if (!*start) return 0; + 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 0; + return -1; strlcpy(tmp, start, s-start+1); - if (tor_version_parse(tmp, &router_version)<0) { + if (tor_version_parse(tmp, router_version)<0) { log_info(LD_DIR,"Router version '%s' unparseable.",tmp); - return 1; /* be safe and say yes */ + return -1; + } + + if (strict) { + if (router_version->major < 0 || + router_version->minor < 0 || + router_version->minor < 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: @@ -4945,26 +4983,37 @@ tor_version_compare(tor_version_t *a, tor_version_t *b) int i; tor_assert(a); tor_assert(b); - if ((i = a->major - b->major)) - return i; - else if ((i = a->minor - b->minor)) - return i; - else if ((i = a->micro - b->micro)) - return i; - else if ((i = a->status - b->status)) - return i; - else if ((i = a->patchlevel - b->patchlevel)) - return i; - else if ((i = strcmp(a->status_tag, b->status_tag))) - return i; - else if ((i = a->svn_revision - b->svn_revision)) - return i; - else if ((i = a->git_tag_len - b->git_tag_len)) - return i; - else if (a->git_tag_len) - return fast_memcmp(a->git_tag, b->git_tag, a->git_tag_len); + + /* 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; + return 0; + +#undef CMP } /** Return true iff versions <b>a</b> and <b>b</b> belong to the same series. |