From 94782444f80f483bafebf537b059f2d8a8e0cdd2 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 1 Jun 2004 18:19:01 +0000 Subject: [PATCH] Check recommended-software string *early*, before actually parsing the directory. svn:r1930 --- doc/TODO | 2 +- src/or/or.h | 3 ++ src/or/routerlist.c | 36 +------------------ src/or/routerparse.c | 83 ++++++++++++++++++++++++++++++++++++++++++++ src/or/test.c | 4 +-- 5 files changed, 90 insertions(+), 38 deletions(-) diff --git a/doc/TODO b/doc/TODO index b14f8cbf03..287207be6c 100644 --- a/doc/TODO +++ b/doc/TODO @@ -23,7 +23,7 @@ For 0.0.7: D try to break apart the main clump of functions better. o rend_services_introduce should check if it's failed a lot recently, and not try for a while if so - - check tor version as soon as you get the recommended-versions + o check tor version as soon as you get the recommended-versions string, regardless of whether parsing the directory succeeded. - make all ORs serve the directory too. diff --git a/src/or/or.h b/src/or/or.h index 6c4c5eff75..eb9ee85a5a 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1334,6 +1334,9 @@ int router_parse_routerlist_from_directory(const char *s, routerinfo_t *router_parse_entry_from_string(const char *s, const char *end); int router_add_exit_policy_from_string(routerinfo_t *router, const char *s); struct exit_policy_t *router_parse_exit_policy_from_string(const char *s); +int check_software_version_against_directory(const char *directory, + int ignoreversion); + #endif diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 98cd402b1c..b2cc910fc1 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -445,34 +445,13 @@ int router_load_routerlist_from_string(const char *s, int trusted) return 0; } -/** Return 1 if myversion is in versionlist. Else return 0. - * (versionlist is a comma-separated list of versions.) */ -int is_recommended_version(const char *myversion, - const char *versionlist) { - int len_myversion = strlen(myversion); - char *comma; - const char *end = versionlist + strlen(versionlist); - - log_fn(LOG_DEBUG,"checking '%s' in '%s'.", myversion, versionlist); - - for(;;) { - comma = strchr(versionlist, ','); - if( ((comma ? comma : end) - versionlist == len_myversion) && - !strncmp(versionlist, myversion, len_myversion)) - /* only do strncmp if the length matches */ - return 1; /* success, it's there */ - if(!comma) - return 0; /* nope */ - versionlist = comma+1; - } -} - /** Add to the current routerlist each router stored in the * signed directory s. If pkey is provided, make sure that s is * signed with pkey. */ int router_load_routerlist_from_directory(const char *s, crypto_pk_env_t *pkey) { routerlist_t *new_list = NULL; + check_software_version_against_directory(s, options.IgnoreVersion); if (router_parse_routerlist_from_directory(s, &new_list, pkey)) { log_fn(LOG_WARN, "Couldn't parse directory."); return -1; @@ -493,19 +472,6 @@ int router_load_routerlist_from_directory(const char *s, crypto_pk_env_t *pkey) log_fn(LOG_WARN, "Error resolving routerlist"); return -1; } - if (!is_recommended_version(VERSION, routerlist->software_versions)) { - log(options.IgnoreVersion ? LOG_WARN : LOG_ERR, - "You are running Tor version %s, which will not work with this network.\n" - "Please use %s%s.", - VERSION, strchr(routerlist->software_versions,',') ? "one of " : "", - routerlist->software_versions); - if(options.IgnoreVersion) { - log(LOG_WARN, "IgnoreVersion is set. If it breaks, we told you so."); - } else { - fflush(0); - exit(0); - } - } return 0; } diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 6b227fcddf..c239a613e2 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -176,6 +176,89 @@ static int parse_time(const char *cp, time_t *t) return 0; } +/** + * Find the first instance of "recommended-software ...\n" at the start of + * a line; return a newly allocated string containing the "..." portion. + * Return NULL if no such instance was found. + */ +static char * +get_recommended_software_from_directory(const char *str) +{ +#define REC "recommended-software " + const char *cp = str, *eol; + int len = strlen(REC); + cp = str; + if (strncmp(str, REC, len)==0) { + cp += len; + } else { + cp = strstr(str, "\n"REC); + if (!cp) + return NULL; + cp += len+1; + } + eol = strchr(cp, '\n'); + if (!eol) + return NULL; + return tor_strndup(cp, eol-cp); +#undef REC +} + +/** Return 1 if myversion is in versionlist. Else return 0. + * (versionlist is a comma-separated list of versions.) */ +/* static */ int is_recommended_version(const char *myversion, + const char *versionlist) { + int len_myversion = strlen(myversion); + char *comma; + const char *end = versionlist + strlen(versionlist); + + log_fn(LOG_DEBUG,"checking '%s' in '%s'.", myversion, versionlist); + + for(;;) { + comma = strchr(versionlist, ','); + if( ((comma ? comma : end) - versionlist == len_myversion) && + !strncmp(versionlist, myversion, len_myversion)) + /* only do strncmp if the length matches */ + return 1; /* success, it's there */ + if(!comma) + return 0; /* nope */ + versionlist = comma+1; + } +} + +/* Return 0 if myversion is supported; else log a message and return + * -1 (or exit if ignoreversions is false) */ +int check_software_version_against_directory(const char *directory, + int ignoreversion) +{ + char *v; + v = get_recommended_software_from_directory(directory); + if (!v) { + log_fn(LOG_WARN, "No recommended-versions string found in directory"); + return -1; + } + /* Look for versions of the form "0.1.0" and of the form "Tor 0.1.0". + * Eventually, we should deprecate the first form. + */ + if (is_recommended_version(VERSION, v) || + is_recommended_version("Tor "VERSION, v)) { + tor_free(v); + return 0; + } + log(ignoreversion ? LOG_WARN : LOG_ERR, + "You are running Tor version %s, which will not work with this network.\n" + "Please use %s%s.", + VERSION, strchr(v,',') ? "one of " : "", v); + tor_free(v); + + if(ignoreversion) { + log(LOG_WARN, "IgnoreVersion is set. If it breaks, we told you so."); + return -1; + } else { + fflush(0); + exit(0); + return -1; /* never reached */ + } +} /** Parse a directory from s and, when done, store the * resulting routerlist in *dest, freeing the old value if necessary. diff --git a/src/or/test.c b/src/or/test.c index 864645b5d0..70b0b5554d 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -635,8 +635,8 @@ test_onion_handshake() { crypto_free_pk_env(pk); } -/* from routers.c */ -int is_recommended_version(char *myversion, char *start); +/* from routerparse.c */ +int is_recommended_version(const char *myversion, const char *start); void test_dir_format()