aboutsummaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2018-10-12 11:39:37 -0400
committerNick Mathewson <nickm@torproject.org>2018-10-12 11:39:37 -0400
commit67351f672450d5f13754294405243a59ddd86de9 (patch)
tree016368ae0c3b6e56c0dc03c185fe5a095d72f22e /src/core
parent391756f262c93d4361fb6189a3ba9704283f73aa (diff)
parenta1504f138d978d73b2c6129957dd0ee344a97efa (diff)
downloadtor-67351f672450d5f13754294405243a59ddd86de9.tar.gz
tor-67351f672450d5f13754294405243a59ddd86de9.zip
Merge remote-tracking branch 'tor-github/pr/380'
Diffstat (limited to 'src/core')
-rw-r--r--src/core/include.am29
-rw-r--r--src/core/mainloop/connection.c3
-rw-r--r--src/core/or/circuitbuild.c1
-rw-r--r--src/core/or/policies.c4
-rw-r--r--src/core/or/protover.c2
-rw-r--r--src/core/or/relay.c1
-rw-r--r--src/core/or/versions.c422
-rw-r--r--src/core/or/versions.h44
8 files changed, 495 insertions, 11 deletions
diff --git a/src/core/include.am b/src/core/include.am
index e51819fa20..1b8ef2ac58 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 \
@@ -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 \
diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c
index ef8c60a3da..3f3b13e069 100644
--- a/src/core/mainloop/connection.c
+++ b/src/core/mainloop/connection.c
@@ -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"
diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c
index 822129d80e..a69457571e 100644
--- a/src/core/or/circuitbuild.c
+++ b/src/core/or/circuitbuild.c
@@ -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"
diff --git a/src/core/or/policies.c b/src/core/or/policies.c
index c3fded1fbd..0eda93c5f3 100644
--- a/src/core/or/policies.c
+++ b/src/core/or/policies.c
@@ -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"
diff --git a/src/core/or/protover.c b/src/core/or/protover.c
index f0791366fe..e80fbfae81 100644
--- a/src/core/or/protover.c
+++ b/src/core/or/protover.c
@@ -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
diff --git a/src/core/or/relay.c b/src/core/or/relay.c
index 9e45a35246..510d96c648 100644
--- a/src/core/or/relay.c
+++ b/src/core/or/relay.c
@@ -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"
diff --git a/src/core/or/versions.c b/src/core/or/versions.c
new file mode 100644
index 0000000000..06274996a7
--- /dev/null
+++ b/src/core/or/versions.c
@@ -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;
+ }
+ }
+ }
+}
diff --git a/src/core/or/versions.h b/src/core/or/versions.h
new file mode 100644
index 0000000000..0c773f3f4c
--- /dev/null
+++ b/src/core/or/versions.h
@@ -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) */