tor-commits
Threads by month
- ----- 2025 -----
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
December 2011
- 17 participants
- 533 discussions
commit 1f59be94b0d8bf20f522296ca9b5a895d36884ac
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Tue Dec 13 20:42:01 2011 +0100
Add a LICENSE.
---
LICENSE | 30 ++++++++++++++++++++++++++++++
1 files changed, 30 insertions(+), 0 deletions(-)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d5b67cd
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright 2011 The Tor Project
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the names of the copyright owners nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
1
0

13 Dec '11
commit 358b92b019a4fc184f9c42b3a8bdbf1c7ff32e32
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Tue Dec 13 20:44:51 2011 +0100
Remove executable bit from many files.
---
0 files changed, 0 insertions(+), 0 deletions(-)
diff --git a/README b/README
old mode 100755
new mode 100644
diff --git a/TODO b/TODO
old mode 100755
new mode 100644
diff --git a/build.xml b/build.xml
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/BridgeDescriptorReader.java b/src/org/torproject/descriptor/BridgeDescriptorReader.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/BridgeExtraInfoDescriptor.java b/src/org/torproject/descriptor/BridgeExtraInfoDescriptor.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/BridgeNetworkStatus.java b/src/org/torproject/descriptor/BridgeNetworkStatus.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/BridgePoolAssignmentReader.java b/src/org/torproject/descriptor/BridgePoolAssignmentReader.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/BridgeServerDescriptor.java b/src/org/torproject/descriptor/BridgeServerDescriptor.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/Descriptor.java b/src/org/torproject/descriptor/Descriptor.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/DescriptorFile.java b/src/org/torproject/descriptor/DescriptorFile.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/DescriptorRequest.java b/src/org/torproject/descriptor/DescriptorRequest.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/DescriptorSourceFactory.java b/src/org/torproject/descriptor/DescriptorSourceFactory.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/DirSourceEntry.java b/src/org/torproject/descriptor/DirSourceEntry.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/GetTorStatsReader.java b/src/org/torproject/descriptor/GetTorStatsReader.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/NetworkStatusEntry.java b/src/org/torproject/descriptor/NetworkStatusEntry.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/RelayDescriptorDownloader.java b/src/org/torproject/descriptor/RelayDescriptorDownloader.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/RelayDescriptorReader.java b/src/org/torproject/descriptor/RelayDescriptorReader.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/RelayExtraInfoDescriptor.java b/src/org/torproject/descriptor/RelayExtraInfoDescriptor.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/RelayNetworkStatusConsensus.java b/src/org/torproject/descriptor/RelayNetworkStatusConsensus.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/RelayNetworkStatusVote.java b/src/org/torproject/descriptor/RelayNetworkStatusVote.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/RelayServerDescriptor.java b/src/org/torproject/descriptor/RelayServerDescriptor.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/TorperfDataReader.java b/src/org/torproject/descriptor/TorperfDataReader.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/example/ConsensusHealthChecker.java b/src/org/torproject/descriptor/example/ConsensusHealthChecker.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/example/MetricsRelayDescriptorAggregator.java b/src/org/torproject/descriptor/example/MetricsRelayDescriptorAggregator.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/example/TorStatusDatabaseUpdater.java b/src/org/torproject/descriptor/example/TorStatusDatabaseUpdater.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/impl/BlockingIteratorImpl.java b/src/org/torproject/descriptor/impl/BlockingIteratorImpl.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/impl/BridgeDescriptorReaderImpl.java b/src/org/torproject/descriptor/impl/BridgeDescriptorReaderImpl.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/impl/DescriptorRequestImpl.java b/src/org/torproject/descriptor/impl/DescriptorRequestImpl.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/impl/DirSourceEntryImpl.java b/src/org/torproject/descriptor/impl/DirSourceEntryImpl.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java b/src/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/impl/RelayDescriptorDownloaderImpl.java b/src/org/torproject/descriptor/impl/RelayDescriptorDownloaderImpl.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/impl/RelayDescriptorReaderImpl.java b/src/org/torproject/descriptor/impl/RelayDescriptorReaderImpl.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java b/src/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java b/src/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java
old mode 100755
new mode 100644
1
0

