From c83d83814660b643b705ed7de4aa1fc35e2d20ad Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 9 Jan 2015 11:36:47 -0500 Subject: Implement proposal 227-vote-on-package-fingerprints.txt This implementation includes tests and a little documentation. --- src/or/config.c | 9 +++++ src/or/dirserv.c | 51 +++++++++++++++++++++++++++ src/or/dirserv.h | 2 ++ src/or/dirvote.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++- src/or/dirvote.h | 6 +++- src/or/networkstatus.c | 4 +++ src/or/or.h | 4 +++ src/or/routerparse.c | 12 +++++++ 8 files changed, 179 insertions(+), 2 deletions(-) (limited to 'src/or') diff --git a/src/or/config.c b/src/or/config.c index 2fa077e146..ab48bac50b 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -73,6 +73,7 @@ static config_abbrev_t option_abbrevs_[] = { PLURAL(HiddenServiceExcludeNode), PLURAL(NumCPU), PLURAL(RendNode), + PLURAL(RecommendedPackage), PLURAL(RendExcludeNode), PLURAL(StrictEntryNode), PLURAL(StrictExitNode), @@ -352,6 +353,7 @@ static config_var_t option_vars_[] = { V(RecommendedVersions, LINELIST, NULL), V(RecommendedClientVersions, LINELIST, NULL), V(RecommendedServerVersions, LINELIST, NULL), + V(RecommendedPackages, LINELIST, NULL), V(RefuseUnknownExits, AUTOBOOL, "auto"), V(RejectPlaintextPorts, CSV, ""), V(RelayBandwidthBurst, MEMUNIT, "0"), @@ -2725,6 +2727,13 @@ options_validate(or_options_t *old_options, or_options_t *options, "features to be broken in unpredictable ways."); } + for (cl = options->RecommendedPackages; cl; cl = cl->next) { + if (! validate_recommended_package_line(cl->value)) { + log_warn(LD_CONFIG, "Invalid RecommendedPackage line %s will be ignored", + escaped(cl->value)); + } + } + if (options->AuthoritativeDir) { if (!options->ContactInfo && !options->TestingTorNetwork) REJECT("Authoritative directory servers must set ContactInfo"); diff --git a/src/or/dirserv.c b/src/or/dirserv.c index d668749c5b..dbdfff1440 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -2504,6 +2504,15 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, v3_out->client_versions = client_versions; v3_out->server_versions = server_versions; + v3_out->package_lines = smartlist_new(); + { + config_line_t *cl; + for (cl = get_options()->RecommendedPackages; cl; cl = cl->next) { + if (validate_recommended_package_line(cl->value)) + smartlist_add(v3_out->package_lines, tor_strdup(cl->value)); + } + } + v3_out->known_flags = smartlist_new(); smartlist_split_string(v3_out->known_flags, "Authority Exit Fast Guard Stable V2Dir Valid", @@ -3249,6 +3258,48 @@ connection_dirserv_flushed_some(dir_connection_t *conn) } } +/** Return true iff line is a valid recommened_packages line. + */ +int +validate_recommended_package_line(const char *line) +{ + const char *cp = line; + +#define WORD() \ + do { \ + if (*cp == ' ') \ + return 0; \ + cp = strchr(cp, ' '); \ + if (!cp) \ + return 0; \ + } while (0) + + WORD(); /* skip packagename */ + ++cp; + WORD(); /* skip version */ + ++cp; + WORD(); /* Skip URL */ + ++cp; + + /* Skip digestname=digestval + */ + int foundeq = 0; + while (*cp) { + if (*cp == ' ') { + if (!foundeq) + return 0; + foundeq = 0; + } else if (*cp == '=') { + if (++foundeq > 1) + return 0; + } + ++cp; + } + + if (!foundeq) + return 0; + return 1; +} + /** Release all storage used by the directory server. */ void dirserv_free_all(void) diff --git a/src/or/dirserv.h b/src/or/dirserv.h index d4ce54260c..514ec444e6 100644 --- a/src/or/dirserv.h +++ b/src/or/dirserv.h @@ -104,6 +104,8 @@ void dirserv_free_all(void); void cached_dir_decref(cached_dir_t *d); cached_dir_t *new_cached_dir(char *s, time_t published); +int validate_recommended_package_line(const char *line); + #ifdef DIRSERV_PRIVATE /* Put the MAX_MEASUREMENT_AGE #define here so unit tests can see it */ diff --git a/src/or/dirvote.c b/src/or/dirvote.c index f0dcc88070..c09c4faf7d 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -66,6 +66,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, { smartlist_t *chunks = smartlist_new(); const char *client_versions = NULL, *server_versions = NULL; + char *packages = NULL; char fingerprint[FINGERPRINT_LEN+1]; char digest[DIGEST_LEN]; uint32_t addr; @@ -98,6 +99,18 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, server_versions_line = tor_strdup(""); } + if (v3_ns->package_lines) { + smartlist_t *tmp = smartlist_new(); + SMARTLIST_FOREACH(v3_ns->package_lines, const char *, p, + if (validate_recommended_package_line(p)) + smartlist_add_asprintf(tmp, "package %s\n", p)); + packages = smartlist_join_strings(tmp, "", 0, NULL); + SMARTLIST_FOREACH(tmp, char *, cp, tor_free(cp)); + smartlist_free(tmp); + } else { + packages = tor_strdup(""); + } + { char published[ISO_TIME_LEN+1]; char va[ISO_TIME_LEN+1]; @@ -132,6 +145,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, "valid-until %s\n" "voting-delay %d %d\n" "%s%s" /* versions */ + "%s" /* packages */ "known-flags %s\n" "flag-thresholds %s\n" "params %s\n" @@ -143,6 +157,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, v3_ns->vote_seconds, v3_ns->dist_seconds, client_versions_line, server_versions_line, + packages, flags, flag_thresholds, params, @@ -230,6 +245,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, done: tor_free(client_versions_line); tor_free(server_versions_line); + tor_free(packages); SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); smartlist_free(chunks); @@ -1037,6 +1053,7 @@ networkstatus_compute_consensus(smartlist_t *votes, const routerstatus_format_type_t rs_format = flavor == FLAV_NS ? NS_V3_CONSENSUS : NS_V3_CONSENSUS_MICRODESC; char *params = NULL; + char *packages = NULL; int added_weights = 0; tor_assert(flavor == FLAV_NS || flavor == FLAV_MICRODESC); tor_assert(total_authorities >= smartlist_len(votes)); @@ -1120,6 +1137,11 @@ networkstatus_compute_consensus(smartlist_t *votes, n_versioning_servers); client_versions = compute_consensus_versions_list(combined_client_versions, n_versioning_clients); + if (consensus_method >= MIN_METHOD_FOR_PACKAGE_LINES) { + packages = compute_consensus_package_lines(votes); + } else { + packages = tor_strdup(""); + } SMARTLIST_FOREACH(combined_server_versions, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(combined_client_versions, char *, cp, tor_free(cp)); @@ -1162,10 +1184,13 @@ networkstatus_compute_consensus(smartlist_t *votes, "voting-delay %d %d\n" "client-versions %s\n" "server-versions %s\n" + "%s" /* packages */ "known-flags %s\n", va_buf, fu_buf, vu_buf, vote_seconds, dist_seconds, - client_versions, server_versions, flaglist); + client_versions, server_versions, + packages, + flaglist); tor_free(flaglist); } @@ -1852,6 +1877,7 @@ networkstatus_compute_consensus(smartlist_t *votes, tor_free(client_versions); tor_free(server_versions); + tor_free(packages); SMARTLIST_FOREACH(flags, char *, cp, tor_free(cp)); smartlist_free(flags); SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); @@ -1860,6 +1886,71 @@ networkstatus_compute_consensus(smartlist_t *votes, return result; } +/** DOCDOC */ +STATIC char * +compute_consensus_package_lines(smartlist_t *votes) +{ + const int n_votes = smartlist_len(votes); + strmap_t *package_status = strmap_new(); + smartlist_t *result_list = smartlist_new(); + + SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) { + if (! v->package_lines) + continue; + SMARTLIST_FOREACH_BEGIN(v->package_lines, const char *, line) { + if (! validate_recommended_package_line(line)) + continue; + + const char *cp = strchr(line, ' '); + if (!cp) continue; + ++cp; + cp = strchr(cp, ' '); + if (!cp) continue; + + char *key = tor_strndup(line, cp - line); + + const char **status = strmap_get(package_status, key); + if (!status) { + status = tor_calloc(n_votes, sizeof(const char *)); + strmap_set(package_status, key, status); + } + status[v_sl_idx] = line; /* overwrite old value */ + tor_free(key); + } SMARTLIST_FOREACH_END(line); + } SMARTLIST_FOREACH_END(v); + + smartlist_t *entries = smartlist_new(); + STRMAP_FOREACH(package_status, key, const char **, values) { + int i, count=-1; + for (i = 0; i < n_votes; ++i) { + if (values[i]) + smartlist_add(entries, (void*) values[i]); + } + smartlist_sort_strings(entries); + int n_voting_for_entry = smartlist_len(entries); + const char *most_frequent = + smartlist_get_most_frequent_string_(entries, &count); + + if (n_voting_for_entry >= 3 && count > n_voting_for_entry / 2) { + smartlist_add_asprintf(result_list, "package %s\n", most_frequent); + } + + smartlist_clear(entries); + + } STRMAP_FOREACH_END; + + smartlist_sort_strings(result_list); + + char *result = smartlist_join_strings(result_list, "", 0, NULL); + + SMARTLIST_FOREACH(result_list, char *, cp, tor_free(cp)); + smartlist_free(result_list); + smartlist_free(entries); + strmap_free(package_status, tor_free_); + + return result; +} + /** Given a consensus vote target and a set of detached signatures in * sigs that correspond to the same consensus, check whether there are * any new signatures in src_voter_list that should be added to diff --git a/src/or/dirvote.h b/src/or/dirvote.h index 8908336fa1..20dcbcd5b6 100644 --- a/src/or/dirvote.h +++ b/src/or/dirvote.h @@ -55,7 +55,7 @@ #define MIN_SUPPORTED_CONSENSUS_METHOD 13 /** The highest consensus method that we currently support. */ -#define MAX_SUPPORTED_CONSENSUS_METHOD 18 +#define MAX_SUPPORTED_CONSENSUS_METHOD 19 /** Lowest consensus method where microdesc consensuses omit any entry * with no microdesc. */ @@ -79,6 +79,9 @@ * microdescriptors. */ #define MIN_METHOD_FOR_ID_HASH_IN_MD 18 +/** Lowest consensus method where we include "package" lines*/ +#define MIN_METHOD_FOR_PACKAGE_LINES 19 + /** Default bandwidth to clip unmeasured bandwidths to using method >= * MIN_METHOD_TO_CLIP_UNMEASURED_BW */ #define DEFAULT_MAX_UNMEASURED_BW_KB 20 @@ -160,6 +163,7 @@ STATIC char *format_networkstatus_vote(crypto_pk_t *private_key, networkstatus_t *v3_ns); STATIC char *dirvote_compute_params(smartlist_t *votes, int method, int total_authorities); +STATIC char *compute_consensus_package_lines(smartlist_t *votes); #endif #endif diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 59ba1e6cb7..19c0b21c21 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -257,6 +257,10 @@ networkstatus_vote_free(networkstatus_t *ns) SMARTLIST_FOREACH(ns->supported_methods, char *, c, tor_free(c)); smartlist_free(ns->supported_methods); } + if (ns->package_lines) { + SMARTLIST_FOREACH(ns->package_lines, char *, c, tor_free(c)); + smartlist_free(ns->package_lines); + } if (ns->voters) { SMARTLIST_FOREACH_BEGIN(ns->voters, networkstatus_voter_info_t *, voter) { tor_free(voter->nickname); diff --git a/src/or/or.h b/src/or/or.h index 58e2164665..228738faab 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2456,6 +2456,9 @@ typedef struct networkstatus_t { /** Vote only: what methods is this voter willing to use? */ smartlist_t *supported_methods; + /** List of 'package' lines describing hashes of downloadable pacakges */ + smartlist_t *package_lines; + /** How long does this vote/consensus claim that authorities take to * distribute their votes to one another? */ int vote_seconds; @@ -3498,6 +3501,7 @@ typedef struct { config_line_t *RecommendedVersions; config_line_t *RecommendedClientVersions; config_line_t *RecommendedServerVersions; + config_line_t *RecommendedPackages; /** Whether dirservers allow router descriptors with private IPs. */ int DirAllowPrivateAddresses; /** Whether routers accept EXTEND cells to routers with private IPs. */ diff --git a/src/or/routerparse.c b/src/or/routerparse.c index a2bc8fbb93..6f3acd0987 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -131,6 +131,7 @@ typedef enum { K_CONSENSUS_METHOD, K_LEGACY_DIR_KEY, K_DIRECTORY_FOOTER, + K_PACKAGE, A_PURPOSE, A_LAST_LISTED, @@ -420,6 +421,7 @@ static token_rule_t networkstatus_token_table[] = { T1("known-flags", K_KNOWN_FLAGS, ARGS, NO_OBJ ), T01("params", K_PARAMS, ARGS, NO_OBJ ), T( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ), + T0N("package", K_PACKAGE, CONCAT_ARGS, NO_OBJ ), CERTIFICATE_MEMBERS @@ -2626,6 +2628,16 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, ns->server_versions = tor_strdup(tok->args[0]); } + { + smartlist_t *package_lst = find_all_by_keyword(tokens, K_PACKAGE); + if (package_lst) { + ns->package_lines = smartlist_new(); + SMARTLIST_FOREACH(package_lst, directory_token_t *, t, + smartlist_add(ns->package_lines, tor_strdup(t->args[0]))); + } + smartlist_free(package_lst); + } + tok = find_by_keyword(tokens, K_KNOWN_FLAGS); ns->known_flags = smartlist_new(); inorder = 1; -- cgit v1.2.3-54-g00ecf From ddfdeb5659be17b3e7a4c34b749207bdeae5124a Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sat, 10 Jan 2015 15:44:32 -0500 Subject: More documentation for proposal 227 work --- doc/tor.1.txt | 6 ++++++ src/common/container.c | 5 ++++- src/or/dirvote.c | 13 ++++++++++--- 3 files changed, 20 insertions(+), 4 deletions(-) (limited to 'src/or') diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 9e86a67359..9b491f7635 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -1881,6 +1881,12 @@ on the public Tor network. multiple times: the values from multiple lines are spliced together. When this is set then **VersioningAuthoritativeDirectory** should be set too. +[[RecommendedPackageVersions]] **RecommendedPackageVersions** __PACKAGENAME__ __VERSION__ __URL__ __DIGESTTYPE__**=**__DIGEST__ :: + Adds "package" line to the directory authority's vote. This information + is used to vote on the correct URL and digest for the released versions + of different Tor-related packages, so that the consensus can certify + them. This line may appear any number of times. + [[RecommendedClientVersions]] **RecommendedClientVersions** __STRING__:: STRING is a comma-separated list of Tor versions currently believed to be safe for clients to use. This information is included in version 2 diff --git a/src/common/container.c b/src/common/container.c index 68e3711c90..864fd8a552 100644 --- a/src/common/container.c +++ b/src/common/container.c @@ -735,7 +735,10 @@ smartlist_get_most_frequent_string(smartlist_t *sl) return smartlist_get_most_frequent(sl, compare_string_ptrs_); } -/** Return the most frequent string in the sorted list sl */ +/** Return the most frequent string in the sorted list sl. + * If count_out is provided, set count_out to the + * number of times that string appears. + */ char * smartlist_get_most_frequent_string_(smartlist_t *sl, int *count_out) { diff --git a/src/or/dirvote.c b/src/or/dirvote.c index c09c4faf7d..7739c52d15 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -1886,13 +1886,18 @@ networkstatus_compute_consensus(smartlist_t *votes, return result; } -/** DOCDOC */ +/** Given a list of networkstatus_t for each vote, return a newly allocated + * string containing the "package" lines for the vote. */ STATIC char * compute_consensus_package_lines(smartlist_t *votes) { const int n_votes = smartlist_len(votes); + + /* This will be a map from "packagename version" strings to arrays + * of const char *, with the i'th member of the array corresponding to the + * package line from the i'th vote. + */ strmap_t *package_status = strmap_new(); - smartlist_t *result_list = smartlist_new(); SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) { if (! v->package_lines) @@ -1901,6 +1906,7 @@ compute_consensus_package_lines(smartlist_t *votes) if (! validate_recommended_package_line(line)) continue; + /* Skip 'cp' to the second space in the line. */ const char *cp = strchr(line, ' '); if (!cp) continue; ++cp; @@ -1919,7 +1925,8 @@ compute_consensus_package_lines(smartlist_t *votes) } SMARTLIST_FOREACH_END(line); } SMARTLIST_FOREACH_END(v); - smartlist_t *entries = smartlist_new(); + smartlist_t *entries = smartlist_new(); /* temporary */ + smartlist_t *result_list = smartlist_new(); /* output */ STRMAP_FOREACH(package_status, key, const char **, values) { int i, count=-1; for (i = 0; i < n_votes; ++i) { -- cgit v1.2.3-54-g00ecf From 1e61b45251bd2895e0448fcf283e4f7e05355f28 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 27 Jan 2015 16:31:48 -0500 Subject: Fixes on prop227 comments, based on comments by mcs on #10395 --- src/or/dirserv.c | 21 ++++++++++++++++++++- src/or/or.h | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'src/or') diff --git a/src/or/dirserv.c b/src/or/dirserv.c index dbdfff1440..4a6c50616c 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -3258,7 +3258,26 @@ connection_dirserv_flushed_some(dir_connection_t *conn) } } -/** Return true iff line is a valid recommened_packages line. +/** Return true iff line is a valid RecommenedPackages line. + */ +/* + The grammar is: + + "package" SP PACKAGENAME SP VERSION SP URL SP DIGESTS NL + + PACKAGENAME = NONSPACE + VERSION = NONSPACE + URL = NONSPACE + DIGESTS = DIGEST | DIGESTS SP DIGEST + DIGEST = DIGESTTYPE "=" DIGESTVAL + + NONSPACE = one or more non-space printing characters + + DIGESTVAL = any number of non-=, non-" " characters. + + SP = " " + NL = a newline + */ int validate_recommended_package_line(const char *line) diff --git a/src/or/or.h b/src/or/or.h index 228738faab..33fc1a46b1 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2456,7 +2456,7 @@ typedef struct networkstatus_t { /** Vote only: what methods is this voter willing to use? */ smartlist_t *supported_methods; - /** List of 'package' lines describing hashes of downloadable pacakges */ + /** List of 'package' lines describing hashes of downloadable packages */ smartlist_t *package_lines; /** How long does this vote/consensus claim that authorities take to -- cgit v1.2.3-54-g00ecf From 9c4328c0384dc5fd84555daddbd54da2d375c4d0 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 27 Jan 2015 16:40:32 -0500 Subject: New GETINFO consensus/packages to expose package information from consensus --- src/or/control.c | 2 ++ src/or/networkstatus.c | 5 +++++ 2 files changed, 7 insertions(+) (limited to 'src/or') diff --git a/src/or/control.c b/src/or/control.c index 9ff71c9541..8e2b4625ae 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -2165,6 +2165,8 @@ static const getinfo_item_t getinfo_items[] = { "Brief summary of router status by nickname (v2 directory format)."), PREFIX("ns/purpose/", networkstatus, "Brief summary of router status by purpose (v2 directory format)."), + PREFIX("consensus/", networkstatus, + "Information abour and from the ns consensus."), ITEM("network-status", dir, "Brief summary of router status (v1 directory format)"), ITEM("circuit-status", events, "List of current circuits originating here."), diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 19c0b21c21..0024b1ffc0 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -1913,6 +1913,11 @@ getinfo_helper_networkstatus(control_connection_t *conn, } else if (!strcmpstart(question, "ns/purpose/")) { *answer = networkstatus_getinfo_by_purpose(question+11, time(NULL)); return *answer ? 0 : -1; + } else if (!strcmpstart(question, "consensus/packages")) { + const networkstatus_t *ns = networkstatus_get_latest_consensus(); + if (ns->package_lines) + *answer = smartlist_join_strings(ns->package_lines, "\n", 1, NULL); + return *answer ? 0 : -1; } else { return 0; } -- cgit v1.2.3-54-g00ecf From c240eea0df38be9a82548a71fa54b553057a8b42 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 28 Jan 2015 11:25:37 -0500 Subject: more typo fixes from mcs and gk --- src/or/control.c | 2 +- src/or/dirserv.c | 2 +- src/or/networkstatus.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/or') diff --git a/src/or/control.c b/src/or/control.c index 8e2b4625ae..ceb2b2f198 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -2166,7 +2166,7 @@ static const getinfo_item_t getinfo_items[] = { PREFIX("ns/purpose/", networkstatus, "Brief summary of router status by purpose (v2 directory format)."), PREFIX("consensus/", networkstatus, - "Information abour and from the ns consensus."), + "Information about and from the ns consensus."), ITEM("network-status", dir, "Brief summary of router status (v1 directory format)"), ITEM("circuit-status", events, "List of current circuits originating here."), diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 4a6c50616c..c65e99e1ff 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -3258,7 +3258,7 @@ connection_dirserv_flushed_some(dir_connection_t *conn) } } -/** Return true iff line is a valid RecommenedPackages line. +/** Return true iff line is a valid RecommendedPackages line. */ /* The grammar is: diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 0024b1ffc0..a25413a12f 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -1913,7 +1913,7 @@ getinfo_helper_networkstatus(control_connection_t *conn, } else if (!strcmpstart(question, "ns/purpose/")) { *answer = networkstatus_getinfo_by_purpose(question+11, time(NULL)); return *answer ? 0 : -1; - } else if (!strcmpstart(question, "consensus/packages")) { + } else if (!strcmp(question, "consensus/packages")) { const networkstatus_t *ns = networkstatus_get_latest_consensus(); if (ns->package_lines) *answer = smartlist_join_strings(ns->package_lines, "\n", 1, NULL); -- cgit v1.2.3-54-g00ecf From 32dad3b83bb21c4f1af4a8e45f539ab8cf8a6779 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 28 Jan 2015 11:28:21 -0500 Subject: Add GETINFO consensus/{valid-{after,until},fresh-until} --- src/or/networkstatus.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'src/or') diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index a25413a12f..9d6d5abe6a 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -1915,9 +1915,27 @@ getinfo_helper_networkstatus(control_connection_t *conn, return *answer ? 0 : -1; } else if (!strcmp(question, "consensus/packages")) { const networkstatus_t *ns = networkstatus_get_latest_consensus(); - if (ns->package_lines) + if (ns && ns->package_lines) *answer = smartlist_join_strings(ns->package_lines, "\n", 1, NULL); return *answer ? 0 : -1; + } else if (!strcmp(question, "consensus/valid-after") || + !strcmp(question, "consensus/fresh-until") || + !strcmp(question, "consensus/valid-until")) { + const networkstatus_t *ns = networkstatus_get_latest_consensus(); + if (ns) { + time_t t; + if (!strcmp(question, "consensus/valid-after")) + t = ns->valid_after; + else if (!strcmp(question, "consensus/fresh-until")) + t = ns->fresh_until; + else + t = ns->valid_until; + + char tbuf[ISO_TIME_LEN+1]; + format_iso_time(tbuf, t); + *answer = tor_strdup(tbuf); + } + return *answer ? 0 : -1; } else { return 0; } -- cgit v1.2.3-54-g00ecf From f935ee2dae5ca026a6bf81cc403bc50ae92bdd70 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 29 Jan 2015 14:04:21 -0500 Subject: Define 'digesttype' correctly --- src/or/dirserv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/or') diff --git a/src/or/dirserv.c b/src/or/dirserv.c index c65e99e1ff..3785d9adee 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -3273,7 +3273,7 @@ connection_dirserv_flushed_some(dir_connection_t *conn) NONSPACE = one or more non-space printing characters - DIGESTVAL = any number of non-=, non-" " characters. + DIGESTVAL = DIGESTTYPE = one or more non-=, non-" " characters. SP = " " NL = a newline -- cgit v1.2.3-54-g00ecf From bd630a899a1ff7658a0c52327fa3cce59e7213b4 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 29 Jan 2015 14:04:57 -0500 Subject: Correctly reject packages lines with empty entries --- src/or/dirserv.c | 42 +++++++++++++++++++++++++++++------------- src/test/test_dir.c | 7 +++++++ 2 files changed, 36 insertions(+), 13 deletions(-) (limited to 'src/or') diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 3785d9adee..5c59fc7a5e 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -3300,22 +3300,38 @@ validate_recommended_package_line(const char *line) WORD(); /* Skip URL */ ++cp; - /* Skip digestname=digestval + */ - int foundeq = 0; - while (*cp) { - if (*cp == ' ') { - if (!foundeq) - return 0; - foundeq = 0; - } else if (*cp == '=') { - if (++foundeq > 1) - return 0; - } - ++cp; + /* Skip digesttype=digestval + */ + int n_entries = 0; + while (1) { + const char *start_of_word = cp; + const char *end_of_word = strchr(cp, ' '); + if (! end_of_word) + end_of_word = cp + strlen(cp); + + if (start_of_word == end_of_word) + return 0; + + const char *eq = memchr(start_of_word, '=', end_of_word - start_of_word); + + if (!eq) + return 0; + if (eq == start_of_word) + return 0; + if (eq == end_of_word - 1) + return 0; + if (memchr(eq+1, '=', end_of_word - (eq+1))) + return 0; + + ++n_entries; + if (0 == *end_of_word) + break; + + cp = end_of_word + 1; } - if (!foundeq) + if (n_entries == 0) return 0; + return 1; } diff --git a/src/test/test_dir.c b/src/test/test_dir.c index 7d3d41401d..efc3ec7940 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -2961,6 +2961,13 @@ test_dir_packages(void *arg) BAD("tor "); BAD("tor"); BAD(""); + BAD("=foobar sha256=" + "3c179f46ca77069a6a0bac70212a9b3b838b2f66129cb52d568837fc79d8fcc7"); + BAD("= = sha256=" + "3c179f46ca77069a6a0bac70212a9b3b838b2f66129cb52d568837fc79d8fcc7"); + + BAD("sha512= sha256=" + "3c179f46ca77069a6a0bac70212a9b3b838b2f66129cb52d568837fc79d8fcc7"); votes = smartlist_new(); smartlist_add(votes, tor_malloc_zero(sizeof(networkstatus_t))); -- cgit v1.2.3-54-g00ecf From b4a8fd895802801198229574c55b3df975aa2244 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 29 Jan 2015 14:14:59 -0500 Subject: When there are no package lines, make consensus/packages say "". Also, give a better error message when there is no consensus. --- src/or/networkstatus.c | 6 +++++- src/or/routerparse.c | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src/or') diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 9d6d5abe6a..da110fdff6 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -1916,7 +1916,9 @@ getinfo_helper_networkstatus(control_connection_t *conn, } else if (!strcmp(question, "consensus/packages")) { const networkstatus_t *ns = networkstatus_get_latest_consensus(); if (ns && ns->package_lines) - *answer = smartlist_join_strings(ns->package_lines, "\n", 1, NULL); + *answer = smartlist_join_strings(ns->package_lines, "\n", 0, NULL); + else + *errmsg = "No consensus available"; return *answer ? 0 : -1; } else if (!strcmp(question, "consensus/valid-after") || !strcmp(question, "consensus/fresh-until") || @@ -1934,6 +1936,8 @@ getinfo_helper_networkstatus(control_connection_t *conn, char tbuf[ISO_TIME_LEN+1]; format_iso_time(tbuf, t); *answer = tor_strdup(tbuf); + } else { + *errmsg = "No consensus available"; } return *answer ? 0 : -1; } else { diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 6f3acd0987..f7687e0e40 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -2630,8 +2630,8 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, { smartlist_t *package_lst = find_all_by_keyword(tokens, K_PACKAGE); + ns->package_lines = smartlist_new(); if (package_lst) { - ns->package_lines = smartlist_new(); SMARTLIST_FOREACH(package_lst, directory_token_t *, t, smartlist_add(ns->package_lines, tor_strdup(t->args[0]))); } -- cgit v1.2.3-54-g00ecf