commit 2bcd6bb0e4cf8b535cf3b4c4ef0eed83dfc82676 Author: Karsten Loesing karsten.loesing@gmx.net Date: Mon Feb 13 12:05:47 2017 +0100
Parse new protocol versions lines. --- CHANGELOG.md | 3 + .../torproject/descriptor/NetworkStatusEntry.java | 9 +++ .../descriptor/RelayNetworkStatusConsensus.java | 36 +++++++++ .../descriptor/RelayNetworkStatusVote.java | 32 ++++++++ .../torproject/descriptor/ServerDescriptor.java | 10 +++ .../descriptor/impl/NetworkStatusEntryImpl.java | 17 ++++ .../torproject/descriptor/impl/ParseHelper.java | 47 +++++++++++ .../impl/RelayNetworkStatusConsensusImpl.java | 68 +++++++++++++++- .../impl/RelayNetworkStatusVoteImpl.java | 66 ++++++++++++++++ .../descriptor/impl/ServerDescriptorImpl.java | 20 ++++- .../descriptor/impl/ConsensusBuilder.java | 60 ++++++++++++++ .../impl/RelayNetworkStatusConsensusImplTest.java | 79 +++++++++++++++++++ .../impl/RelayNetworkStatusVoteImplTest.java | 92 ++++++++++++++++++++++ .../descriptor/impl/ServerDescriptorImplTest.java | 49 ++++++++++-- 14 files changed, 581 insertions(+), 7 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md index 755428d..6bcfea9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ the application can decide at any time to stop consuming descriptors without having to worry about the reader thread not being done. + - Parse "proto" lines in server descriptors, "pr" lines in status + entries, and "(recommended|required)-(client|relay)-protocols" + lines in consensuses and votes.
# Changes in version 1.5.0 - 2016-10-19 diff --git a/src/main/java/org/torproject/descriptor/NetworkStatusEntry.java b/src/main/java/org/torproject/descriptor/NetworkStatusEntry.java index 68f6939..ba413bb 100644 --- a/src/main/java/org/torproject/descriptor/NetworkStatusEntry.java +++ b/src/main/java/org/torproject/descriptor/NetworkStatusEntry.java @@ -5,6 +5,7 @@ package org.torproject.descriptor;
import java.util.List; import java.util.Set; +import java.util.SortedMap; import java.util.SortedSet;
/** @@ -123,6 +124,14 @@ public interface NetworkStatusEntry { public String getVersion();
/** + * Return the version numbers of all protocols supported by this server, or + * null if the status entry does not specify supported protocol versions. + * + * @since 1.6.0 + */ + public SortedMap<String, SortedSet<Long>> getProtocols(); + + /** * Return the bandwidth weight of this server or -1 if the status entry * didn't contain a bandwidth line. * diff --git a/src/main/java/org/torproject/descriptor/RelayNetworkStatusConsensus.java b/src/main/java/org/torproject/descriptor/RelayNetworkStatusConsensus.java index a2deba3..b004b66 100644 --- a/src/main/java/org/torproject/descriptor/RelayNetworkStatusConsensus.java +++ b/src/main/java/org/torproject/descriptor/RelayNetworkStatusConsensus.java @@ -113,6 +113,42 @@ public interface RelayNetworkStatusConsensus extends Descriptor { public List<String> getRecommendedClientVersions();
/** + * Return the version numbers of all protocols that clients should support, + * or null if the consensus does not contain an opinion about protocol + * versions. + * + * @since 1.6.0 + */ + public SortedMap<String, SortedSet<Long>> getRecommendedClientProtocols(); + + /** + * Return the version numbers of all protocols that relays should support, + * or null if the consensus does not contain an opinion about protocol + * versions. + * + * @since 1.6.0 + */ + public SortedMap<String, SortedSet<Long>> getRecommendedRelayProtocols(); + + /** + * Return the version numbers of all protocols that clients must support, + * or null if the consensus does not contain an opinion about protocol + * versions. + * + * @since 1.6.0 + */ + public SortedMap<String, SortedSet<Long>> getRequiredClientProtocols(); + + /** + * Return the version numbers of all protocols that relays must support, + * or null if the consensus does not contain an opinion about protocol + * versions. + * + * @since 1.6.0 + */ + public SortedMap<String, SortedSet<Long>> getRequiredRelayProtocols(); + + /** * Return a list of software packages and their versions together with a * URL and one or more digests in the format <code>PackageName Version * URL DIGESTS</code> that are known by at least three directory diff --git a/src/main/java/org/torproject/descriptor/RelayNetworkStatusVote.java b/src/main/java/org/torproject/descriptor/RelayNetworkStatusVote.java index a3f8170..9ea804d 100644 --- a/src/main/java/org/torproject/descriptor/RelayNetworkStatusVote.java +++ b/src/main/java/org/torproject/descriptor/RelayNetworkStatusVote.java @@ -105,6 +105,38 @@ public interface RelayNetworkStatusVote extends Descriptor { public List<String> getRecommendedClientVersions();
/** + * Return the version numbers of all protocols that clients should support, + * or null if the vote does not contain an opinion about protocol versions. + * + * @since 1.6.0 + */ + public SortedMap<String, SortedSet<Long>> getRecommendedClientProtocols(); + + /** + * Return the version numbers of all protocols that relays should support, + * or null if the vote does not contain an opinion about protocol versions. + * + * @since 1.6.0 + */ + public SortedMap<String, SortedSet<Long>> getRecommendedRelayProtocols(); + + /** + * Return the version numbers of all protocols that clients must support, + * or null if the vote does not contain an opinion about protocol versions. + * + * @since 1.6.0 + */ + public SortedMap<String, SortedSet<Long>> getRequiredClientProtocols(); + + /** + * Return the version numbers of all protocols that relays must support, + * or null if the vote does not contain an opinion about protocol versions. + * + * @since 1.6.0 + */ + public SortedMap<String, SortedSet<Long>> getRequiredRelayProtocols(); + + /** * Return a list of software packages and their versions together with a * URL and one or more digests in the format <code>PackageName Version * URL DIGESTS</code> that are known by this directory authority, or diff --git a/src/main/java/org/torproject/descriptor/ServerDescriptor.java b/src/main/java/org/torproject/descriptor/ServerDescriptor.java index 418cb55..4ecade6 100644 --- a/src/main/java/org/torproject/descriptor/ServerDescriptor.java +++ b/src/main/java/org/torproject/descriptor/ServerDescriptor.java @@ -4,6 +4,8 @@ package org.torproject.descriptor;
import java.util.List; +import java.util.SortedMap; +import java.util.SortedSet;
/** * Contains a relay or sanitized bridge server descriptor. @@ -152,6 +154,14 @@ public interface ServerDescriptor extends Descriptor { public String getPlatform();
/** + * Return the version numbers of all protocols supported by this server, or + * null if this descriptor does not specify supported protocol versions. + * + * @since 1.6.0 + */ + public SortedMap<String, SortedSet<Long>> getProtocols(); + + /** * Return the time in milliseconds since the epoch when this descriptor * and the corresponding extra-info descriptor were generated. * diff --git a/src/main/java/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java b/src/main/java/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java index d26eaeb..f67e6bd 100644 --- a/src/main/java/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java +++ b/src/main/java/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java @@ -57,6 +57,7 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry { this.atMostOnceKeywords = new TreeSet<>(); this.atMostOnceKeywords.add("s"); this.atMostOnceKeywords.add("v"); + this.atMostOnceKeywords.add("pr"); this.atMostOnceKeywords.add("w"); this.atMostOnceKeywords.add("p"); } @@ -95,6 +96,9 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry { case "v": this.parseVLine(line, parts); break; + case "pr": + this.parsePrLine(line, parts); + break; case "w": this.parseWLine(line, parts); break; @@ -191,6 +195,12 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry { } }
+ private void parsePrLine(String line, String[] parts) + throws DescriptorParseException { + this.parsedAtMostOnceKeyword("pr"); + this.protocols = ParseHelper.parseProtocolVersions(line, line, parts); + } + private void parseWLine(String line, String[] parts) throws DescriptorParseException { this.parsedAtMostOnceKeyword("w"); @@ -359,6 +369,13 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry { return this.version; }
+ private SortedMap<String, SortedSet<Long>> protocols; + + @Override + public SortedMap<String, SortedSet<Long>> getProtocols() { + return this.protocols; + } + private long bandwidth = -1L;
@Override diff --git a/src/main/java/org/torproject/descriptor/impl/ParseHelper.java b/src/main/java/org/torproject/descriptor/impl/ParseHelper.java index dfa9065..f73a591 100644 --- a/src/main/java/org/torproject/descriptor/impl/ParseHelper.java +++ b/src/main/java/org/torproject/descriptor/impl/ParseHelper.java @@ -8,13 +8,16 @@ import org.torproject.descriptor.DescriptorParseException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; import java.util.SortedMap; +import java.util.SortedSet; import java.util.TimeZone; import java.util.TreeMap; +import java.util.TreeSet; import java.util.regex.Pattern;
import javax.xml.bind.DatatypeConverter; @@ -578,5 +581,49 @@ public class ParseHelper { throw new DescriptorParseException("Unable to locate " + "master-key-ed25519 in identity-ed25519."); } + + private static Map<String, SortedMap<String, SortedSet<Long>>> + parsedProtocolVersions = new HashMap<>(); + + protected static SortedMap<String, SortedSet<Long>> parseProtocolVersions( + String line, String lineNoOpt, String[] partsNoOpt) + throws DescriptorParseException { + if (!parsedProtocolVersions.containsKey(lineNoOpt)) { + SortedMap<String, SortedSet<Long>> parsed = new TreeMap<>(); + boolean invalid = false; + try { + for (int i = 1; i < partsNoOpt.length; i++) { + String[] part = partsNoOpt[i].split("="); + SortedSet<Long> versions = new TreeSet<>(); + for (String val : part[1].split(",")) { + if (val.contains("-")) { + String[] fromTo = val.split("-"); + long from = Long.parseLong(fromTo[0]); + long to = Long.parseLong(fromTo[1]); + if (from > to || to >= 0x1_0000_0000L) { + invalid = true; + } else { + for (long j = from; + j <= to; j++) { + versions.add(j); + } + } + } else { + versions.add(Long.parseLong(val)); + } + } + parsed.put(part[0], Collections.unmodifiableSortedSet(versions)); + } + } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) { + throw new DescriptorParseException("Invalid line '" + line + "'.", e); + } + if (invalid) { + throw new DescriptorParseException("Invalid line '" + line + "'."); + } + parsedProtocolVersions.put(lineNoOpt, + Collections.unmodifiableSortedMap(parsed)); + } + return parsedProtocolVersions.get(lineNoOpt); + } }
diff --git a/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java b/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java index 8733729..fd4cf7e 100644 --- a/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java +++ b/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java @@ -52,7 +52,9 @@ public class RelayNetworkStatusConsensusImpl extends NetworkStatusImpl + "valid-until,voting-delay,known-flags").split(","))); this.checkExactlyOnceKeywords(exactlyOnceKeywords); Set<String> atMostOnceKeywords = new HashSet<>(Arrays.asList(( - "client-versions,server-versions,params,directory-footer," + "client-versions,server-versions,recommended-client-protocols," + + "recommended-relay-protocols,required-client-protocols," + + "required-relay-protocols,params,directory-footer," + "bandwidth-weights").split(","))); this.checkAtMostOnceKeywords(atMostOnceKeywords); this.checkFirstKeyword("network-status-version"); @@ -124,6 +126,18 @@ public class RelayNetworkStatusConsensusImpl extends NetworkStatusImpl case "server-versions": this.parseServerVersionsLine(line, parts); break; + case "recommended-client-protocols": + this.parseRecommendedClientProtocolsLine(line, parts); + break; + case "recommended-relay-protocols": + this.parseRecommendedRelayProtocolsLine(line, parts); + break; + case "required-client-protocols": + this.parseRequiredClientProtocolsLine(line, parts); + break; + case "required-relay-protocols": + this.parseRequiredRelayProtocolsLine(line, parts); + break; case "package": this.parsePackageLine(line, parts); break; @@ -281,6 +295,30 @@ public class RelayNetworkStatusConsensusImpl extends NetworkStatusImpl line, parts); }
+ private void parseRecommendedClientProtocolsLine(String line, String[] parts) + throws DescriptorParseException { + this.recommendedClientProtocols = ParseHelper.parseProtocolVersions(line, + line, parts); + } + + private void parseRecommendedRelayProtocolsLine(String line, String[] parts) + throws DescriptorParseException { + this.recommendedRelayProtocols = ParseHelper.parseProtocolVersions(line, + line, parts); + } + + private void parseRequiredClientProtocolsLine(String line, String[] parts) + throws DescriptorParseException { + this.requiredClientProtocols = ParseHelper.parseProtocolVersions(line, + line, parts); + } + + private void parseRequiredRelayProtocolsLine(String line, String[] parts) + throws DescriptorParseException { + this.requiredRelayProtocols = ParseHelper.parseProtocolVersions(line, line, + parts); + } + private void parsePackageLine(String line, String[] parts) throws DescriptorParseException { if (parts.length < 5) { @@ -397,6 +435,34 @@ public class RelayNetworkStatusConsensusImpl extends NetworkStatusImpl : Arrays.asList(this.recommendedServerVersions); }
+ private SortedMap<String, SortedSet<Long>> recommendedClientProtocols; + + @Override + public SortedMap<String, SortedSet<Long>> getRecommendedClientProtocols() { + return this.recommendedClientProtocols; + } + + private SortedMap<String, SortedSet<Long>> recommendedRelayProtocols; + + @Override + public SortedMap<String, SortedSet<Long>> getRecommendedRelayProtocols() { + return this.recommendedRelayProtocols; + } + + private SortedMap<String, SortedSet<Long>> requiredClientProtocols; + + @Override + public SortedMap<String, SortedSet<Long>> getRequiredClientProtocols() { + return this.requiredClientProtocols; + } + + private SortedMap<String, SortedSet<Long>> requiredRelayProtocols; + + @Override + public SortedMap<String, SortedSet<Long>> getRequiredRelayProtocols() { + return this.requiredRelayProtocols; + } + private List<String> packageLines;
@Override diff --git a/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java b/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java index 02390de..619b2c1 100644 --- a/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java +++ b/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java @@ -52,6 +52,8 @@ public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl this.checkExactlyOnceKeywords(exactlyOnceKeywords); Set<String> atMostOnceKeywords = new HashSet<>(Arrays.asList(( "consensus-methods,client-versions,server-versions," + + "recommended-client-protocols,recommended-relay-protocols," + + "required-client-protocols,required-relay-protocols," + "flag-thresholds,params,contact," + "legacy-key,dir-key-crosscert,dir-address,directory-footer") .split(","))); @@ -117,6 +119,18 @@ public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl case "server-versions": this.parseServerVersionsLine(line, parts); break; + case "recommended-client-protocols": + this.parseRecommendedClientProtocolsLine(line, parts); + break; + case "recommended-relay-protocols": + this.parseRecommendedRelayProtocolsLine(line, parts); + break; + case "required-client-protocols": + this.parseRequiredClientProtocolsLine(line, parts); + break; + case "required-relay-protocols": + this.parseRequiredRelayProtocolsLine(line, parts); + break; case "package": this.parsePackageLine(line, parts); break; @@ -305,6 +319,30 @@ public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl line, parts); }
+ private void parseRecommendedClientProtocolsLine(String line, String[] parts) + throws DescriptorParseException { + this.recommendedClientProtocols = ParseHelper.parseProtocolVersions(line, + line, parts); + } + + private void parseRecommendedRelayProtocolsLine(String line, String[] parts) + throws DescriptorParseException { + this.recommendedRelayProtocols = ParseHelper.parseProtocolVersions(line, + line, parts); + } + + private void parseRequiredClientProtocolsLine(String line, String[] parts) + throws DescriptorParseException { + this.requiredClientProtocols = ParseHelper.parseProtocolVersions(line, + line, parts); + } + + private void parseRequiredRelayProtocolsLine(String line, String[] parts) + throws DescriptorParseException { + this.requiredRelayProtocols = ParseHelper.parseProtocolVersions(line, line, + parts); + } + private void parsePackageLine(String line, String[] parts) throws DescriptorParseException { if (parts.length < 5) { @@ -710,6 +748,34 @@ public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl : Arrays.asList(this.recommendedServerVersions); }
+ private SortedMap<String, SortedSet<Long>> recommendedClientProtocols; + + @Override + public SortedMap<String, SortedSet<Long>> getRecommendedClientProtocols() { + return this.recommendedClientProtocols; + } + + private SortedMap<String, SortedSet<Long>> recommendedRelayProtocols; + + @Override + public SortedMap<String, SortedSet<Long>> getRecommendedRelayProtocols() { + return this.recommendedRelayProtocols; + } + + private SortedMap<String, SortedSet<Long>> requiredClientProtocols; + + @Override + public SortedMap<String, SortedSet<Long>> getRequiredClientProtocols() { + return this.requiredClientProtocols; + } + + private SortedMap<String, SortedSet<Long>> requiredRelayProtocols; + + @Override + public SortedMap<String, SortedSet<Long>> getRequiredRelayProtocols() { + return this.requiredRelayProtocols; + } + private List<String> packageLines;
@Override diff --git a/src/main/java/org/torproject/descriptor/impl/ServerDescriptorImpl.java b/src/main/java/org/torproject/descriptor/impl/ServerDescriptorImpl.java index 183959a..309cad4 100644 --- a/src/main/java/org/torproject/descriptor/impl/ServerDescriptorImpl.java +++ b/src/main/java/org/torproject/descriptor/impl/ServerDescriptorImpl.java @@ -16,6 +16,8 @@ import java.util.HashSet; import java.util.List; import java.util.Scanner; import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet;
import javax.xml.bind.DatatypeConverter;
@@ -34,7 +36,7 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl "router,bandwidth,published".split(","))); this.checkExactlyOnceKeywords(exactlyOnceKeywords); Set<String> atMostOnceKeywords = new HashSet<>(Arrays.asList(( - "identity-ed25519,master-key-ed25519,platform,fingerprint," + "identity-ed25519,master-key-ed25519,platform,proto,fingerprint," + "hibernating,uptime,contact,family,read-history,write-history," + "eventdns,caches-extra-info,extra-info-digest," + "hidden-service-dir,protocols,allow-single-hop-exits,onion-key," @@ -80,6 +82,9 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl case "platform": this.parsePlatformLine(line, lineNoOpt, partsNoOpt); break; + case "proto": + this.parseProtoLine(line, lineNoOpt, partsNoOpt); + break; case "published": this.parsePublishedLine(line, lineNoOpt, partsNoOpt); break; @@ -303,6 +308,12 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl } }
+ private void parseProtoLine(String line, String lineNoOpt, + String[] partsNoOpt) throws DescriptorParseException { + this.protocols = ParseHelper.parseProtocolVersions(line, lineNoOpt, + partsNoOpt); + } + private void parsePublishedLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { this.publishedMillis = ParseHelper.parseTimestampAtIndex(line, @@ -812,6 +823,13 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl return this.platform; }
+ private SortedMap<String, SortedSet<Long>> protocols; + + @Override + public SortedMap<String, SortedSet<Long>> getProtocols() { + return this.protocols; + } + private long publishedMillis;
@Override diff --git a/src/test/java/org/torproject/descriptor/impl/ConsensusBuilder.java b/src/test/java/org/torproject/descriptor/impl/ConsensusBuilder.java index b765be6..24d5a02 100644 --- a/src/test/java/org/torproject/descriptor/impl/ConsensusBuilder.java +++ b/src/test/java/org/torproject/descriptor/impl/ConsensusBuilder.java @@ -126,6 +126,54 @@ public class ConsensusBuilder { return new RelayNetworkStatusConsensusImpl(cb.buildConsensus(), true); }
+ private String recommendedClientProtocolsLine = + "recommended-client-protocols Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 " + + "HSIntro=3 HSRend=1 Link=4 LinkAuth=1 Microdesc=1-2 Relay=2"; + + protected static RelayNetworkStatusConsensus + createWithRecommendedClientProtocolsLine(String line) + throws DescriptorParseException { + ConsensusBuilder cb = new ConsensusBuilder(); + cb.recommendedClientProtocolsLine = line; + return new RelayNetworkStatusConsensusImpl(cb.buildConsensus(), true); + } + + private String recommendedRelayProtocolsLine = + "recommended-relay-protocols Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 " + + "HSIntro=3 HSRend=1 Link=4 LinkAuth=1 Microdesc=1-2 Relay=2"; + + protected static RelayNetworkStatusConsensus + createWithRecommendedRelayProtocolsLine(String line) + throws DescriptorParseException { + ConsensusBuilder cb = new ConsensusBuilder(); + cb.recommendedRelayProtocolsLine = line; + return new RelayNetworkStatusConsensusImpl(cb.buildConsensus(), true); + } + + private String requiredClientProtocolsLine = + "required-client-protocols Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 " + + "HSIntro=3 HSRend=1 Link=4 LinkAuth=1 Microdesc=1-2 Relay=2"; + + protected static RelayNetworkStatusConsensus + createWithRequiredClientProtocolsLine(String line) + throws DescriptorParseException { + ConsensusBuilder cb = new ConsensusBuilder(); + cb.requiredClientProtocolsLine = line; + return new RelayNetworkStatusConsensusImpl(cb.buildConsensus(), true); + } + + private String requiredRelayProtocolsLine = + "required-relay-protocols Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 " + + "HSRend=1 Link=3-4 LinkAuth=1 Microdesc=1 Relay=1-2"; + + protected static RelayNetworkStatusConsensus + createWithRequiredRelayProtocolsLine(String line) + throws DescriptorParseException { + ConsensusBuilder cb = new ConsensusBuilder(); + cb.requiredRelayProtocolsLine = line; + return new RelayNetworkStatusConsensusImpl(cb.buildConsensus(), true); + } + private String paramsLine = "params " + "CircuitPriorityHalflifeMsec=30000 bwauthbestratio=1 " + "bwauthcircs=1 bwauthdescbw=0 bwauthkp=10000 bwauthpid=1 " @@ -322,6 +370,18 @@ public class ConsensusBuilder { if (this.knownFlagsLine != null) { sb.append(this.knownFlagsLine).append("\n"); } + if (this.recommendedClientProtocolsLine != null) { + sb.append(this.recommendedClientProtocolsLine).append("\n"); + } + if (this.recommendedRelayProtocolsLine != null) { + sb.append(this.recommendedRelayProtocolsLine).append("\n"); + } + if (this.requiredClientProtocolsLine != null) { + sb.append(this.requiredClientProtocolsLine).append("\n"); + } + if (this.requiredRelayProtocolsLine != null) { + sb.append(this.requiredRelayProtocolsLine).append("\n"); + } if (this.paramsLine != null) { sb.append(this.paramsLine).append("\n"); } diff --git a/src/test/java/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImplTest.java b/src/test/java/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImplTest.java index ebcbd83..786ae54 100644 --- a/src/test/java/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImplTest.java +++ b/src/test/java/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImplTest.java @@ -19,6 +19,7 @@ import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.TreeSet;
/* TODO Add test cases for all lines starting with "opt ". */
@@ -242,6 +243,16 @@ public class RelayNetworkStatusConsensusImplTest { return createWithStatusEntry(seb.buildStatusEntry()); }
+ private String prLine = "pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 " + + "HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2"; + + private static RelayNetworkStatusConsensus + createWithPrLine(String line) throws DescriptorParseException { + StatusEntryBuilder seb = new StatusEntryBuilder(); + seb.prLine = line; + return createWithStatusEntry(seb.buildStatusEntry()); + } + @SuppressWarnings("checkstyle:membername") private String wLine = "w Bandwidth=1";
@@ -275,6 +286,9 @@ public class RelayNetworkStatusConsensusImplTest { if (this.vLine != null) { sb.append(this.vLine).append("\n"); } + if (this.prLine != null) { + sb.append(this.prLine).append("\n"); + } if (this.wLine != null) { sb.append(this.wLine).append("\n"); } @@ -353,6 +367,14 @@ public class RelayNetworkStatusConsensusImplTest { assertTrue(consensus.getRecommendedServerVersions().contains( "0.2.3.8-alpha")); assertTrue(consensus.getKnownFlags().contains("Running")); + assertTrue(consensus.getRecommendedClientProtocols().get("Cons") + .contains(1L)); + assertFalse(consensus.getRecommendedRelayProtocols().get("Cons") + .contains(33L)); + assertFalse(consensus.getRequiredClientProtocols().get("Relay") + .contains(1L)); + assertTrue(consensus.getRequiredRelayProtocols().get("Relay") + .contains(1L)); assertEquals(30000, (int) consensus.getConsensusParams().get( "CircuitPriorityHalflifeMsec")); assertEquals("86.59.21.38", consensus.getDirSourceEntries().get( @@ -667,6 +689,54 @@ public class RelayNetworkStatusConsensusImplTest { }
@Test() + public void testRecommendedClientProtocols123() + throws DescriptorParseException { + RelayNetworkStatusConsensus consensus = ConsensusBuilder + .createWithRecommendedClientProtocolsLine( + "recommended-client-protocols Cons=1,2,3"); + assertEquals(new TreeSet<Long>(Arrays.asList(new Long[] { 1L, 2L, 3L })), + consensus.getRecommendedClientProtocols().get("Cons")); + } + + @Test() + public void testRecommendedRelayProtocols134() + throws DescriptorParseException { + RelayNetworkStatusConsensus consensus = ConsensusBuilder + .createWithRecommendedRelayProtocolsLine( + "recommended-relay-protocols Cons=1,3-4"); + assertEquals(new TreeSet<Long>(Arrays.asList(new Long[] { 1L, 3L, 4L })), + consensus.getRecommendedRelayProtocols().get("Cons")); + } + + @Test() + public void testRequiredClientProtocols1425() + throws DescriptorParseException { + RelayNetworkStatusConsensus consensus = ConsensusBuilder + .createWithRequiredClientProtocolsLine( + "required-client-protocols Cons=1-3,2-4"); + assertEquals(new TreeSet<Long>(Arrays.asList( + new Long[] { 1L, 2L, 3L, 4L })), + consensus.getRequiredClientProtocols().get("Cons")); + } + + @Test() + public void testRequiredRelayProtocols1111() + throws DescriptorParseException { + RelayNetworkStatusConsensus consensus = ConsensusBuilder + .createWithRequiredRelayProtocolsLine( + "required-relay-protocols Cons=1-1,1-1"); + assertEquals(new TreeSet<Long>(Arrays.asList(new Long[] { 1L })), + consensus.getRequiredRelayProtocols().get("Cons")); + } + + @Test(expected = DescriptorParseException.class) + public void testRequiredRelayProtocolsTwice() + throws DescriptorParseException { + ConsensusBuilder.createWithRequiredRelayProtocolsLine( + "required-relay-protocols Cons=1\nrequired-relay-protocols Cons=1"); + } + + @Test() public void testPackageNone() throws DescriptorParseException { RelayNetworkStatusConsensus consensus = ConsensusBuilder.createWithPackageLines(null); @@ -1022,6 +1092,15 @@ public class RelayNetworkStatusConsensusImplTest { }
@Test(expected = DescriptorParseException.class) + public void testTwoPrLines() throws DescriptorParseException { + StatusEntryBuilder sb = new StatusEntryBuilder(); + sb.prLine = sb.prLine + "\n" + sb.prLine; + ConsensusBuilder cb = new ConsensusBuilder(); + cb.statusEntries.add(sb.buildStatusEntry()); + new RelayNetworkStatusConsensusImpl(cb.buildConsensus(), true); + } + + @Test(expected = DescriptorParseException.class) public void testWLineNoSpace() throws DescriptorParseException { StatusEntryBuilder.createWithWLine("w"); } diff --git a/src/test/java/org/torproject/descriptor/impl/RelayNetworkStatusVoteImplTest.java b/src/test/java/org/torproject/descriptor/impl/RelayNetworkStatusVoteImplTest.java index 847c538..ea7b927 100644 --- a/src/test/java/org/torproject/descriptor/impl/RelayNetworkStatusVoteImplTest.java +++ b/src/test/java/org/torproject/descriptor/impl/RelayNetworkStatusVoteImplTest.java @@ -16,6 +16,7 @@ import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.TreeSet;
/* TODO Add test cases for all lines starting with "opt ". */
@@ -153,6 +154,54 @@ public class RelayNetworkStatusVoteImplTest { return new RelayNetworkStatusVoteImpl(vb.buildVote(), true); }
+ private String recommendedClientProtocolsLine = + "recommended-client-protocols Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 " + + "HSIntro=3 HSRend=1 Link=4 LinkAuth=1 Microdesc=1-2 Relay=2"; + + private static RelayNetworkStatusVote + createWithRecommendedClientProtocolsLine(String line) + throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + vb.recommendedClientProtocolsLine = line; + return new RelayNetworkStatusVoteImpl(vb.buildVote(), true); + } + + private String recommendedRelayProtocolsLine = + "recommended-relay-protocols Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 " + + "HSIntro=3 HSRend=1 Link=4 LinkAuth=1 Microdesc=1-2 Relay=2"; + + private static RelayNetworkStatusVote + createWithRecommendedRelayProtocolsLine(String line) + throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + vb.recommendedRelayProtocolsLine = line; + return new RelayNetworkStatusVoteImpl(vb.buildVote(), true); + } + + private String requiredClientProtocolsLine = + "required-client-protocols Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 " + + "HSIntro=3 HSRend=1 Link=4 LinkAuth=1 Microdesc=1-2 Relay=2"; + + private static RelayNetworkStatusVote + createWithRequiredClientProtocolsLine(String line) + throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + vb.requiredClientProtocolsLine = line; + return new RelayNetworkStatusVoteImpl(vb.buildVote(), true); + } + + private String requiredRelayProtocolsLine = + "required-relay-protocols Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 " + + "HSRend=1 Link=3-4 LinkAuth=1 Microdesc=1 Relay=1-2"; + + private static RelayNetworkStatusVote + createWithRequiredRelayProtocolsLine(String line) + throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + vb.requiredRelayProtocolsLine = line; + return new RelayNetworkStatusVoteImpl(vb.buildVote(), true); + } + private String flagThresholdsLine = "flag-thresholds " + "stable-uptime=693369 stable-mtbf=153249 fast-speed=40960 " + "guard-wfu=94.669% guard-tk=691200 guard-bw-inc-exits=174080 " @@ -493,6 +542,18 @@ public class RelayNetworkStatusVoteImplTest { if (this.knownFlagsLine != null) { sb.append(this.knownFlagsLine).append("\n"); } + if (this.recommendedClientProtocolsLine != null) { + sb.append(this.recommendedClientProtocolsLine).append("\n"); + } + if (this.recommendedRelayProtocolsLine != null) { + sb.append(this.recommendedRelayProtocolsLine).append("\n"); + } + if (this.requiredClientProtocolsLine != null) { + sb.append(this.requiredClientProtocolsLine).append("\n"); + } + if (this.requiredRelayProtocolsLine != null) { + sb.append(this.requiredRelayProtocolsLine).append("\n"); + } if (this.flagThresholdsLine != null) { sb.append(this.flagThresholdsLine).append("\n"); } @@ -875,6 +936,37 @@ public class RelayNetworkStatusVoteImplTest { "client-versions ,0.2.2.34"); }
+ @Test(expected = DescriptorParseException.class) + public void testRecommendedClientProtocols21() + throws DescriptorParseException { + VoteBuilder.createWithRecommendedClientProtocolsLine( + "recommended-client-protocols Cons=2-1"); + } + + @Test() + public void testRecommendedRelayProtocols0() + throws DescriptorParseException { + RelayNetworkStatusVote vote = + VoteBuilder.createWithRecommendedRelayProtocolsLine( + "recommended-relay-protocols Cons=0"); + assertEquals(new TreeSet<Long>(Arrays.asList(new Long[] { 0L })), + vote.getRecommendedRelayProtocols().get("Cons")); + } + + @Test(expected = DescriptorParseException.class) + public void testRequiredClientProtocols1Max() + throws DescriptorParseException { + VoteBuilder.createWithRequiredClientProtocolsLine( + "recommended-client-protocols Cons=1-4294967296"); + } + + @Test(expected = DescriptorParseException.class) + public void testRequiredRelayProtocolsMinus1() + throws DescriptorParseException { + VoteBuilder.createWithRequiredRelayProtocolsLine( + "recommended-client-protocols Cons=-1"); + } + @Test() public void testPackageNone() throws DescriptorParseException { RelayNetworkStatusVote vote = diff --git a/src/test/java/org/torproject/descriptor/impl/ServerDescriptorImplTest.java b/src/test/java/org/torproject/descriptor/impl/ServerDescriptorImplTest.java index 3769ead..4370321 100644 --- a/src/test/java/org/torproject/descriptor/impl/ServerDescriptorImplTest.java +++ b/src/test/java/org/torproject/descriptor/impl/ServerDescriptorImplTest.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.SortedMap; +import java.util.TreeSet;
/* Test parsing of relay server descriptors. */ public class ServerDescriptorImplTest { @@ -226,7 +227,7 @@ public class ServerDescriptorImplTest { return new RelayServerDescriptorImpl(db.buildDescriptor(), true); }
- private String protocolsLine = "opt protocols Link 1 2 Circuit 1"; + private String protocolsLine = null;
private static ServerDescriptor createWithProtocolsLine( String line) throws DescriptorParseException { @@ -235,6 +236,16 @@ public class ServerDescriptorImplTest { return new RelayServerDescriptorImpl(db.buildDescriptor(), true); }
+ private String protoLine = "proto Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 " + + "HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2"; + + private static ServerDescriptor createWithProtoLine( + String line) throws DescriptorParseException { + DescriptorBuilder db = new DescriptorBuilder(); + db.protoLine = line; + return new RelayServerDescriptorImpl(db.buildDescriptor(), true); + } + private String allowSingleHopExitsLine = null;
private static ServerDescriptor @@ -395,6 +406,9 @@ public class ServerDescriptorImplTest { if (this.protocolsLine != null) { sb.append(this.protocolsLine).append("\n"); } + if (this.protoLine != null) { + sb.append(this.protoLine).append("\n"); + } if (this.allowSingleHopExitsLine != null) { sb.append(this.allowSingleHopExitsLine).append("\n"); } @@ -446,10 +460,10 @@ public class ServerDescriptorImplTest { assertEquals(0, (int) descriptor.getDirPort()); assertEquals("Tor 0.2.2.35 (git-b04388f9e7546a9f) on Linux i686", descriptor.getPlatform()); - assertEquals(Arrays.asList(new Integer[] {1, 2}), - descriptor.getLinkProtocolVersions()); - assertEquals(Arrays.asList(new Integer[] {1}), - descriptor.getCircuitProtocolVersions()); + assertEquals(new TreeSet<Long>(Arrays.asList( + new Long[] { 1L, 2L, 3L, 4L })), descriptor.getProtocols().get("Link")); + assertEquals(new TreeSet<Long>(Arrays.asList( + new Long[] { 1L })), descriptor.getProtocols().get("LinkAuth")); assertEquals(1325390599000L, descriptor.getPublishedMillis()); assertEquals("D8733048FC8EC9102466AD8F3098622BF1BF71FD", descriptor.getFingerprint()); @@ -605,6 +619,16 @@ public class ServerDescriptorImplTest { }
@Test() + public void testProtocolsOpt() throws DescriptorParseException { + ServerDescriptor descriptor = DescriptorBuilder + .createWithProtocolsLine("opt protocols Link 1 2 Circuit 1"); + assertEquals(Arrays.asList(new Integer[] {1, 2}), + descriptor.getLinkProtocolVersions()); + assertEquals(Arrays.asList(new Integer[] {1}), + descriptor.getCircuitProtocolVersions()); + } + + @Test() public void testProtocolsNoOpt() throws DescriptorParseException { ServerDescriptor descriptor = DescriptorBuilder .createWithProtocolsLine("protocols Link 1 2 Circuit 1"); @@ -626,6 +650,21 @@ public class ServerDescriptorImplTest { DescriptorBuilder.createWithProtocolsLine("opt protocols Link 1 2"); }
+ @Test() + public void testProtoGreenPurple() throws DescriptorParseException { + ServerDescriptor descriptor = DescriptorBuilder + .createWithProtoLine("proto Green=23 Purple=42"); + assertEquals(new TreeSet<Long>(Arrays.asList(new Long[] { 23L })), + descriptor.getProtocols().get("Green")); + assertEquals(new TreeSet<Long>(Arrays.asList(new Long[] { 42L })), + descriptor.getProtocols().get("Purple")); + } + + @Test(expected = DescriptorParseException.class) + public void testProtoInvalid() throws DescriptorParseException { + DescriptorBuilder.createWithProtoLine("proto Invalid=1+2+3"); + } + @Test(expected = DescriptorParseException.class) public void testPublishedMissing() throws DescriptorParseException { DescriptorBuilder.createWithPublishedLine(null);
tor-commits@lists.torproject.org