13 Dec '11
commit 703ba95627833d413cb4085b4d63c44add14ce54
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Tue Dec 13 20:39:33 2011 +0100
Add unit tests for parsing consensuses.
The parser doesn't detect many problems yet. Most of the unit tests check
for the absence of exceptions when they really should test for the
exceptions. This is more like a TODO list for making the parser better.
---
build.xml | 25 +
.../impl/RelayNetworkStatusConsensusImplTest.java | 1084 ++++++++++++++++++++
2 files changed, 1109 insertions(+), 0 deletions(-)
diff --git a/build.xml b/build.xml
index de40dd0..83cd991 100755
--- a/build.xml
+++ b/build.xml
@@ -1,10 +1,12 @@
<project default="run" name="descriptor" basedir=".">
<property name="sources" value="src"/>
<property name="classes" value="classes"/>
+ <property name="tests" value="test"/>
<property name="libs" value="lib"/>
<path id="classpath">
<pathelement path="${classes}"/>
<pathelement location="lib/commons-codec-1.4.jar"/>
+ <pathelement location="lib/junit-4.8.2.jar"/>
</path>
<target name="init">
<mkdir dir="${classes}"/>
@@ -29,5 +31,28 @@
<jar destfile="descriptor.jar"
basedir="${classes}"/>
</target>
+ <target name="test" depends="compile">
+ <javac destdir="${classes}"
+ srcdir="${tests}"
+ source="1.5"
+ target="1.5"
+ debug="true"
+ deprecation="true"
+ optimize="false"
+ failonerror="true"
+ includeantruntime="false">
+ <classpath>
+ <fileset dir="${libs}"/>
+ </classpath>
+ </javac>
+ <junit haltonfailure="true" printsummary="off">
+ <classpath refid="classpath"/>
+ <formatter type="plain" usefile="false"/>
+ <batchtest>
+ <fileset dir="${classes}"
+ includes="**/*Test.class"/>
+ </batchtest>
+ </junit>
+ </target>
</project>
diff --git a/test/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImplTest.java b/test/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImplTest.java
new file mode 100644
index 0000000..4a7a7be
--- /dev/null
+++ b/test/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImplTest.java
@@ -0,0 +1,1084 @@
+/* Copyright 2011 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.descriptor.impl;
+
+import org.torproject.descriptor.RelayNetworkStatusConsensus;
+import org.torproject.descriptor.impl.RelayNetworkStatusConsensusImpl;
+
+import java.util.*;
+
+import org.junit.*;
+import org.junit.rules.*;
+import static org.junit.Assert.*;
+
+/* Test parsing of network status consensuses. The main focus is on
+ * making sure that the parser is as robust as possible and doesn't break,
+ * no matter what gets fed into it. A secondary focus is to ensure that
+ * a parsed consensus is fully compatible to dir-spec.txt. */
+public class RelayNetworkStatusConsensusImplTest {
+
+ /* Helper class to build a consensus based on default data and
+ * modifications requested by test methods. */
+ private static class ConsensusBuilder {
+ private String networkStatusVersionLine = "network-status-version 3";
+ private static void createWithNetworkStatusVersionLine(String line) {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.networkStatusVersionLine = line;
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+ private String voteStatusLine = "vote-status consensus";
+ private static void createWithVoteStatusLine(String line) {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.voteStatusLine = line;
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+ private String consensusMethodLine = "consensus-method 11";
+ private static void createWithConsensusMethodLine(String line) {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.consensusMethodLine = line;
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+ private String validAfterLine = "valid-after 2011-11-30 09:00:00";
+ private static void createWithValidAfterLine(String line) {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.validAfterLine = line;
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+ private String freshUntilLine = "fresh-until 2011-11-30 10:00:00";
+ private static void createWithFreshUntilLine(String line) {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.freshUntilLine = line;
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+ private String validUntilLine = "valid-until 2011-11-30 12:00:00";
+ private static void createWithValidUntilLine(String line) {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.validUntilLine = line;
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+ private String votingDelayLine = "voting-delay 300 300";
+ private static void createWithVotingDelayLine(String line) {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.votingDelayLine = line;
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+ private String clientVersionsLine = "client-versions 0.2.1.31,"
+ + "0.2.2.34,0.2.3.6-alpha,0.2.3.7-alpha,0.2.3.8-alpha";
+ private static void createWithClientVersionsLine(String line) {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.clientVersionsLine = line;
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+ private String serverVersionsLine = "server-versions 0.2.1.31,"
+ + "0.2.2.34,0.2.3.6-alpha,0.2.3.7-alpha,0.2.3.8-alpha";
+ private static void createWithServerVersionsLine(String line) {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.serverVersionsLine = line;
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+ private String knownFlagsLine = "known-flags Authority BadExit Exit "
+ + "Fast Guard HSDir Named Running Stable Unnamed V2Dir Valid";
+ private static void createWithKnownFlagsLine(String line) {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.knownFlagsLine = line;
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+ private String paramsLine = "params "
+ + "CircuitPriorityHalflifeMsec=30000 bwauthbestratio=1 "
+ + "bwauthcircs=1 bwauthdescbw=0 bwauthkp=10000 bwauthpid=1 "
+ + "bwauthtd=5000 bwauthti=50000 bwauthtidecay=5000 cbtnummodes=3 "
+ + "cbtquantile=80 circwindow=1000 refuseunknownexits=1";
+ private static void createWithParamsLine(String line) {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.paramsLine = line;
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+ private List<String> dirSources = new ArrayList<String>();
+ private List<String> statusEntries = new ArrayList<String>();
+ private String directoryFooterLine = "directory-footer";
+ private static void createWithDirectoryFooterLine(String line) {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.directoryFooterLine = line;
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+ private String bandwidthWeightsLine = "bandwidth-weights Wbd=285 "
+ + "Wbe=0 Wbg=0 Wbm=10000 Wdb=10000 Web=10000 Wed=1021 Wee=10000 "
+ + "Weg=1021 Wem=10000 Wgb=10000 Wgd=8694 Wgg=10000 Wgm=10000 "
+ + "Wmb=10000 Wmd=285 Wme=0 Wmg=0 Wmm=10000";
+ private static void createWithBandwidthWeightsLine(String line) {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.bandwidthWeightsLine = line;
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+ private List<String> directorySignatures = new ArrayList<String>();
+ private ConsensusBuilder() {
+ this.dirSources.add("dir-source tor26 "
+ + "14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4 86.59.21.38 "
+ + "86.59.21.38 80 443\ncontact Peter Palfrader\nvote-digest "
+ + "0333880AA67ED7E07C11108656D0C8D6DD1C7E5D");
+ this.dirSources.add("dir-source ides "
+ + "27B6B5996C426270A5C95488AA5BCEB6BCC86956 216.224.124.114 "
+ + "216.224.124.114 9030 9090\ncontact Mike Perry "
+ + "<mikeperryTAfsckedTODorg>\nvote-digest "
+ + "1A8827ECD53184F7A771EFA9B3D30DC473FE8670");
+ this.statusEntries.add("r ANONIONROUTER "
+ + "AHhuQ8zFQJdT8l42Axxc6m6kNwI yEMZ5B/JQixNZgC1+2rLe0pR9rU "
+ + "2011-11-30 02:52:58 93.128.66.111 24051 24052\ns Exit Fast "
+ + "Named Running V2Dir Valid\nv Tor 0.2.2.34\nw "
+ + "Bandwidth=1100\np reject 25,119,135-139,6881-6999");
+ this.statusEntries.add("r Magellan AHlabo2RwnD8I7MPOIpJVVPgGJQ "
+ + "rB/7uzI4mU38bZ9cSXEy+Z/4Cuk 2011-11-30 05:37:35 "
+ + "188.177.149.216 9001 9030\ns Fast Named Running V2Dir "
+ + "Valid\nv Tor 0.2.2.34\nw Bandwidth=367\np reject 1-65535");
+ this.directorySignatures.add("directory-signature "
+ + "14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4 "
+ + "3509BA5A624403A905C74DA5C8A0CEC9E0D3AF86\n"
+ + "-----BEGIN SIGNATURE-----\n"
+ + "NYRcTWAMRiYYiGW0hIbzeZKU6sefg98AwwXrQUCudO8wfA1cfgttTDoscB9I"
+ + "TbOY\n"
+ + "x+c30jV/qQCMamTAEDGgJTw8KghI32vytupKallI1EjCOF8UvL1UnALgpaR7"
+ + "sZ3W\n"
+ + "7WQZVVrWDtnYaULOEKfwnGnRC7WwE+YRSysbzwwCVs0=\n"
+ + "-----END SIGNATURE-----");
+ this.directorySignatures.add("directory-signature "
+ + "27B6B5996C426270A5C95488AA5BCEB6BCC86956 "
+ + "D5C30C15BB3F1DA27669C2D88439939E8F418FCF\n"
+ + "-----BEGIN SIGNATURE-----\n"
+ + "DzFPj3vyYrCv0W3r8qDPJPlmeLnadY+drjWkdOqO66Ih/hAWBb9KcBJAX1sX"
+ + "aDA7\n"
+ + "/iSaDhduBXuJdcu8lbmMP8d6uYBdRjHXqWDXySUZAkSfPB4JJPNGvfoQA/qe"
+ + "by7E\n"
+ + "5374pPPL6WwCLJHkKtk21S9oHDmFBdlZq7JWQelWlVM=\n"
+ + "-----END SIGNATURE-----");
+ }
+ private byte[] buildConsensus() {
+ StringBuilder sb = new StringBuilder();
+ this.appendHeader(sb);
+ this.appendBody(sb);
+ this.appendFooter(sb);
+ return sb.toString().getBytes();
+ }
+ private void appendHeader(StringBuilder sb) {
+ if (this.networkStatusVersionLine != null) {
+ sb.append(this.networkStatusVersionLine + "\n");
+ }
+ if (this.voteStatusLine != null) {
+ sb.append(this.voteStatusLine + "\n");
+ }
+ if (this.consensusMethodLine != null) {
+ sb.append(this.consensusMethodLine + "\n");
+ }
+ if (this.validAfterLine != null) {
+ sb.append(this.validAfterLine + "\n");
+ }
+ if (this.freshUntilLine != null) {
+ sb.append(this.freshUntilLine + "\n");
+ }
+ if (this.validUntilLine != null) {
+ sb.append(this.validUntilLine + "\n");
+ }
+ if (this.votingDelayLine != null) {
+ sb.append(this.votingDelayLine + "\n");
+ }
+ if (this.clientVersionsLine != null) {
+ sb.append(this.clientVersionsLine + "\n");
+ }
+ if (this.serverVersionsLine != null) {
+ sb.append(this.serverVersionsLine + "\n");
+ }
+ if (this.knownFlagsLine != null) {
+ sb.append(this.knownFlagsLine + "\n");
+ }
+ if (this.paramsLine != null) {
+ sb.append(this.paramsLine + "\n");
+ }
+ for (String dirSource : this.dirSources) {
+ sb.append(dirSource + "\n");
+ }
+ }
+ private void appendBody(StringBuilder sb) {
+ for (String statusEntry : this.statusEntries) {
+ sb.append(statusEntry + "\n");
+ }
+ }
+ private void appendFooter(StringBuilder sb) {
+ if (this.directoryFooterLine != null) {
+ sb.append(this.directoryFooterLine + "\n");
+ }
+ if (this.bandwidthWeightsLine != null) {
+ sb.append(this.bandwidthWeightsLine + "\n");
+ }
+ for (String directorySignature : this.directorySignatures) {
+ sb.append(directorySignature + "\n");
+ }
+ }
+ }
+
+ /* Helper class to build a directory source based on default data and
+ * modifications requested by test methods. */
+ private static class DirSourceBuilder {
+ private static void createWithDirSource(String dirSourceString) {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.dirSources.add(dirSourceString);
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+ private String nickname = "gabelmoo";
+ private static void createWithNickname(String string) {
+ DirSourceBuilder dsb = new DirSourceBuilder();
+ dsb.nickname = string;
+ createWithDirSource(dsb.buildDirSource());
+ }
+ private String identity = "ED03BB616EB2F60BEC80151114BB25CEF515B226";
+ private static void createWithIdentity(String string) {
+ DirSourceBuilder dsb = new DirSourceBuilder();
+ dsb.identity = string;
+ createWithDirSource(dsb.buildDirSource());
+ }
+ private String hostName = "212.112.245.170";
+ private static void createWithHostName(String string) {
+ DirSourceBuilder dsb = new DirSourceBuilder();
+ dsb.hostName = string;
+ createWithDirSource(dsb.buildDirSource());
+ }
+ private String address = "212.112.245.170";
+ private static void createWithAddress(String string) {
+ DirSourceBuilder dsb = new DirSourceBuilder();
+ dsb.address = string;
+ createWithDirSource(dsb.buildDirSource());
+ }
+ private String dirPort = "80";
+ private static void createWithDirPort(String string) {
+ DirSourceBuilder dsb = new DirSourceBuilder();
+ dsb.dirPort = string;
+ createWithDirSource(dsb.buildDirSource());
+ }
+ private String orPort = "443";
+ private static void createWithOrPort(String string) {
+ DirSourceBuilder dsb = new DirSourceBuilder();
+ dsb.orPort = string;
+ createWithDirSource(dsb.buildDirSource());
+ }
+ private String contactLine = "contact 4096R/C5AA446D Sebastian Hahn "
+ + "<tor(a)sebastianhahn.net>";
+ private static void createWithContactLine(String line) {
+ DirSourceBuilder dsb = new DirSourceBuilder();
+ dsb.contactLine = line;
+ createWithDirSource(dsb.buildDirSource());
+ }
+ private String voteDigestLine =
+ "vote-digest 0F398A5834D2C139E1D92310B09F814F243354D1";
+ private static void createWithVoteDigestLine(String line) {
+ DirSourceBuilder dsb = new DirSourceBuilder();
+ dsb.voteDigestLine = line;
+ createWithDirSource(dsb.buildDirSource());
+ }
+ private String buildDirSource() {
+ StringBuilder sb = new StringBuilder();
+ String dirSourceLine = "dir-source " + this.nickname + " "
+ + this.identity + " " + this.hostName + " " + this.address + " "
+ + this.dirPort + " " + this.orPort;
+ sb.append(dirSourceLine + "\n");
+ if (this.contactLine != null) {
+ sb.append(this.contactLine + "\n");
+ }
+ if (this.voteDigestLine != null) {
+ sb.append(this.voteDigestLine + "\n");
+ }
+ String dirSourceWithTrailingNewLine = sb.toString();
+ String dirSource = dirSourceWithTrailingNewLine.substring(0,
+ dirSourceWithTrailingNewLine.length() - 1);
+ return dirSource;
+ }
+ }
+
+ /* Helper class to build a status entry based on default data and
+ * modifications requested by test methods. */
+ private static class StatusEntryBuilder {
+ private static void createWithStatusEntry(String statusEntryString) {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.statusEntries.add(statusEntryString);
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+ private String nickname = "right2privassy3";
+ private static void createWithNickname(String string) {
+ StatusEntryBuilder seb = new StatusEntryBuilder();
+ seb.nickname = string;
+ createWithStatusEntry(seb.buildStatusEntry());
+ }
+ private String fingerprintBase64 = "ADQ6gCT3DiFHKPDFr3rODBUI8HM";
+ private static void createWithFingerprintBase64(String string) {
+ StatusEntryBuilder seb = new StatusEntryBuilder();
+ seb.fingerprintBase64 = string;
+ createWithStatusEntry(seb.buildStatusEntry());
+ }
+ private String descriptorBase64 = "Yiti+nayuT2Efe2X1+M4nslwVuU";
+ private static void createWithDescriptorBase64(String string) {
+ StatusEntryBuilder seb = new StatusEntryBuilder();
+ seb.descriptorBase64 = string;
+ createWithStatusEntry(seb.buildStatusEntry());
+ }
+ private String publishedString = "2011-11-29 21:34:27";
+ private static void createWithPublishedString(String string) {
+ StatusEntryBuilder seb = new StatusEntryBuilder();
+ seb.publishedString = string;
+ createWithStatusEntry(seb.buildStatusEntry());
+ }
+ private String address = "50.63.8.215";
+ private static void createWithAddress(String string) {
+ StatusEntryBuilder seb = new StatusEntryBuilder();
+ seb.address = string;
+ createWithStatusEntry(seb.buildStatusEntry());
+ }
+ private String orPort = "9023";
+ private static void createWithOrPort(String string) {
+ StatusEntryBuilder seb = new StatusEntryBuilder();
+ seb.orPort = string;
+ createWithStatusEntry(seb.buildStatusEntry());
+ }
+ private String dirPort = "0";
+ private static void createWithDirPort(String string) {
+ StatusEntryBuilder seb = new StatusEntryBuilder();
+ seb.dirPort = string;
+ createWithStatusEntry(seb.buildStatusEntry());
+ }
+ private String sLine = "s Exit Fast Named Running Stable Valid";
+ private static void createWithSLine(String line) {
+ StatusEntryBuilder seb = new StatusEntryBuilder();
+ seb.sLine = line;
+ createWithStatusEntry(seb.buildStatusEntry());
+ }
+ private String vLine = "v Tor 0.2.1.29 (r8e9b25e6c7a2e70c)";
+ private static void createWithVLine(String line) {
+ StatusEntryBuilder seb = new StatusEntryBuilder();
+ seb.vLine = line;
+ createWithStatusEntry(seb.buildStatusEntry());
+ }
+ private String wLine = "w Bandwidth=1";
+ private static void createWithWLine(String line) {
+ StatusEntryBuilder seb = new StatusEntryBuilder();
+ seb.wLine = line;
+ createWithStatusEntry(seb.buildStatusEntry());
+ }
+ private String pLine = "p accept 80,1194,1220,1293";
+ private static void createWithPLine(String line) {
+ StatusEntryBuilder seb = new StatusEntryBuilder();
+ seb.pLine = line;
+ createWithStatusEntry(seb.buildStatusEntry());
+ }
+ private String buildStatusEntry() {
+ StringBuilder sb = new StringBuilder();
+ String rLine = "r " + nickname + " " + fingerprintBase64 + " "
+ + descriptorBase64 + " " + publishedString + " " + address + " "
+ + orPort + " " + dirPort;
+ sb.append(rLine + "\n");
+ if (this.sLine != null) {
+ sb.append(this.sLine + "\n");
+ }
+ if (this.vLine != null) {
+ sb.append(this.vLine + "\n");
+ }
+ if (this.wLine != null) {
+ sb.append(this.wLine + "\n");
+ }
+ if (this.pLine != null) {
+ sb.append(this.pLine + "\n");
+ }
+ String statusEntryWithTrailingNewLine = sb.toString();
+ String statusEntry = statusEntryWithTrailingNewLine.substring(0,
+ statusEntryWithTrailingNewLine.length() - 1);
+ return statusEntry;
+ }
+ }
+
+ /* Helper class to build a directory signature based on default data and
+ * modifications requested by test methods. */
+ private static class DirectorySignatureBuilder {
+ private static void createWithDirectorySignature(
+ String directorySignatureString) {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.directorySignatures.add(directorySignatureString);
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+ private String identity = "ED03BB616EB2F60BEC80151114BB25CEF515B226";
+ private static void createWithIdentity(String string) {
+ DirectorySignatureBuilder dsb = new DirectorySignatureBuilder();
+ dsb.identity = string;
+ createWithDirectorySignature(dsb.buildDirectorySignature());
+ }
+ private String signingKey =
+ "845CF1D0B370CA443A8579D18E7987E7E532F639";
+ private static void createWithSigningKey(String string) {
+ DirectorySignatureBuilder dsb = new DirectorySignatureBuilder();
+ dsb.signingKey = string;
+ createWithDirectorySignature(dsb.buildDirectorySignature());
+ }
+ private String buildDirectorySignature() {
+ String directorySignature = "directory-signature " + identity + " "
+ + signingKey + "\n"
+ + "-----BEGIN SIGNATURE-----\n"
+ + "gE64+/4BH43v1+7jS9FK1tu2+94at8xhVSPn4O/PpOx7b0Yb+S1hac1QHAiS"
+ + "Ll+k\n"
+ + "6OiANKzhj54WHSrUswBPrOzjmKj0OhGXSAe5nHZUFX9a1MDQLDCoZBj536X9"
+ + "P3JG\n"
+ + "z89A+wrsN17I5490y66AEvws54BYZMbgRfp8HXn/0Ss=\n"
+ + "-----END SIGNATURE-----";
+ return directorySignature;
+ }
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testSampleConsensus() {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+
+ /* TODO Throwing a RuntimeException here (and in most places below) is
+ * bad. Maybe we should define a DescriptorParseException. */
+ @Test(expected = RuntimeException.class)
+ public void testNetworkStatusVersionNoLine() {
+ ConsensusBuilder.createWithNetworkStatusVersionLine(null);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testNetworkStatusVersionPrefixLineAtChar() {
+ ConsensusBuilder.createWithNetworkStatusVersionLine(
+ "@consensus\nnetwork-status-version 3");
+ }
+
+ /* TODO This doesn't break. Should it? */
+ @Test()
+ public void testNetworkStatusVersionPrefixDirectoryFooter() {
+ ConsensusBuilder.createWithNetworkStatusVersionLine(
+ "directory-footer\nnetwork-status-version 3");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testNetworkStatusVersionPrefixLinePoundChar() {
+ ConsensusBuilder.createWithNetworkStatusVersionLine(
+ "#consensus\nnetwork-status-version 3");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testNetworkStatusVersionNoSpace() {
+ ConsensusBuilder.createWithNetworkStatusVersionLine(
+ "network-status-version");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testNetworkStatusVersionOneSpace() {
+ ConsensusBuilder.createWithNetworkStatusVersionLine(
+ "network-status-version ");
+ }
+
+ /* TODO The parser should only accept version 3 and throw an Exception
+ * here. */
+ @Test()
+ public void testNetworkStatusVersion42() {
+ ConsensusBuilder.createWithNetworkStatusVersionLine(
+ "network-status-version 42");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testNetworkStatusVersionFourtyTwo() {
+ ConsensusBuilder.createWithNetworkStatusVersionLine(
+ "network-status-version FourtyTwo");
+ }
+
+ /* TODO Shouldn't this throw an exception? */
+ @Test()
+ public void testVoteStatusNoLine() {
+ ConsensusBuilder.createWithVoteStatusLine(null);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testVoteStatusNoSpace() {
+ ConsensusBuilder.createWithVoteStatusLine("vote-status");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testVoteStatusOneSpace() {
+ ConsensusBuilder.createWithVoteStatusLine("vote-status ");
+ }
+
+ /* TODO Should this be accepted or not? */
+ @Test(expected = RuntimeException.class)
+ public void testVoteStatusConsensusOneSpace() {
+ ConsensusBuilder.createWithVoteStatusLine("vote-status consensus ");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testVoteStatusVote() {
+ ConsensusBuilder.createWithVoteStatusLine("vote-status vote");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testVoteStatusTheMagicVoteStatus() {
+ ConsensusBuilder.createWithVoteStatusLine(
+ "vote-status TheMagicVoteStatus");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testConsensusMethodNoLine() {
+ ConsensusBuilder.createWithConsensusMethodLine(null);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testConsensusMethodNoSpace() {
+ ConsensusBuilder.createWithConsensusMethodLine("consensus-method");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testConsensusMethodOneSpace() {
+ ConsensusBuilder.createWithConsensusMethodLine("consensus-method ");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testConsensusMethodEleven() {
+ ConsensusBuilder.createWithConsensusMethodLine(
+ "consensus-method eleven");
+ }
+
+ /* TODO We shouldn't allow negative values here. */
+ @Test()
+ public void testConsensusMethodMinusOne() {
+ ConsensusBuilder.createWithConsensusMethodLine("consensus-method -1");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testConsensusMethodNinePeriod() {
+ ConsensusBuilder.createWithConsensusMethodLine("consensus-method "
+ + "999999999999999999999999999999999999999999999999999999999999");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testValidAfterNoLine() {
+ ConsensusBuilder.createWithValidAfterLine(null);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testValidAfterNoSpace() {
+ ConsensusBuilder.createWithValidAfterLine("valid-after");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testValidAfterOneSpace() {
+ ConsensusBuilder.createWithValidAfterLine("valid-after ");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testValidAfterLongAgo() {
+ ConsensusBuilder.createWithValidAfterLine("valid-after long ago");
+ }
+
+ /* TODO Wow, this should really throw an exception! */
+ @Test()
+ public void testValidAfterFeb30() {
+ ConsensusBuilder.createWithValidAfterLine(
+ "valid-after 2011-02-30 09:00:00");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testFreshUntilNoLine() {
+ ConsensusBuilder.createWithFreshUntilLine(null);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testFreshUntilAroundTen() {
+ ConsensusBuilder.createWithFreshUntilLine(
+ "fresh-until 2011-11-30 around ten");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testValidUntilTomorrowMorning() {
+ ConsensusBuilder.createWithValidUntilLine(
+ "valid-until tomorrow morning");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testVotingDelayNoLine() {
+ ConsensusBuilder.createWithVotingDelayLine(null);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testVotingDelayNoSpace() {
+ ConsensusBuilder.createWithVotingDelayLine("voting-delay");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testVotingDelayOneSpace() {
+ ConsensusBuilder.createWithVotingDelayLine("voting-delay ");
+ }
+
+ /* TODO This should throw an exception. */
+ @Test()
+ public void testVotingDelayTriple() {
+ ConsensusBuilder.createWithVotingDelayLine(
+ "voting-delay 300 300 300");
+ }
+
+ /* TODO This should throw an exception. */
+ @Test()
+ public void testVotingDelaySingle() {
+ ConsensusBuilder.createWithVotingDelayLine("voting-delay 300");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testVotingDelayOneTwo() {
+ ConsensusBuilder.createWithVotingDelayLine("voting-delay one two");
+ }
+
+ /* TODO Should this be forbidden? */
+ @Test()
+ public void testClientVersionsNoLineServerVersionsNoLine() {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.clientVersionsLine = null;
+ cb.serverVersionsLine = null;
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+
+ /* TODO Should this be forbidden? */
+ @Test()
+ public void testServerVersionsNoLine() {
+ ConsensusBuilder.createWithServerVersionsLine(null);
+ }
+
+ /* TODO Should this be forbidden? */
+ @Test()
+ public void testClientVersionsNoLine() {
+ ConsensusBuilder.createWithClientVersionsLine(null);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testClientVersionsNoSpace() {
+ ConsensusBuilder.createWithClientVersionsLine("client-versions");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testClientVersionsOneSpace() {
+ ConsensusBuilder.createWithClientVersionsLine("client-versions ");
+ }
+
+ /* TODO This should be caught. */
+ @Test()
+ public void testClientVersionsComma() {
+ ConsensusBuilder.createWithClientVersionsLine("client-versions ,");
+ }
+
+ /* TODO This should be caught. */
+ @Test()
+ public void testClientVersionsCommaVersion() {
+ ConsensusBuilder.createWithClientVersionsLine(
+ "client-versions ,0.2.2.34");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testKnownFlagsNoLine() {
+ ConsensusBuilder.createWithKnownFlagsLine(null);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testKnownFlagsNoSpace() {
+ ConsensusBuilder.createWithKnownFlagsLine("known-flags");
+ }
+
+ /* TODO Looks like this okay, right? */
+ @Test()
+ public void testKnownFlagsOneSpace() {
+ ConsensusBuilder.createWithKnownFlagsLine("known-flags ");
+ }
+
+ /* TODO Make sure that the params line is optional. */
+ @Test()
+ public void testParamsNoLine() {
+ ConsensusBuilder.createWithParamsLine(null);
+ }
+
+ /* TODO If it's okay to provide an empty params line, this one should be
+ * accepted, too. */
+ @Test(expected = RuntimeException.class)
+ public void testParamsNoSpace() {
+ ConsensusBuilder.createWithParamsLine("params");
+ }
+
+ /* TODO Is this okay? */
+ @Test()
+ public void testParamsOneSpace() {
+ ConsensusBuilder.createWithParamsLine("params ");
+ }
+
+ /* TODO Hmm, and this is okay? */
+ @Test()
+ public void testParamsThreeSpaces() {
+ ConsensusBuilder.createWithParamsLine("params ");
+ }
+
+ /* TODO The error message here looked strange. Investigate. */
+ @Test(expected = RuntimeException.class)
+ public void testParamsNoEqualSign() {
+ ConsensusBuilder.createWithParamsLine("params key-value");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDirSourceIdentityTooShort() {
+ DirSourceBuilder.createWithIdentity("ED03BB616EB2F60BEC8015111");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDirSourceIdentityTooLong() {
+ DirSourceBuilder.createWithIdentity("ED03BB616EB2F60BEC8015111"
+ + "4BB25CEF515B226ED03BB616EB2F60BEC8");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDirSourceAddress24() {
+ DirSourceBuilder.createWithAddress("212.112.245");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDirSourceAddress40() {
+ DirSourceBuilder.createWithAddress("212.112.245.170.123");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDirSourceDirPortMinusOne() {
+ DirSourceBuilder.createWithDirPort("-1");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDirSourceDirPort66666() {
+ DirSourceBuilder.createWithDirPort("66666");
+ }
+
+ /* TODO We should check this. */
+ @Test(expected = RuntimeException.class)
+ public void testDirSourceDirPortOnions() {
+ DirSourceBuilder.createWithDirPort("onions");
+ }
+
+ /* TODO We should check this. */
+ @Test(expected = RuntimeException.class)
+ public void testDirSourceOrPortOnions() {
+ DirSourceBuilder.createWithOrPort("onions");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDirSourceContactNoLine() {
+ DirSourceBuilder.createWithContactLine(null);
+ }
+
+ /* TODO We should check this. */
+ @Test(expected = RuntimeException.class)
+ public void testDirSourceContactLineNoSpace() {
+ DirSourceBuilder.createWithContactLine("contact");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDirSourceContactLineOneSpace() {
+ DirSourceBuilder.createWithContactLine("contact ");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDirSourceVoteDigestNoLine() {
+ DirSourceBuilder.createWithVoteDigestLine(null);
+ }
+
+ /* TODO We should check this. */
+ @Test(expected = RuntimeException.class)
+ public void testDirSourceVoteDigestLineNoSpace() {
+ DirSourceBuilder.createWithVoteDigestLine("vote-digest");
+ }
+
+ /* TODO We should check this. */
+ @Test(expected = RuntimeException.class)
+ public void testDirSourceVoteDigestLineOneSpace() {
+ DirSourceBuilder.createWithVoteDigestLine("vote-digest ");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testNicknameNotAllowedChars() {
+ StatusEntryBuilder.createWithNickname("notAll()wed");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testNicknameTooLong() {
+ StatusEntryBuilder.createWithNickname("1234567890123456789tooLong");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testFingerprintTooShort() {
+ StatusEntryBuilder.createWithFingerprintBase64("TooShort");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testFingerprintEndsWithEqualSign() {
+ StatusEntryBuilder.createWithFingerprintBase64(
+ "ADQ6gCT3DiFHKPDFr3rODBUI8H=");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testFingerprintTooLong() {
+ StatusEntryBuilder.createWithFingerprintBase64(
+ "ADQ6gCT3DiFHKPDFr3rODBUI8HMAAAA");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDescriptorTooShort() {
+ StatusEntryBuilder.createWithDescriptorBase64("TooShort");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDescriptorEndsWithEqualSign() {
+ StatusEntryBuilder.createWithDescriptorBase64(
+ "ADQ6gCT3DiFHKPDFr3rODBUI8H=");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDescriptorTooLong() {
+ StatusEntryBuilder.createWithDescriptorBase64(
+ "Yiti+nayuT2Efe2X1+M4nslwVuUAAAA");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testPublished1960() {
+ StatusEntryBuilder.createWithPublishedString("1960-11-29 21:34:27");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testPublished9999() {
+ StatusEntryBuilder.createWithPublishedString("9999-11-29 21:34:27");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testAddress256() {
+ StatusEntryBuilder.createWithAddress("256.63.8.215");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testAddress24() {
+ StatusEntryBuilder.createWithAddress("50.63.8/24");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testAddressV6() {
+ StatusEntryBuilder.createWithAddress("::1");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testOrPort66666() {
+ StatusEntryBuilder.createWithOrPort("66666");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testOrPortEighty() {
+ StatusEntryBuilder.createWithOrPort("eighty");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDirPortMinusOne() {
+ StatusEntryBuilder.createWithDirPort("-1");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDirPortZero() {
+ StatusEntryBuilder.createWithDirPort("zero");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testSLineNoSpace() {
+ StatusEntryBuilder.createWithSLine("s");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testSLineOneSpace() {
+ StatusEntryBuilder.createWithSLine("s ");
+ }
+
+ /* TODO We should detect this. */
+ @Test()
+ public void testTwoSLines() {
+ StatusEntryBuilder sb = new StatusEntryBuilder();
+ sb.sLine = sb.sLine + "\n" + sb.sLine;
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.statusEntries.add(sb.buildStatusEntry());
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+
+ /* TODO This is not allowed, right? */
+ @Test(expected = RuntimeException.class)
+ public void testWLineNoSpace() {
+ StatusEntryBuilder.createWithSLine("w");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testWLineOneSpace() {
+ StatusEntryBuilder.createWithSLine("w ");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testWLineWarpSeven() {
+ StatusEntryBuilder.createWithWLine("w Warp=7");
+ }
+
+ /* TODO We should detect this. */
+ @Test()
+ public void testTwoWLines() {
+ StatusEntryBuilder sb = new StatusEntryBuilder();
+ sb.wLine = sb.wLine + "\n" + sb.wLine;
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.statusEntries.add(sb.buildStatusEntry());
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testPLineNoPolicy() {
+ StatusEntryBuilder.createWithPLine("p 80");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testPLineNoPorts() {
+ StatusEntryBuilder.createWithPLine("p accept");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testPLineNoPolicyNoPorts() {
+ StatusEntryBuilder.createWithPLine("p ");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testPLineProject() {
+ StatusEntryBuilder.createWithPLine("p project 80");
+ }
+
+ /* TODO We should detect this. */
+ @Test()
+ public void testTwoPLines() {
+ StatusEntryBuilder sb = new StatusEntryBuilder();
+ sb.pLine = sb.pLine + "\n" + sb.pLine;
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.statusEntries.add(sb.buildStatusEntry());
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+
+ /* TODO Should we allow this? */
+ @Test(expected = RuntimeException.class)
+ public void testNoStatusEntries() {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.statusEntries.clear();
+ new RelayNetworkStatusConsensusImpl(cb.buildConsensus());
+ }
+
+ /* TODO Why does this not break? Ah, maybe it just leaves out one
+ * status entry. Ugh. It should break! */
+ @Test()
+ public void testDirectoryFooterNoLine() {
+ ConsensusBuilder.createWithDirectoryFooterLine(null);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testDirectoryFooterLineSpace() {
+ ConsensusBuilder.createWithDirectoryFooterLine("directory-footer ");
+ }
+
+ /* TODO Make sure that this is really okay in the code. */
+ @Test()
+ public void testBandwidthWeightsNoLine() {
+ ConsensusBuilder.createWithBandwidthWeightsLine(null);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testBandwidthWeightsLineNoSpace() {
+ ConsensusBuilder.createWithBandwidthWeightsLine("bandwidth-weights");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testBandwidthWeightsLineOneSpace() {
+ ConsensusBuilder.createWithBandwidthWeightsLine("bandwidth-weights ");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testBandwidthWeightsLineNoEqualSign() {
+ ConsensusBuilder.createWithBandwidthWeightsLine(
+ "bandwidth-weights Wbd-285");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDirectorySignatureIdentityTooShort() {
+ DirectorySignatureBuilder.createWithIdentity("ED03BB616EB2F60");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDirectorySignatureIdentityTooLong() {
+ DirectorySignatureBuilder.createWithIdentity(
+ "ED03BB616EB2F60BEC80151114BB25CEF515B226ED03BB616EB2F60BEC");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDirectorySignatureSigningKeyTooShort() {
+ DirectorySignatureBuilder.createWithSigningKey("845CF1D0B370CA4");
+ }
+
+ /* TODO We should check this. */
+ @Test()
+ public void testDirectorySignatureSigningKeyTooLong() {
+ DirectorySignatureBuilder.createWithSigningKey(
+ "845CF1D0B370CA443A8579D18E7987E7E532F639845CF1D0B370CA443A");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testNonAsciiByte20() {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ byte[] consensusBytes = cb.buildConsensus();
+ consensusBytes[20] = (byte) 200;
+ new RelayNetworkStatusConsensusImpl(consensusBytes);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testNonAsciiByteMinusOne() {
+ ConsensusBuilder cb = new ConsensusBuilder();
+ cb.networkStatusVersionLine = "Xnetwork-status-version 3";
+ byte[] consensusBytes = cb.buildConsensus();
+ consensusBytes[0] = (byte) 200;
+ new RelayNetworkStatusConsensusImpl(consensusBytes);
+ }
+}
+
1
0
commit 8164af5ba0e571dfcd735274e1c4079c79a6fd8d
Author: Damian Johnson <atagar(a)torproject.org>
Date: Mon Dec 12 18:24:44 2011 -0800
Using input version string for __str__
Originally we reconstructed version strings from its components since that's
all the Version class had (a separate factory translated strings into Version
objects). However, that's no longer the case and much simpler if we just have
the __str__ method provide the constructing string rather than try to recreate
it.
patch by gsathya
---
stem/version.py | 14 +++-----------
1 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/stem/version.py b/stem/version.py
index 214e06a..26080cc 100644
--- a/stem/version.py
+++ b/stem/version.py
@@ -94,6 +94,7 @@ class Version:
ValueError if input isn't a valid tor version
"""
+ self.version_str = version_str
m = re.match(r'^([0-9]+).([0-9]+).([0-9]+)(.[0-9]+)?(-\S*)?$', version_str)
if m:
@@ -114,19 +115,10 @@ class Version:
def __str__(self):
"""
- Provides the normal representation for the version, for instance:
- "0.2.2.23-alpha"
+ Provides the string used to construct the Version.
"""
- suffix = ""
-
- if self.patch:
- suffix += ".%i" % self.patch
-
- if self.status:
- suffix += "-%s" % self.status
-
- return "%i.%i.%i%s" % (self.major, self.minor, self.micro, suffix)
+ return self.version_str
def __cmp__(self, other):
"""
1
0
commit 4d0d5598eec4936f103293802c217377ada8751f
Author: Damian Johnson <atagar(a)torproject.org>
Date: Mon Dec 12 18:51:03 2011 -0800
Joining get_protocolinfo_* functions
Having a joined socket constructor and PROTOCOLINFO query doesn't make sense.
It allowed the user to make a PROTOCOLINFO query in a single line without a
leftover socket but that use case is so rare that it's fine for it to take a
couple more lines. This api is simpler and better for the common case.
---
stem/connection.py | 90 +++++++-------------------------
test/integ/connection/protocolinfo.py | 23 ++++++---
2 files changed, 35 insertions(+), 78 deletions(-)
diff --git a/stem/connection.py b/stem/connection.py
index 07dc50e..71b6e5b 100644
--- a/stem/connection.py
+++ b/stem/connection.py
@@ -25,8 +25,7 @@ authenticate_none - Authenticates to an open control socket.
authenticate_password - Authenticates to a socket supporting password auth.
authenticate_cookie - Authenticates to a socket supporting cookie auth.
-get_protocolinfo_by_port - PROTOCOLINFO query via a control port.
-get_protocolinfo_by_socket - PROTOCOLINFO query via a control socket.
+get_protocolinfo - issues a PROTOCOLINFO query
ProtocolInfoResponse - Reply from a PROTOCOLINFO query.
|- Attributes:
| |- protocol_version
@@ -292,63 +291,19 @@ def authenticate_cookie(control_socket, cookie_path, suppress_ctl_errors = True)
if not suppress_ctl_errors: raise exc
else: raise CookieAuthRejected("Socket failed (%s)" % exc)
-def get_protocolinfo_by_port(control_addr = "127.0.0.1", control_port = 9051, get_socket = False):
- """
- Issues a PROTOCOLINFO query to a control port, getting information about the
- tor process running on it.
-
- Arguments:
- control_addr (str) - ip address of the controller
- control_port (int) - port number of the controller
- get_socket (bool) - provides the socket with the response if True,
- otherwise the socket is closed when we're done
-
- Returns:
- stem.connection.ProtocolInfoResponse provided by tor, if get_socket is True
- then this provides a tuple instead with both the response and connected
- socket (stem.socket.ControlPort)
-
- Raises:
- stem.socket.ProtocolError if the PROTOCOLINFO response is malformed
- stem.socket.SocketError if problems arise in establishing or using the
- socket
- """
-
- control_socket = stem.socket.ControlPort(control_addr, control_port, False)
-
- try:
- control_socket.connect()
- control_socket.send("PROTOCOLINFO 1")
- protocolinfo_response = control_socket.recv()
- ProtocolInfoResponse.convert(protocolinfo_response)
-
- # attempt to expand relative cookie paths using our port to infer the pid
- if control_addr == "127.0.0.1":
- _expand_cookie_path(protocolinfo_response, stem.util.system.get_pid_by_port, control_port)
-
- if get_socket:
- return (protocolinfo_response, control_socket)
- else:
- control_socket.close()
- return protocolinfo_response
- except stem.socket.ControllerError, exc:
- control_socket.close()
- raise exc
-
-def get_protocolinfo_by_socket(socket_path = "/var/run/tor/control", get_socket = False):
+def get_protocolinfo(control_socket):
"""
Issues a PROTOCOLINFO query to a control socket, getting information about
the tor process running on it.
+ Tor hangs up on sockets after receiving a PROTOCOLINFO query if it isn't next
+ followed by authentication.
+
Arguments:
- socket_path (str) - path where the control socket is located
- get_socket (bool) - provides the socket with the response if True,
- otherwise the socket is closed when we're done
+ control_socket (stem.socket.ControlSocket) - connected tor control socket
Returns:
- stem.connection.ProtocolInfoResponse provided by tor, if get_socket is True
- then this provides a tuple instead with both the response and connected
- socket (stem.socket.ControlSocketFile)
+ stem.connection.ProtocolInfoResponse provided by tor
Raises:
stem.socket.ProtocolError if the PROTOCOLINFO response is malformed
@@ -356,25 +311,20 @@ def get_protocolinfo_by_socket(socket_path = "/var/run/tor/control", get_socket
socket
"""
- control_socket = stem.socket.ControlSocketFile(socket_path, False)
+ control_socket.send("PROTOCOLINFO 1")
+ protocolinfo_response = control_socket.recv()
+ ProtocolInfoResponse.convert(protocolinfo_response)
- try:
- control_socket.connect()
- control_socket.send("PROTOCOLINFO 1")
- protocolinfo_response = control_socket.recv()
- ProtocolInfoResponse.convert(protocolinfo_response)
-
- # attempt to expand relative cookie paths using our port to infer the pid
- _expand_cookie_path(protocolinfo_response, stem.util.system.get_pid_by_open_file, socket_path)
-
- if get_socket:
- return (protocolinfo_response, control_socket)
- else:
- control_socket.close()
- return protocolinfo_response
- except stem.socket.ControllerError, exc:
- control_socket.close()
- raise exc
+ # attempt ot expand relative cookie paths via the control port or socket file
+ if isinstance(control_socket, stem.socket.ControlPort):
+ if control_socket.get_address() == "127.0.0.1":
+ pid_method = stem.util.system.get_pid_by_port
+ _expand_cookie_path(protocolinfo_response, pid_method, control_socket.get_port())
+ elif isinstance(control_socket, stem.socket.ControlSocketFile):
+ pid_method = stem.util.system.get_pid_by_open_file
+ _expand_cookie_path(protocolinfo_response, pid_method, control_socket.get_socket_path())
+
+ return protocolinfo_response
def _expand_cookie_path(protocolinfo_response, pid_resolver, pid_resolution_arg):
"""
diff --git a/test/integ/connection/protocolinfo.py b/test/integ/connection/protocolinfo.py
index 02d097d..dfc1c01 100644
--- a/test/integ/connection/protocolinfo.py
+++ b/test/integ/connection/protocolinfo.py
@@ -49,7 +49,8 @@ class TestProtocolInfo(unittest.TestCase):
def test_get_protocolinfo_by_port(self):
"""
- Exercises the stem.connection.get_protocolinfo_by_port function.
+ Exercises the stem.connection.get_protocolinfo function with a control
+ port.
"""
# If we have both the 'RELATIVE' target and a cookie then test_parsing
@@ -74,15 +75,21 @@ class TestProtocolInfo(unittest.TestCase):
connection_type = test.runner.get_runner().get_connection_type()
if test.runner.OPT_PORT in test.runner.CONNECTION_OPTS[connection_type]:
- protocolinfo_response = stem.connection.get_protocolinfo_by_port(control_port = test.runner.CONTROL_PORT)
+ control_socket = stem.socket.ControlPort(control_port = test.runner.CONTROL_PORT)
+ protocolinfo_response = stem.connection.get_protocolinfo(control_socket)
self.assert_protocolinfo_attr(protocolinfo_response, connection_type)
+
+ # we should have a usable socket at this point
+ self.assertTrue(control_socket.is_alive())
+ control_socket.close()
else:
# we don't have a control port
- self.assertRaises(stem.socket.SocketError, stem.connection.get_protocolinfo_by_port, "127.0.0.1", test.runner.CONTROL_PORT)
+ self.assertRaises(stem.socket.SocketError, stem.socket.ControlPort, "127.0.0.1", test.runner.CONTROL_PORT)
def test_get_protocolinfo_by_socket(self):
"""
- Exercises the stem.connection.get_protocolinfo_by_socket function.
+ Exercises the stem.connection.get_protocolinfo function with a control
+ socket.
"""
cwd_by_socket_lookup_prefixes = (
@@ -100,16 +107,16 @@ class TestProtocolInfo(unittest.TestCase):
connection_type = test.runner.get_runner().get_connection_type()
if test.runner.OPT_SOCKET in test.runner.CONNECTION_OPTS[connection_type]:
- protocolinfo_response, control_socket = stem.connection.get_protocolinfo_by_socket(socket_path = test.runner.CONTROL_SOCKET_PATH, get_socket = True)
+ control_socket = stem.socket.ControlSocketFile(test.runner.CONTROL_SOCKET_PATH)
+ protocolinfo_response = stem.connection.get_protocolinfo(control_socket)
self.assert_protocolinfo_attr(protocolinfo_response, connection_type)
- # also exercising the get_socket argument - we should have a usable
- # socket at this point
+ # we should have a usable socket at this point
self.assertTrue(control_socket.is_alive())
control_socket.close()
else:
# we don't have a control socket
- self.assertRaises(stem.socket.SocketError, stem.connection.get_protocolinfo_by_socket, test.runner.CONTROL_SOCKET_PATH)
+ self.assertRaises(stem.socket.SocketError, stem.socket.ControlSocketFile, test.runner.CONTROL_SOCKET_PATH)
def assert_protocolinfo_attr(self, protocolinfo_response, connection_type):
"""
1
0

13 Dec '11
commit a584686dd01f12c8209ea7bc55019fec752eeaa2
Author: Damian Johnson <atagar(a)torproject.org>
Date: Mon Dec 12 18:05:23 2011 -0800
Defaulting ControlSocket constructors to connect
ControlSocket users almost always want the socket to be connected initially to
defaulting it that way.
---
stem/connection.py | 6 ++++--
stem/socket.py | 20 ++++++++++++++++++--
test/runner.py | 2 --
3 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/stem/connection.py b/stem/connection.py
index 938ab2f..07dc50e 100644
--- a/stem/connection.py
+++ b/stem/connection.py
@@ -314,8 +314,9 @@ def get_protocolinfo_by_port(control_addr = "127.0.0.1", control_port = 9051, ge
socket
"""
+ control_socket = stem.socket.ControlPort(control_addr, control_port, False)
+
try:
- control_socket = stem.socket.ControlPort(control_addr, control_port)
control_socket.connect()
control_socket.send("PROTOCOLINFO 1")
protocolinfo_response = control_socket.recv()
@@ -355,8 +356,9 @@ def get_protocolinfo_by_socket(socket_path = "/var/run/tor/control", get_socket
socket
"""
+ control_socket = stem.socket.ControlSocketFile(socket_path, False)
+
try:
- control_socket = stem.socket.ControlSocketFile(socket_path)
control_socket.connect()
control_socket.send("PROTOCOLINFO 1")
protocolinfo_response = control_socket.recv()
diff --git a/stem/socket.py b/stem/socket.py
index 1739aaa..2dcb8ac 100644
--- a/stem/socket.py
+++ b/stem/socket.py
@@ -237,18 +237,26 @@ class ControlPort(ControlSocket):
option.
"""
- def __init__(self, control_addr = "127.0.0.1", control_port = 9051):
+ def __init__(self, control_addr = "127.0.0.1", control_port = 9051, connect = True):
"""
ControlPort constructor.
Arguments:
control_addr (str) - ip address of the controller
control_port (int) - port number of the controller
+ connect (bool) - connects to the socket if True, leaves it
+ unconnected otherwise
+
+ Raises:
+ stem.socket.SocketError if connect is True and we're unable to establish
+ a connection
"""
ControlSocket.__init__(self)
self._control_addr = control_addr
self._control_port = control_port
+
+ if connect: self.connect()
def get_address(self):
"""
@@ -284,16 +292,24 @@ class ControlSocketFile(ControlSocket):
option.
"""
- def __init__(self, socket_path = "/var/run/tor/control"):
+ def __init__(self, socket_path = "/var/run/tor/control", connect = True):
"""
ControlSocketFile constructor.
Arguments:
socket_path (str) - path where the control socket is located
+ connect (bool) - connects to the socket if True, leaves it
+ unconnected otherwise
+
+ Raises:
+ stem.socket.SocketError if connect is True and we're unable to establish
+ a connection
"""
ControlSocket.__init__(self)
self._socket_path = socket_path
+
+ if connect: self.connect()
def get_socket_path(self):
"""
diff --git a/test/runner.py b/test/runner.py
index 6284464..566644b 100644
--- a/test/runner.py
+++ b/test/runner.py
@@ -345,8 +345,6 @@ class Runner:
control_socket = stem.socket.ControlSocketFile(CONTROL_SOCKET_PATH)
else: return None
- control_socket.connect()
-
# TODO: replace with higher level authentication functions when we have them
if authenticate:
if OPT_COOKIE in conn_opts:
1
0

13 Dec '11
commit 297a41b085a92eb1c5b5c92464d3bc9cd27cef94
Author: Damian Johnson <atagar(a)torproject.org>
Date: Tue Dec 13 10:06:53 2011 -0800
Reconnecting socket after auth failures
Tor disconnects the control socket after Failed AUTHENTICATE calls in an effort
to mitigate the issue discussed in...
http://archives.seul.org/or/announce/Sep-2007/msg00000.html
This is unintuitive to stem users so I'm making a best effort attempt to
reconnect the socket in those cases. This isn't guaranteed to succeed, but
checking is_alive() is far nicer for callers than a try/connect/except block.
---
stem/connection.py | 43 ++++++++++++++++++++-----------
test/integ/connection/authentication.py | 12 ++++++--
2 files changed, 37 insertions(+), 18 deletions(-)
diff --git a/stem/connection.py b/stem/connection.py
index 71b6e5b..e9bd5f7 100644
--- a/stem/connection.py
+++ b/stem/connection.py
@@ -126,8 +126,11 @@ def authenticate_none(control_socket, suppress_ctl_errors = True):
authenticate before they can be used, even if tor hasn't been configured to
use any authentication.
- For general usage use the authenticate function instead. If authentication
- fails then tor will close the control socket.
+ If authentication fails tor will disconnect and we'll make a best effort
+ attempt to re-establish the connection. This may not succeed, so check
+ is_alive() before using the socket further.
+
+ For general usage use the authenticate() function instead.
Arguments:
control_socket (stem.socket.ControlSocket) - socket to be authenticated
@@ -145,10 +148,13 @@ def authenticate_none(control_socket, suppress_ctl_errors = True):
# if we got anything but an OK response then error
if str(auth_response) != "OK":
- control_socket.close()
+ try: control_socket.connect()
+ except: pass
+
raise OpenAuthRejected(str(auth_response), auth_response)
except stem.socket.ControllerError, exc:
- control_socket.close()
+ try: control_socket.connect()
+ except: pass
if not suppress_ctl_errors: raise exc
else: raise OpenAuthRejected("Socket failed (%s)" % exc)
@@ -158,8 +164,11 @@ def authenticate_password(control_socket, password, suppress_ctl_errors = True):
Authenticates to a control socket that uses a password (via the
HashedControlPassword torrc option). Quotes in the password are escaped.
- For general usage use the authenticate function instead. If authentication
- fails then tor will close the control socket.
+ If authentication fails tor will disconnect and we'll make a best effort
+ attempt to re-establish the connection. This may not succeed, so check
+ is_alive() before using the socket further.
+
+ For general usage use the authenticate() function instead.
note: If you use this function directly, rather than authenticate(), we may
mistakenly raise a PasswordAuthRejected rather than IncorrectPassword. This
@@ -191,7 +200,8 @@ def authenticate_password(control_socket, password, suppress_ctl_errors = True):
# if we got anything but an OK response then error
if str(auth_response) != "OK":
- control_socket.close()
+ try: control_socket.connect()
+ except: pass
# all we have to go on is the error message from tor...
# Password did not match HashedControlPassword value value from configuration...
@@ -202,7 +212,8 @@ def authenticate_password(control_socket, password, suppress_ctl_errors = True):
else:
raise PasswordAuthRejected(str(auth_response), auth_response)
except stem.socket.ControllerError, exc:
- control_socket.close()
+ try: control_socket.connect()
+ except: pass
if not suppress_ctl_errors: raise exc
else: raise PasswordAuthRejected("Socket failed (%s)" % exc)
@@ -217,8 +228,11 @@ def authenticate_cookie(control_socket, cookie_path, suppress_ctl_errors = True)
The IncorrectCookieSize and UnreadableCookieFile exceptions take precidence
over the other types.
- For general usage use the authenticate function instead. If authentication
- fails then tor will close the control socket.
+ If authentication fails tor will disconnect and we'll make a best effort
+ attempt to re-establish the connection. This may not succeed, so check
+ is_alive() before using the socket further.
+
+ For general usage use the authenticate() function instead.
note: If you use this function directly, rather than authenticate(), we may
mistakenly raise a CookieAuthRejected rather than IncorrectCookieValue. This
@@ -241,7 +255,6 @@ def authenticate_cookie(control_socket, cookie_path, suppress_ctl_errors = True)
"""
if not os.path.exists(cookie_path):
- control_socket.close()
raise UnreadableCookieFile("Authentication failed: '%s' doesn't exist" % cookie_path)
# Abort if the file isn't 32 bytes long. This is to avoid exposing arbitrary
@@ -256,7 +269,6 @@ def authenticate_cookie(control_socket, cookie_path, suppress_ctl_errors = True)
auth_cookie_size = os.path.getsize(cookie_path)
if auth_cookie_size != 32:
- control_socket.close()
exc_msg = "Authentication failed: authentication cookie '%s' is the wrong size (%i bytes instead of 32)" % (cookie_path, auth_cookie_size)
raise IncorrectCookieSize(exc_msg)
@@ -265,7 +277,6 @@ def authenticate_cookie(control_socket, cookie_path, suppress_ctl_errors = True)
auth_cookie_contents = auth_cookie_file.read()
auth_cookie_file.close()
except IOError, exc:
- control_socket.close()
raise UnreadableCookieFile("Authentication failed: unable to read '%s' (%s)" % (cookie_path, exc))
try:
@@ -274,7 +285,8 @@ def authenticate_cookie(control_socket, cookie_path, suppress_ctl_errors = True)
# if we got anything but an OK response then error
if str(auth_response) != "OK":
- control_socket.close()
+ try: control_socket.connect()
+ except: pass
# all we have to go on is the error message from tor...
# ... Authentication cookie did not match expected value.
@@ -286,7 +298,8 @@ def authenticate_cookie(control_socket, cookie_path, suppress_ctl_errors = True)
else:
raise CookieAuthRejected(str(auth_response), auth_response)
except stem.socket.ControllerError, exc:
- control_socket.close()
+ try: control_socket.connect()
+ except: pass
if not suppress_ctl_errors: raise exc
else: raise CookieAuthRejected("Socket failed (%s)" % exc)
diff --git a/test/integ/connection/authentication.py b/test/integ/connection/authentication.py
index ee36946..3d7d199 100644
--- a/test/integ/connection/authentication.py
+++ b/test/integ/connection/authentication.py
@@ -246,8 +246,9 @@ class TestAuthenticate(unittest.TestCase):
control_socket.close()
self.fail()
except stem.connection.AuthenticationFailure, exc:
- self.assertFalse(control_socket.is_alive())
+ self.assertTrue(control_socket.is_alive())
self.assertEqual(failure_msg, str(exc))
+ control_socket.close()
def _check_auth(self, auth_type, *auth_args):
"""
@@ -268,8 +269,13 @@ class TestAuthenticate(unittest.TestCase):
control_socket = runner.get_tor_socket(False)
auth_function = self._get_auth_function(control_socket, auth_type, *auth_args)
- # run the authentication, letting this raise if there's a problem
- auth_function()
+ # run the authentication, re-raising if there's a problem
+ try:
+ auth_function()
+ except stem.connection.AuthenticationFailure, exc:
+ self.assertTrue(control_socket.is_alive())
+ control_socket.close()
+ raise exc
# issues a 'GETINFO config-file' query to confirm that we can use the socket
control_socket.send("GETINFO config-file")
1
0
commit 7d5d5d5857b65b8a0009ae7c5ea8fd222009d874
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Tue Dec 13 13:16:38 2011 +0100
Add a LICENSE file.
---
LICENSE | 30 ++++++++++++++++++++++++++++++
1 files changed, 30 insertions(+), 0 deletions(-)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d5b67cd
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright 2011 The Tor Project
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the names of the copyright owners nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
1
0

13 Dec '11
commit 33847557a83af4413f4be91d6c1065eecdc4a163
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Tue Dec 13 13:24:55 2011 +0100
Remove the executable flag from most files.
---
0 files changed, 0 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
old mode 100755
new mode 100644
diff --git a/README b/README
old mode 100755
new mode 100644
diff --git a/build.xml b/build.xml
old mode 100755
new mode 100644
diff --git a/src/org/torproject/doctor/Checker.java b/src/org/torproject/doctor/Checker.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/doctor/Downloader.java b/src/org/torproject/doctor/Downloader.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/doctor/Main.java b/src/org/torproject/doctor/Main.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/doctor/MetricsWebsiteReport.java b/src/org/torproject/doctor/MetricsWebsiteReport.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/doctor/StatusFileReport.java b/src/org/torproject/doctor/StatusFileReport.java
old mode 100755
new mode 100644
diff --git a/src/org/torproject/doctor/Warning.java b/src/org/torproject/doctor/Warning.java
old mode 100755
new mode 100644
1
0

[doctor/master] Clean up a comments and use saner output filenames.
by karsten@torproject.org 13 Dec '11
by karsten@torproject.org 13 Dec '11
13 Dec '11
commit bbdfc6f942e58aa9191acc5609f73660f608051a
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Tue Dec 13 14:22:22 2011 +0100
Clean up a comments and use saner output filenames.
---
.gitignore | 1 +
README | 36 +++++++++++++
src/org/torproject/doctor/Checker.java | 15 +++---
src/org/torproject/doctor/DownloadStatistics.java | 16 ++++++-
src/org/torproject/doctor/Downloader.java | 24 ++++++---
src/org/torproject/doctor/Main.java | 11 ++--
.../torproject/doctor/MetricsWebsiteReport.java | 8 +--
src/org/torproject/doctor/StatusFileReport.java | 54 +++++++++++--------
src/org/torproject/doctor/Warning.java | 2 +-
9 files changed, 114 insertions(+), 53 deletions(-)
diff --git a/.gitignore b/.gitignore
index 64253cb..14a8cb2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
classes/
lib/
+out/
diff --git a/README b/README
index 0a9a9b4..1b900d2 100644
--- a/README
+++ b/README
@@ -8,3 +8,39 @@ from the Tor directory authorities and checks them for consensus problems.
DocTor writes its findings to local files which can then be sent to a
mailing list or IRC bot, or which can be served by an HTTP server.
+
+Howto
+-----
+
+Create a lib/ directory.
+
+Download Apache Commons Codec 1.4 or higher and put it in the lib/
+directory. If the filename is not commons-codec-1.4.jar, update the
+build.xml file.
+
+Clone metrics-lib, create a .jar file using `ant jar`, and put it in the
+lib/ directory, too.
+
+Compile the Java classes using `ant compile`.
+
+Run the application using `ant run`.
+
+Output files are:
+
+ - out/status/new-warnings: Consensus warnings that have been found in
+ this execution or that were found long enough before to not be
+ rate-limited anymore.
+
+ - out/status/all-warnings: All warnings found in this execution, but only
+ if at least one of them is in new-warnings, too.
+
+ - out/website/consensus-health.html: HTML file containing a full
+ comparison of consensuses to its votes, marking problems in red.
+
+Generated temp files (read: don't mess with them) are:
+
+ - out/stats/download-stats.csv: Raw consensus download times.
+
+ - out/stats/last-warned: Warning messages and when they were last
+ contained in new-warnings or all-warnings.
+
diff --git a/src/org/torproject/doctor/Checker.java b/src/org/torproject/doctor/Checker.java
index ee4e29e..c78ebf6 100644
--- a/src/org/torproject/doctor/Checker.java
+++ b/src/org/torproject/doctor/Checker.java
@@ -14,7 +14,6 @@ public class Checker {
/* Warning messages consisting of type and details. */
private SortedMap<Warning, String> warnings =
new TreeMap<Warning, String>();
-
public SortedMap<Warning, String> getWarnings() {
return this.warnings;
}
@@ -26,13 +25,7 @@ public class Checker {
dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
}
- /* Downloaded consensus and corresponding votes for processing. */
- private SortedMap<String, RelayNetworkStatusConsensus>
- downloadedConsensuses = new TreeMap<String,
- RelayNetworkStatusConsensus>();
- private RelayNetworkStatusConsensus downloadedConsensus;
- private List<RelayNetworkStatusVote> downloadedVotes =
- new ArrayList<RelayNetworkStatusVote>();
+ /* Check consensuses and votes. */
public void processDownloadedConsensuses(
List<DescriptorRequest> downloads) {
this.storeDownloads(downloads);
@@ -57,6 +50,12 @@ public class Checker {
/* Store consensuses and votes in a way that we can process them more
* easily. */
+ private SortedMap<String, RelayNetworkStatusConsensus>
+ downloadedConsensuses = new TreeMap<String,
+ RelayNetworkStatusConsensus>();
+ private RelayNetworkStatusConsensus downloadedConsensus;
+ private List<RelayNetworkStatusVote> downloadedVotes =
+ new ArrayList<RelayNetworkStatusVote>();
private void storeDownloads(List<DescriptorRequest> downloads) {
for (DescriptorRequest request : downloads) {
for (Descriptor descriptor : request.getDescriptors()) {
diff --git a/src/org/torproject/doctor/DownloadStatistics.java b/src/org/torproject/doctor/DownloadStatistics.java
index 9df0333..e30aed8 100644
--- a/src/org/torproject/doctor/DownloadStatistics.java
+++ b/src/org/torproject/doctor/DownloadStatistics.java
@@ -6,9 +6,15 @@ import java.io.*;
import java.util.*;
import org.torproject.descriptor.*;
+/* Provide simple statistics about consensus download times. */
public class DownloadStatistics {
+
+ /* Add a new set of download times by append them to the history
+ * file. */
+ private File statisticsFile = new File("out/state/download-stats.csv");
public void memorizeFetchTimes(List<DescriptorRequest> downloads) {
try {
+ this.statisticsFile.getParentFile().mkdirs();
BufferedWriter bw = new BufferedWriter(new FileWriter(
this.statisticsFile, true));
for (DescriptorRequest request : downloads) {
@@ -31,10 +37,12 @@ public class DownloadStatistics {
+ this.statisticsFile.getAbsolutePath() + ". Ignoring.");
}
}
+
+ /* Prepare statistics by reading the download history and sorting to
+ * calculate percentiles more easily. */
private SortedMap<String, List<Long>> downloadData =
new TreeMap<String, List<Long>>();
private int maxDownloadsPerAuthority = 0;
- private File statisticsFile = new File("download-stats.csv");
public void prepareStatistics() {
if (this.statisticsFile.exists()) {
long cutOffMillis = System.currentTimeMillis()
@@ -71,9 +79,13 @@ public class DownloadStatistics {
}
}
}
+
+ /* Return the list of authorities that we have statistics for. */
public SortedSet<String> getKnownAuthorities() {
return new TreeSet<String>(this.downloadData.keySet());
}
+
+ /* Return the download time percentile for a directory authority. */
public String getPercentile(String authority, int percentile) {
if (percentile < 0 || percentile > 100 ||
!this.downloadData.containsKey(authority)) {
@@ -84,6 +96,8 @@ public class DownloadStatistics {
return String.valueOf(fetchTimes.get(index));
}
}
+
+ /* Return the number of NAs (timeouts) for a directory authority. */
public String getNAs(String authority) {
if (!this.downloadData.containsKey(authority)) {
return "NA";
diff --git a/src/org/torproject/doctor/Downloader.java b/src/org/torproject/doctor/Downloader.java
index 317b3b6..f20885f 100644
--- a/src/org/torproject/doctor/Downloader.java
+++ b/src/org/torproject/doctor/Downloader.java
@@ -2,23 +2,22 @@
* See LICENSE for licensing information */
package org.torproject.doctor;
-import java.io.*;
-import java.net.*;
-import java.text.*;
import java.util.*;
-import java.util.zip.*;
import org.torproject.descriptor.*;
/* Download the latest network status consensus and corresponding
- * votes. */
+ * votes using metrics-lib. */
public class Downloader {
/* Download the current consensus and corresponding votes. */
public List<DescriptorRequest> downloadFromAuthorities() {
+ /* Create a descriptor downloader instance that will do all the hard
+ * download work for us. */
RelayDescriptorDownloader downloader =
DescriptorSourceFactory.createRelayDescriptorDownloader();
+ /* Configure the currently known directory authorities. */
downloader.addDirectoryAuthority("gabelmoo", "212.112.245.170", 80);
downloader.addDirectoryAuthority("tor26", "86.59.21.38", 80);
downloader.addDirectoryAuthority("ides", "216.224.124.114", 9030);
@@ -28,20 +27,28 @@ public class Downloader {
downloader.addDirectoryAuthority("moria1", "128.31.0.34", 9131);
downloader.addDirectoryAuthority("dizum", "194.109.206.212", 80);
+ /* Instruct the downloader to include the current consensus and all
+ * referenced votes in the downloads. The consensus shall be
+ * downloaded from all directory authorities, not just from one. */
downloader.setIncludeCurrentConsensusFromAllDirectoryAuthorities();
downloader.setIncludeCurrentReferencedVotes();
+ /* Set a per-request timeout of 60 seconds. */
downloader.setRequestTimeout(60L * 1000L);
- List<DescriptorRequest> allRequests =
- new ArrayList<DescriptorRequest>();
+ /* Iterate over the finished (or aborted) requests and memorize the
+ * included consensuses or votes. The processing will take place
+ * later. */
Iterator<DescriptorRequest> descriptorRequests =
downloader.downloadDescriptors();
+ List<DescriptorRequest> allRequests =
+ new ArrayList<DescriptorRequest>();
while (descriptorRequests.hasNext()) {
try {
allRequests.add(descriptorRequests.next());
} catch (NoSuchElementException e) {
- /* TODO In theory, this exception shouldn't be thrown. */
+ /* TODO In theory, this exception shouldn't be thrown. This is a
+ * bug in metrics-lib. */
System.err.println("Internal error: next() doesn't provide an "
+ "element even though hasNext() returned true. Got "
+ allRequests.size() + " elements so far. Stopping to "
@@ -50,6 +57,7 @@ public class Downloader {
}
}
+ /* We downloaded everything we wanted. */
return allRequests;
}
}
diff --git a/src/org/torproject/doctor/Main.java b/src/org/torproject/doctor/Main.java
index 40973b4..f723e0b 100644
--- a/src/org/torproject/doctor/Main.java
+++ b/src/org/torproject/doctor/Main.java
@@ -5,13 +5,13 @@ package org.torproject.doctor;
import java.util.*;
import org.torproject.descriptor.*;
-/* Coordinate the process of downloading consensus and votes to check
- * Tor's consensus health. */
+/* Coordinate the process of downloading the current consensus and votes
+ * to check Tor's consensus health. */
public class Main {
public static void main(String[] args) {
- /* Download consensus and corresponding votes from the directory
- * authorities. */
+ /* Download the current consensus from all directory authorities and
+ * all referenced votes from any directory authority. */
Downloader downloader = new Downloader();
List<DescriptorRequest> downloads =
downloader.downloadFromAuthorities();
@@ -26,8 +26,7 @@ public class Main {
statusFile.writeReport();
/* Write a complete consensus-health report to an HTML file. */
- MetricsWebsiteReport website =
- new MetricsWebsiteReport("website/consensus-health.html");
+ MetricsWebsiteReport website = new MetricsWebsiteReport();
website.processDownloadedConsensuses(downloads);
DownloadStatistics fetchStatistics = new DownloadStatistics();
fetchStatistics.memorizeFetchTimes(downloads);
diff --git a/src/org/torproject/doctor/MetricsWebsiteReport.java b/src/org/torproject/doctor/MetricsWebsiteReport.java
index 8d0bb0b..ac60ae7 100644
--- a/src/org/torproject/doctor/MetricsWebsiteReport.java
+++ b/src/org/torproject/doctor/MetricsWebsiteReport.java
@@ -19,12 +19,8 @@ public class MetricsWebsiteReport {
}
/* Output file to write report to. */
- private File htmlOutputFile;
-
- /* Initialize this report. */
- public MetricsWebsiteReport(String htmlOutputFilename) {
- this.htmlOutputFile = new File(htmlOutputFilename);
- }
+ private File htmlOutputFile =
+ new File("out/website/consensus-health.html");
/* Store the downloaded consensus and corresponding votes for later
* processing. */
diff --git a/src/org/torproject/doctor/StatusFileReport.java b/src/org/torproject/doctor/StatusFileReport.java
index 7890005..a8838b6 100644
--- a/src/org/torproject/doctor/StatusFileReport.java
+++ b/src/org/torproject/doctor/StatusFileReport.java
@@ -7,7 +7,9 @@ import java.text.*;
import java.util.*;
/* Check a given consensus and votes for irregularities and write results
- * to stdout while rate-limiting warnings based on severity. */
+ * to status files while rate-limiting warnings based on severity. There
+ * will be a 'all-warnings' file with all warnings and a 'new-warnings'
+ * file with only the warnings that haven't been emitted recently. */
public class StatusFileReport {
/* Date-time format to format timestamps. */
@@ -23,32 +25,32 @@ public class StatusFileReport {
this.warnings = warnings;
}
- /* Check consensuses and votes for irregularities and write output to
- * stdout. */
+ /* Write warnings to the status files. */
public void writeReport() {
this.readLastWarned();
- this.prepareReports();
+ this.prepareStatusFiles();
this.writeStatusFiles();
this.writeLastWarned();
}
- /* Warning messages of the last 24 hours that is used to implement
- * rate limiting. */
+ /* Map of warning message strings of the last 24 hours and when they
+ * were last included in the 'new-warnings' file. This map is used to
+ * implement rate limiting. */
private Map<String, Long> lastWarned = new HashMap<String, Long>();
/* Read when we last emitted a warning to rate-limit some of them. */
+ private File lastWarnedFile = new File("out/state/last-warned");
private void readLastWarned() {
long now = System.currentTimeMillis();
- File lastWarnedFile = new File("stats/chc-last-warned");
try {
- if (lastWarnedFile.exists()) {
+ if (this.lastWarnedFile.exists()) {
BufferedReader br = new BufferedReader(new FileReader(
- lastWarnedFile));
+ this.lastWarnedFile));
String line;
while ((line = br.readLine()) != null) {
if (!line.contains(": ")) {
- System.err.println("Bad line in stats/chc-last-warned: '" + line
- + "'. Ignoring this line.");
+ System.err.println("Bad line in stats/chc-last-warned: '"
+ + line + "'. Ignoring this line.");
continue;
}
long warnedMillis = Long.parseLong(line.substring(0,
@@ -63,20 +65,21 @@ public class StatusFileReport {
}
} catch (IOException e) {
System.err.println("Could not read file '"
- + lastWarnedFile.getAbsolutePath() + "' to learn which "
+ + this.lastWarnedFile.getAbsolutePath() + "' to learn which "
+ "warnings have been sent out before. Ignoring.");
}
}
- /* Prepare a report to be written to stdout. */
+ /* Prepare status files to be written. */
private String allWarnings = null, newWarnings = null;
- private void prepareReports() {
+ private void prepareStatusFiles() {
SortedMap<String, Long> warningStrings = new TreeMap<String, Long>();
for (Map.Entry<Warning, String> e : this.warnings.entrySet()) {
Warning type = e.getKey();
String details = e.getValue();
switch (type) {
case NoConsensusKnown:
+ warningStrings.put("No consensus known.", 0L);
break;
case ConsensusDownloadTimeout:
warningStrings.put("The following directory authorities did "
@@ -158,12 +161,17 @@ public class StatusFileReport {
}
}
- /* Write report to stdout. */
+ /* Write status files to disk. */
+ private File allWarningsFile = new File("out/status/all-warnings");
+ private File newWarningsFile = new File("out/status/new-warnings");
private void writeStatusFiles() {
try {
+ this.allWarningsFile.getParentFile().mkdirs();
+ this.newWarningsFile.getParentFile().mkdirs();
BufferedWriter allBw = new BufferedWriter(new FileWriter(
- "all-warnings")), newBw = new BufferedWriter(new FileWriter(
- "new-warnings"));
+ this.allWarningsFile));
+ BufferedWriter newBw = new BufferedWriter(new FileWriter(
+ this.newWarningsFile));
if (this.allWarnings != null) {
allBw.write(this.allWarnings);
}
@@ -173,25 +181,25 @@ public class StatusFileReport {
allBw.close();
newBw.close();
} catch (IOException e) {
- System.err.println("Could not write status files 'all-warnings' "
- + "and/or 'new-warnings'. Ignoring.");
+ System.err.println("Could not write status files '"
+ + this.allWarningsFile.getAbsolutePath() + "' and/or '"
+ + this.newWarningsFile.getAbsolutePath() + "'. Ignoring.");
}
}
/* Write timestamps when warnings were last sent to disk. */
private void writeLastWarned() {
- File lastWarnedFile = new File("stats/chc-last-warned");
try {
- lastWarnedFile.getParentFile().mkdirs();
+ this.lastWarnedFile.getParentFile().mkdirs();
BufferedWriter bw = new BufferedWriter(new FileWriter(
- lastWarnedFile));
+ this.lastWarnedFile));
for (Map.Entry<String, Long> e : lastWarned.entrySet()) {
bw.write(String.valueOf(e.getValue()) + ": " + e.getKey() + "\n");
}
bw.close();
} catch (IOException e) {
System.err.println("Could not write file '"
- + lastWarnedFile.getAbsolutePath() + "' to remember which "
+ + this.lastWarnedFile.getAbsolutePath() + "' to remember which "
+ "warnings have been sent out before. Ignoring.");
}
}
diff --git a/src/org/torproject/doctor/Warning.java b/src/org/torproject/doctor/Warning.java
index 0cb8cd8..1684f89 100644
--- a/src/org/torproject/doctor/Warning.java
+++ b/src/org/torproject/doctor/Warning.java
@@ -49,7 +49,7 @@ public enum Warning {
ConsensusMissingVotes,
/* The consensuses downloaded from one or more authorities are missing
- * signatures from other, previously voting authorities. */
+ * signatures from previously voting authorities. */
ConsensusMissingSignatures
}
1
0