Initial project commit
This commit is contained in:
52
CircuitLoadTest/CircuitLoadTest.csproj
Normal file
52
CircuitLoadTest/CircuitLoadTest.csproj
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||||
|
<ProductVersion>8.0.30703</ProductVersion>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>{124BEFA2-D0CB-4D6D-AD53-166DE405CC60}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>CircuitLoadTest</RootNamespace>
|
||||||
|
<AssemblyName>CircuitLoadTest</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
||||||
43
CircuitLoadTest/Program.cs
Normal file
43
CircuitLoadTest/Program.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Data.SqlClient;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
|
||||||
|
namespace CircuitLoadTest
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
String file = System.IO.File.ReadAllText("C:\\Projects\\Fun\\Tor\\Hermes\\bin\\Debug\\circ.debug.csv");
|
||||||
|
StringReader reader = new StringReader(file);
|
||||||
|
using (SqlConnection conn = new SqlConnection("Data Source=MAIN;Initial Catalog=Test;User Id=sa;Password=Sm0kers@Gy0;"))
|
||||||
|
{
|
||||||
|
conn.Open();
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
String line = reader.ReadLine();
|
||||||
|
if (String.IsNullOrEmpty(line))
|
||||||
|
break;
|
||||||
|
String[] parts = line.Split(',');
|
||||||
|
String sqlRequest = String.Format(@"MERGE dbo.TorTest AS target
|
||||||
|
USING (SELECT {0}, '{1}') AS source (CircuitID, [Status])
|
||||||
|
ON (target.CircuitID = source.CircuitID)
|
||||||
|
WHEN MATCHED AND ([Status] = 'CLOSED' OR [Status] = 'FAILED') THEN
|
||||||
|
UPDATE SET Closed = 1
|
||||||
|
WHEN NOT MATCHED AND ([Status] = 'BUILT') THEN
|
||||||
|
INSERT (CircuitID, Closed)
|
||||||
|
VALUES (source.CircuitID, 0);", parts[0], parts[1]);
|
||||||
|
new SqlCommand(sqlRequest, conn).ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
//Socket s = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
|
||||||
|
//s.Bind(new System.Net.IPEndPoint(System.Net.IPAddress.IPv6Any, 1234));
|
||||||
|
////s.Listen(10);
|
||||||
|
//Console.ReadLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
36
CircuitLoadTest/Properties/AssemblyInfo.cs
Normal file
36
CircuitLoadTest/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("CircuitLoadTest")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("CircuitLoadTest")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2012")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("ff92e3e4-01be-4da8-8b2c-3e14600692b0")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
53
Hermes/App.config
Normal file
53
Hermes/App.config
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<!--<system.diagnostics>
|
||||||
|
<trace autoflush="true" />
|
||||||
|
<sources>
|
||||||
|
<source name="System.Net">
|
||||||
|
<listeners>
|
||||||
|
<add name="System.Net"/>
|
||||||
|
</listeners>
|
||||||
|
</source>
|
||||||
|
<source name="System.Net.HttpListener">
|
||||||
|
<listeners>
|
||||||
|
<add name="System.Net"/>
|
||||||
|
</listeners>
|
||||||
|
</source>
|
||||||
|
<source name="System.Net.Sockets">
|
||||||
|
<listeners>
|
||||||
|
<add name="System.Net"/>
|
||||||
|
</listeners>
|
||||||
|
</source>
|
||||||
|
<source name="System.Net.Cache">
|
||||||
|
<listeners>
|
||||||
|
<add name="System.Net"/>
|
||||||
|
</listeners>
|
||||||
|
</source>
|
||||||
|
</sources>
|
||||||
|
<sharedListeners>
|
||||||
|
<add
|
||||||
|
name="System.Net"
|
||||||
|
type="System.Diagnostics.TextWriterTraceListener"
|
||||||
|
initializeData="C:\\TorTrace.log" traceOutputOptions = "DateTime" />
|
||||||
|
</sharedListeners>
|
||||||
|
<switches>
|
||||||
|
<add name="System.Net" value="Verbose" />
|
||||||
|
<add name="System.Net.Sockets" value="Verbose" />
|
||||||
|
<add name="System.Net.Cache" value="Verbose" />
|
||||||
|
<add name="System.Net.HttpListener" value="Verbose" />
|
||||||
|
</switches>
|
||||||
|
</system.diagnostics>-->
|
||||||
|
<appSettings>
|
||||||
|
<add key="Circuits" value="20"/>
|
||||||
|
<add key="Filters" value="FlagFilter,ExitPolicyFilter,CountryFilter,BandwidthObservedFilter"/>
|
||||||
|
<add key="CountryCode" value="US"/>
|
||||||
|
<add key="Flags" value="Fast,Stable"/>
|
||||||
|
<add key="AntiFlags" value=""/>
|
||||||
|
<add key="ExitEndPoint" value="18.0.0.1:80"/>
|
||||||
|
<add key="Proximity" value="1900"/>
|
||||||
|
<add key="SourceAddress" value="71.203.135.226"/>
|
||||||
|
<add key="MinimumObservableSpeed" value="1048576"/>
|
||||||
|
<add key ="CircuitManager" value="HostSectionedCircuitManager"/>
|
||||||
|
<add key="RouteSelector" value="UniqueHighestSpeedTwoNodeSelector"/>
|
||||||
|
</appSettings>
|
||||||
|
</configuration>
|
||||||
119
Hermes/CircuitManagers/CircuitManagerBase.cs
Normal file
119
Hermes/CircuitManagers/CircuitManagerBase.cs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Hermes.CircuitManagers
|
||||||
|
{
|
||||||
|
public abstract class CircuitManagerBase
|
||||||
|
{
|
||||||
|
#region Circuits
|
||||||
|
public virtual void AddCircuit(Circuit circuit)
|
||||||
|
{
|
||||||
|
_ciruitLock.AcquireWriterLock(_lockTimeout);
|
||||||
|
_circuits.Add(circuit);
|
||||||
|
_ciruitLock.ReleaseWriterLock();
|
||||||
|
}
|
||||||
|
public virtual void RemoveCircuit(Circuit circuit)
|
||||||
|
{
|
||||||
|
_ciruitLock.AcquireWriterLock(_lockTimeout);
|
||||||
|
if (circuit != null && circuit.AttachedStreams.Count > 0)
|
||||||
|
{
|
||||||
|
circuit.AttachedStreams.ForEach(p => p.Attached = false);
|
||||||
|
circuit.AttachedStreams.Clear();
|
||||||
|
}
|
||||||
|
_circuits.Remove(circuit);
|
||||||
|
_ciruitLock.ReleaseWriterLock();
|
||||||
|
}
|
||||||
|
public virtual Circuit GetCircuit(Int32 circuitID)
|
||||||
|
{
|
||||||
|
_ciruitLock.AcquireReaderLock(_lockTimeout);
|
||||||
|
Circuit circ = _circuits.FirstOrDefault(p => p.CircuitID.Equals(circuitID));
|
||||||
|
_ciruitLock.ReleaseReaderLock();
|
||||||
|
return circ;
|
||||||
|
}
|
||||||
|
public IEnumerable<Circuit> Circuits
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_ciruitLock.AcquireReaderLock(_lockTimeout);
|
||||||
|
IEnumerable<Circuit> array = _circuits.ToArray();
|
||||||
|
_ciruitLock.ReleaseReaderLock();
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region Streams
|
||||||
|
public virtual void RemoveStream(Int32 circuitID, Int32 streamID)
|
||||||
|
{
|
||||||
|
_streamLock.AcquireReaderLock(_lockTimeout);
|
||||||
|
Stream stream = _streams.FirstOrDefault(p => p.StreamID.Equals(streamID));
|
||||||
|
_streamLock.ReleaseReaderLock();
|
||||||
|
if (stream != null)
|
||||||
|
RemoveStream(circuitID, stream);
|
||||||
|
}
|
||||||
|
public virtual void RemoveStream(Int32 circuitID, Stream stream)
|
||||||
|
{
|
||||||
|
_streamLock.AcquireWriterLock(_lockTimeout);
|
||||||
|
_streams.Remove(stream);
|
||||||
|
_streamLock.ReleaseWriterLock();
|
||||||
|
_ciruitLock.AcquireReaderLock(_lockTimeout);
|
||||||
|
Circuit circ = _circuits.FirstOrDefault(p => p.CircuitID.Equals(circuitID));
|
||||||
|
if (circ != null)
|
||||||
|
{
|
||||||
|
circ.AttachedStreams.Remove(stream);
|
||||||
|
stream.Attached = false;
|
||||||
|
}
|
||||||
|
_ciruitLock.ReleaseReaderLock();
|
||||||
|
}
|
||||||
|
public virtual void RemoveStream(Stream stream)
|
||||||
|
{
|
||||||
|
RemoveStream(stream.CircuitID, stream);
|
||||||
|
}
|
||||||
|
public virtual Stream GetStream(Int32 streamID)
|
||||||
|
{
|
||||||
|
_streamLock.AcquireReaderLock(_lockTimeout);
|
||||||
|
Stream stream = _streams.FirstOrDefault(p => p.StreamID.Equals(streamID));
|
||||||
|
_streamLock.ReleaseReaderLock();
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
public IEnumerable<Stream> Streams
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_streamLock.AcquireReaderLock(_lockTimeout);
|
||||||
|
IEnumerable<Stream> array = _streams.ToArray();
|
||||||
|
_streamLock.ReleaseReaderLock();
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public virtual void AssignStreamToCircuit(Stream stream, Circuit circuit)
|
||||||
|
{
|
||||||
|
_ciruitLock.AcquireWriterLock(_lockTimeout);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
circuit.AttachedStreams.Add(stream);
|
||||||
|
stream.Circuit = circuit;
|
||||||
|
stream.Attached = true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{ throw e; }
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_ciruitLock.ReleaseWriterLock();
|
||||||
|
}
|
||||||
|
_streamLock.AcquireWriterLock(_lockTimeout);
|
||||||
|
_streams.Add(stream);
|
||||||
|
_streamLock.ReleaseWriterLock();
|
||||||
|
}
|
||||||
|
protected ReaderWriterLock _ciruitLock = new ReaderWriterLock();
|
||||||
|
protected ReaderWriterLock _streamLock = new ReaderWriterLock();
|
||||||
|
protected List<Circuit> _circuits = new List<Circuit>();
|
||||||
|
protected List<Stream> _streams = new List<Stream>();
|
||||||
|
protected Int32 _lockTimeout = 5000;
|
||||||
|
}
|
||||||
|
}
|
||||||
198
Hermes/CircuitManagers/EventBasedCircuitManager.cs
Normal file
198
Hermes/CircuitManagers/EventBasedCircuitManager.cs
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using TorControlLibrary;
|
||||||
|
using TorControlLibrary.Responses;
|
||||||
|
using Hermes.Objects;
|
||||||
|
using Hermes.Selectors;
|
||||||
|
using TorControlLibrary.Exceptions;
|
||||||
|
|
||||||
|
namespace Hermes.CircuitManagers
|
||||||
|
{
|
||||||
|
public abstract class EventBasedCircuitManager : CircuitManagerBase
|
||||||
|
{
|
||||||
|
public IRouteSelector RouteSelector { get; set; }
|
||||||
|
protected ControlConnection _controlConnection;
|
||||||
|
public Int32 ExpectedCircuits { get; set; }
|
||||||
|
public Int32 CircuitCount { get { return _circuits.Count(); } }
|
||||||
|
public void Initialize(ControlConnection controlConnection,IRouteSelector RouteSelector, Dictionary<String, String> parameters)
|
||||||
|
{
|
||||||
|
PrepareControlConnection(controlConnection, RouteSelector);
|
||||||
|
if(parameters.ContainsKey("ExpectedCircuits"))
|
||||||
|
ExpectedCircuits = Int32.Parse(parameters["ExpectedCircuits"]);
|
||||||
|
}
|
||||||
|
public void Initialize(ControlConnection controlConnection, IRouteSelector RouteSelector)
|
||||||
|
{
|
||||||
|
PrepareControlConnection(controlConnection, RouteSelector);
|
||||||
|
}
|
||||||
|
protected virtual void PrepareControlConnection(ControlConnection connection, IRouteSelector RouteSelector)
|
||||||
|
{
|
||||||
|
_controlConnection = connection;
|
||||||
|
this.RouteSelector = RouteSelector;
|
||||||
|
_controlConnection.ServerEvent += new Action<TorControlLibrary.Responses.EventResponse>(connection_ServerEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void connection_ServerEvent(EventResponse obj)
|
||||||
|
{
|
||||||
|
switch (obj.EventType)
|
||||||
|
{
|
||||||
|
case "CIRC":
|
||||||
|
switch (obj.Action)
|
||||||
|
{
|
||||||
|
case "LAUNCHED":
|
||||||
|
OnCircuitLaunched(obj);
|
||||||
|
break;
|
||||||
|
case "EXTENDED":
|
||||||
|
OnCircuitExtended(obj);
|
||||||
|
break;
|
||||||
|
case "BUILT":
|
||||||
|
OnCircuitBuilt(obj);
|
||||||
|
break;
|
||||||
|
case "CLOSED":
|
||||||
|
OnCircuitClosed(obj);
|
||||||
|
break;
|
||||||
|
case "FAILED":
|
||||||
|
OnCircuitFailed(obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "STREAM":
|
||||||
|
switch (obj.Action)
|
||||||
|
{
|
||||||
|
case "NEW":
|
||||||
|
OnStreamNew(obj);
|
||||||
|
break;
|
||||||
|
case "NEWRESOLVE":
|
||||||
|
case "NEWRESOLVED":
|
||||||
|
OnStreamNewResolved(obj);
|
||||||
|
break;
|
||||||
|
case "SENTCONNECT":
|
||||||
|
OnStreamSentConnect(obj);
|
||||||
|
break;
|
||||||
|
case "SENTRESOLVE":
|
||||||
|
OnStreamSentResolve(obj);
|
||||||
|
break;
|
||||||
|
case "SUCCEEDED":
|
||||||
|
OnStreamSucceeded(obj);
|
||||||
|
break;
|
||||||
|
case "DETACHED":
|
||||||
|
OnStreamDetached(obj);
|
||||||
|
break;
|
||||||
|
case "CLOSED":
|
||||||
|
OnStreamClosed(obj);
|
||||||
|
break;
|
||||||
|
case "FAILED":
|
||||||
|
OnStreamFailed(obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#region Internal Events
|
||||||
|
/// <summary>
|
||||||
|
/// the circuit has just been started; no work has been done yet to build it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response"></param>
|
||||||
|
protected virtual void OnCircuitLaunched(EventResponse response) { }
|
||||||
|
/// <summary>
|
||||||
|
/// the circuit has just been extended a single step.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response"></param>
|
||||||
|
protected virtual void OnCircuitExtended(EventResponse response) { }
|
||||||
|
/// <summary>
|
||||||
|
/// the circuit is finished.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response"></param>
|
||||||
|
protected virtual void OnCircuitBuilt(EventResponse response) { }
|
||||||
|
/// <summary>
|
||||||
|
/// the circuit could not be built, and has been abandoned.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response"></param>
|
||||||
|
protected virtual void OnCircuitFailed(EventResponse response) { }
|
||||||
|
/// <summary>
|
||||||
|
/// a successfully built circuit is now closed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response"></param>
|
||||||
|
protected virtual void OnCircuitClosed(EventResponse response) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// an application has asked for an anonymous connection
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response"></param>
|
||||||
|
protected virtual void OnStreamNew(EventResponse response) { }
|
||||||
|
/// <summary>
|
||||||
|
/// an application has asked for an anonymous hostname lookup
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response"></param>
|
||||||
|
protected virtual void OnStreamNewResolved(EventResponse response) { }
|
||||||
|
/// <summary>
|
||||||
|
/// the stream has been attached to a circuit, and we have sent a connection request down the circuit
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response"></param>
|
||||||
|
protected virtual void OnStreamSentConnect(EventResponse response) { }
|
||||||
|
/// <summary>
|
||||||
|
/// the stream has been attached to a circuit, and we have sent a lookup request down the circuit
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response"></param>
|
||||||
|
protected virtual void OnStreamSentResolve(EventResponse response) { }
|
||||||
|
/// <summary>
|
||||||
|
/// the stream has been connected, or the lookup request has been answered
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response"></param>
|
||||||
|
protected virtual void OnStreamSucceeded(EventResponse response) { }
|
||||||
|
/// <summary>
|
||||||
|
/// the stream was detached from its circuit, but could be reattached to another.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response"></param>
|
||||||
|
protected virtual void OnStreamDetached(EventResponse response) { }
|
||||||
|
/// <summary>
|
||||||
|
/// the stream closed normally
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response"></param>
|
||||||
|
protected virtual void OnStreamClosed(EventResponse response) { }
|
||||||
|
/// <summary>
|
||||||
|
/// the stream failed and cannot be retried
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response"></param>
|
||||||
|
protected virtual void OnStreamFailed(EventResponse response) { }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
#region EventResponse Parsing and Router processing
|
||||||
|
protected Circuit ParseCircuitResponse(EventResponse resp)
|
||||||
|
{
|
||||||
|
String[] parts = resp.EventInformation.Split(' ');
|
||||||
|
String[] routers = parts[2].Split(',');
|
||||||
|
Circuit circ = new Circuit();
|
||||||
|
foreach (String router in routers)
|
||||||
|
circ.AddNextRouter(RouteSelector.FindRouter(router));
|
||||||
|
|
||||||
|
circ.CircuitID = resp.ID;
|
||||||
|
if (resp.EventInformation.Contains("PURPOSE="))
|
||||||
|
circ.Purpose = resp.EventInformation.Substring(resp.EventInformation.IndexOf("PURPOSE=") + 8);
|
||||||
|
|
||||||
|
return circ;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
public void RequestNewCircuit()
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_controlConnection.CreateCircuit(
|
||||||
|
RouteSelector.CreateNewCircuit().ToString()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (TorException e)
|
||||||
|
{
|
||||||
|
//Remove and retry
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RequestNewCircuit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
72
Hermes/CircuitManagers/HostSectionedCircuitManager.cs
Normal file
72
Hermes/CircuitManagers/HostSectionedCircuitManager.cs
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
|
||||||
|
namespace Hermes.CircuitManagers
|
||||||
|
{
|
||||||
|
public class HostSectionedCircuitManager : OneShotRoundRobinCircuitManager
|
||||||
|
{
|
||||||
|
public Dictionary<String, Objects.Circuit> DestinationDictionary { get; set; }
|
||||||
|
|
||||||
|
public HostSectionedCircuitManager()
|
||||||
|
{
|
||||||
|
DestinationDictionary = new Dictionary<string, Circuit>();
|
||||||
|
}
|
||||||
|
protected override void AssignStream(Objects.Stream stream)
|
||||||
|
{
|
||||||
|
Circuit circ = null;
|
||||||
|
lock (DestinationDictionary)
|
||||||
|
{
|
||||||
|
if (DestinationDictionary.ContainsKey(stream.DestinationHost))
|
||||||
|
circ = DestinationDictionary[stream.DestinationHost];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
circ = GetCircuitForStream(stream);
|
||||||
|
while (circ == null)
|
||||||
|
{ //There is not yet a circuit
|
||||||
|
//Wait for more circuits to build
|
||||||
|
System.Threading.Thread.Sleep(5000);
|
||||||
|
circ = GetCircuitForStream(stream);
|
||||||
|
}
|
||||||
|
DestinationDictionary.Add(stream.DestinationHost, circ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AssignStreamToCircuit(stream, circ);
|
||||||
|
}
|
||||||
|
catch (TorControlLibrary.Exceptions.TorUnknownCircuitException e)
|
||||||
|
{ //The circuit has become invalidated, most likely due to it closing.
|
||||||
|
//cleanup
|
||||||
|
RemoveCircuit(circ);
|
||||||
|
//try
|
||||||
|
//{
|
||||||
|
// _controlConnection.CloseCircuit(circ.CircuitID);
|
||||||
|
//}
|
||||||
|
//catch (Exception) { }
|
||||||
|
//Call this function again, with hopefully better results next time
|
||||||
|
AssignStream(stream);
|
||||||
|
}
|
||||||
|
catch (TorControlLibrary.Exceptions.TorUnknownStreamException e)
|
||||||
|
{ //Stream no longer exists, clean up and exit
|
||||||
|
RemoveStream(stream);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_controlConnection.CloseStream(stream.StreamID);
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override void RemoveCircuit(Circuit circuit)
|
||||||
|
{
|
||||||
|
lock (DestinationDictionary)
|
||||||
|
{
|
||||||
|
if (DestinationDictionary.ContainsValue(circuit))
|
||||||
|
DestinationDictionary.Remove(DestinationDictionary.First(p => p.Value.Equals(circuit)).Key);
|
||||||
|
}
|
||||||
|
base.RemoveCircuit(circuit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
Hermes/CircuitManagers/ICircuitManager.cs
Normal file
24
Hermes/CircuitManagers/ICircuitManager.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
using Hermes.Selectors;
|
||||||
|
|
||||||
|
namespace Hermes.CircuitManagers
|
||||||
|
{
|
||||||
|
public interface ICircuitManager
|
||||||
|
{
|
||||||
|
void Initialize(TorControlLibrary.ControlConnection controlConnection, IRouteSelector RouteSelector, Dictionary<String, String> parameters);
|
||||||
|
void Initialize(TorControlLibrary.ControlConnection controlConnection, IRouteSelector RouteSelector);
|
||||||
|
|
||||||
|
//Circuit management
|
||||||
|
void AddCircuit(Circuit circuit);
|
||||||
|
Circuit GetCircuit(Int32 circuitID);
|
||||||
|
void RemoveCircuit(Circuit circuit);
|
||||||
|
void RequestNewCircuit();
|
||||||
|
|
||||||
|
//Stream Management
|
||||||
|
void RemoveStream(Int32 circuitID, Int32 streamID);
|
||||||
|
}
|
||||||
|
}
|
||||||
116
Hermes/CircuitManagers/OneShotCircuitManager.cs
Normal file
116
Hermes/CircuitManagers/OneShotCircuitManager.cs
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
|
||||||
|
namespace Hermes.CircuitManagers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// One of the most basic circuit managers, using randomization to select the next viable circuit
|
||||||
|
/// </summary>
|
||||||
|
public class OneShotRoundRobinCircuitManager : EventBasedCircuitManager, ICircuitManager
|
||||||
|
{
|
||||||
|
#region Event Overrides
|
||||||
|
protected override void OnCircuitBuilt(TorControlLibrary.Responses.EventResponse response)
|
||||||
|
{
|
||||||
|
//Add the completely built circuit
|
||||||
|
AddCircuit(ParseCircuitResponse(response));
|
||||||
|
}
|
||||||
|
protected override void OnCircuitClosed(TorControlLibrary.Responses.EventResponse response)
|
||||||
|
{
|
||||||
|
Objects.Circuit circ = GetCircuit(response.ID);
|
||||||
|
RemoveCircuit(circ);
|
||||||
|
if (circ.Purpose.Equals("USER") || circ.Purpose.Equals("GENERAL"))
|
||||||
|
RequestNewCircuit();
|
||||||
|
}
|
||||||
|
protected override void OnCircuitFailed(TorControlLibrary.Responses.EventResponse response)
|
||||||
|
{
|
||||||
|
Objects.Circuit circ = GetCircuit(response.ID);
|
||||||
|
if(circ != null)
|
||||||
|
RemoveCircuit(circ);
|
||||||
|
|
||||||
|
if (response.EventInformation.Contains("PURPOSE=USER") || response.EventInformation.Contains("PURPOSE=GENERAL"))
|
||||||
|
RequestNewCircuit();
|
||||||
|
}
|
||||||
|
protected override void OnStreamClosed(TorControlLibrary.Responses.EventResponse response)
|
||||||
|
{
|
||||||
|
Stream stream = Stream.ParseStream(response);
|
||||||
|
RemoveStream(stream);
|
||||||
|
}
|
||||||
|
protected override void OnStreamDetached(TorControlLibrary.Responses.EventResponse response)
|
||||||
|
{
|
||||||
|
Stream stream = Stream.ParseStream(response);
|
||||||
|
if (stream.CircuitID != 0)
|
||||||
|
stream.Circuit = GetCircuit(stream.CircuitID);
|
||||||
|
|
||||||
|
RemoveStream(stream);
|
||||||
|
|
||||||
|
if (stream.Purpose.Equals("USER") || stream.Purpose.Equals("GENERAL"))
|
||||||
|
AssignStream(stream);
|
||||||
|
}
|
||||||
|
protected override void OnStreamFailed(TorControlLibrary.Responses.EventResponse response)
|
||||||
|
{
|
||||||
|
Stream stream = Stream.ParseStream(response);
|
||||||
|
if (stream.CircuitID != 0)
|
||||||
|
stream.Circuit = GetCircuit(stream.CircuitID);
|
||||||
|
|
||||||
|
RemoveStream(stream);
|
||||||
|
}
|
||||||
|
protected override void OnStreamNew(TorControlLibrary.Responses.EventResponse response)
|
||||||
|
{
|
||||||
|
Stream stream = Stream.ParseStream(response);
|
||||||
|
if (stream.CircuitID != 0)
|
||||||
|
stream.Circuit = GetCircuit(stream.CircuitID);
|
||||||
|
|
||||||
|
if (stream.Purpose.Equals("USER") || stream.Purpose.Equals("GENERAL"))
|
||||||
|
AssignStream(stream);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
protected virtual void AssignStream(Stream stream)
|
||||||
|
{
|
||||||
|
Circuit circ = GetCircuitForStream(stream);
|
||||||
|
while (circ == null)
|
||||||
|
{
|
||||||
|
//Wait for more circuits to build
|
||||||
|
System.Threading.Thread.Sleep(5000);
|
||||||
|
circ = GetCircuitForStream(stream);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AssignStreamToCircuit(stream, circ);
|
||||||
|
}
|
||||||
|
catch (TorControlLibrary.Exceptions.TorUnknownCircuitException e)
|
||||||
|
{ //The circuit has become invalidated, we need to try again
|
||||||
|
//cleanup
|
||||||
|
RemoveCircuit(circ);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_controlConnection.CloseCircuit(circ.CircuitID);
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
//Call this function again, with hopefully better results next time
|
||||||
|
AssignStream(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override void AssignStreamToCircuit(Stream stream, Circuit circuit)
|
||||||
|
{
|
||||||
|
//Handles internal objects
|
||||||
|
base.AssignStreamToCircuit(stream, circuit);
|
||||||
|
_controlConnection.AttachStream(stream.StreamID, circuit.CircuitID);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// This method chooses the circuit to attach to the specified stream
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected virtual Circuit GetCircuitForStream(Stream stream)
|
||||||
|
{
|
||||||
|
//Round Robin the next circuit
|
||||||
|
if (stream.Destination != null)
|
||||||
|
return Circuits.Where(p => p.Routers.Last().Value.ExitPolicy.IsAcceptableDestination(stream.Destination) && p.AttachedStreams.Count == Circuits.Min(z => z.AttachedStreams.Count)).FirstOrDefault();
|
||||||
|
else
|
||||||
|
return Circuits.Where(p => p.AttachedStreams.Count == Circuits.Min(z => z.AttachedStreams.Count)).FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
138
Hermes/CircuitManagers/OneShotRoundRobinCircuitManager.cs
Normal file
138
Hermes/CircuitManagers/OneShotRoundRobinCircuitManager.cs
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
using TorControlLibrary.Responses;
|
||||||
|
|
||||||
|
namespace Hermes.CircuitManagers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// One of the most basic circuit managers, using randomization to select the next viable circuit
|
||||||
|
/// </summary>
|
||||||
|
public class OneShotRoundRobinCircuitManager : EventBasedCircuitManager, ICircuitManager
|
||||||
|
{
|
||||||
|
#region Event Overrides
|
||||||
|
protected override void OnCircuitBuilt(TorControlLibrary.Responses.EventResponse response)
|
||||||
|
{
|
||||||
|
//Add the completely built circuit
|
||||||
|
AddCircuit(ParseCircuitResponse(response));
|
||||||
|
}
|
||||||
|
protected override void OnCircuitClosed(TorControlLibrary.Responses.EventResponse response)
|
||||||
|
{
|
||||||
|
Objects.Circuit circ = GetCircuit(response.ID);
|
||||||
|
if(circ != null)
|
||||||
|
RemoveCircuit(circ);
|
||||||
|
|
||||||
|
if (response.EventInformation.Contains("PURPOSE=USER") || response.EventInformation.Contains("PURPOSE=GENERAL") && CircuitCount < ExpectedCircuits)
|
||||||
|
RequestNewCircuit();
|
||||||
|
}
|
||||||
|
protected override void OnCircuitFailed(TorControlLibrary.Responses.EventResponse response)
|
||||||
|
{
|
||||||
|
Objects.Circuit circ = GetCircuit(response.ID);
|
||||||
|
if(circ != null)
|
||||||
|
RemoveCircuit(circ);
|
||||||
|
|
||||||
|
if (response.EventInformation.Contains("PURPOSE=USER") || response.EventInformation.Contains("PURPOSE=GENERAL") && CircuitCount < ExpectedCircuits)
|
||||||
|
RequestNewCircuit();
|
||||||
|
}
|
||||||
|
protected override void OnStreamClosed(TorControlLibrary.Responses.EventResponse response)
|
||||||
|
{
|
||||||
|
Stream stream = Stream.ParseStream(response);
|
||||||
|
RemoveStream(stream);
|
||||||
|
}
|
||||||
|
protected override void OnStreamDetached(TorControlLibrary.Responses.EventResponse response)
|
||||||
|
{
|
||||||
|
Stream stream = Stream.ParseStream(response);
|
||||||
|
if (stream.CircuitID != 0)
|
||||||
|
stream.Circuit = GetCircuit(stream.CircuitID);
|
||||||
|
|
||||||
|
RemoveStream(stream);
|
||||||
|
|
||||||
|
if (stream.Purpose != null && (stream.Purpose.Equals("USER") || stream.Purpose.Equals("GENERAL")))
|
||||||
|
AssignStream(stream);
|
||||||
|
}
|
||||||
|
protected override void OnStreamFailed(TorControlLibrary.Responses.EventResponse response)
|
||||||
|
{
|
||||||
|
Stream stream = Stream.ParseStream(response);
|
||||||
|
if (stream.CircuitID != 0)
|
||||||
|
stream.Circuit = GetCircuit(stream.CircuitID);
|
||||||
|
|
||||||
|
RemoveStream(stream);
|
||||||
|
}
|
||||||
|
protected override void OnStreamNewResolved(EventResponse response)
|
||||||
|
{
|
||||||
|
OnStreamNew(response);
|
||||||
|
//base.OnStreamNewResolved(response);
|
||||||
|
}
|
||||||
|
protected override void OnStreamNew(TorControlLibrary.Responses.EventResponse response)
|
||||||
|
{
|
||||||
|
Stream stream = Stream.ParseStream(response);
|
||||||
|
if (stream.CircuitID != 0)
|
||||||
|
stream.Circuit = GetCircuit(stream.CircuitID);
|
||||||
|
|
||||||
|
if (stream.Purpose.Equals("USER") || stream.Purpose.Equals("GENERAL"))
|
||||||
|
AssignStream(stream);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
protected virtual void AssignStream(Stream stream)
|
||||||
|
{
|
||||||
|
Circuit circ = GetCircuitForStream(stream);
|
||||||
|
while (circ == null)
|
||||||
|
{
|
||||||
|
//Wait for more circuits to build
|
||||||
|
System.Threading.Thread.Sleep(5000);
|
||||||
|
circ = GetCircuitForStream(stream);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AssignStreamToCircuit(stream, circ);
|
||||||
|
}
|
||||||
|
catch (TorControlLibrary.Exceptions.TorUnknownCircuitException e)
|
||||||
|
{ //The circuit has become invalidated, we need to try again
|
||||||
|
//cleanup
|
||||||
|
RemoveCircuit(circ);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_controlConnection.CloseCircuit(circ.CircuitID);
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
//Call this function again, with hopefully better results next time
|
||||||
|
AssignStream(stream);
|
||||||
|
}
|
||||||
|
catch (TorControlLibrary.Exceptions.TorUnknownStreamException e)
|
||||||
|
{ //Stream no longer exists, clean up and exit
|
||||||
|
RemoveStream(stream);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_controlConnection.CloseStream(stream.StreamID);
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override void AssignStreamToCircuit(Stream stream, Circuit circuit)
|
||||||
|
{
|
||||||
|
//Handles internal objects
|
||||||
|
base.AssignStreamToCircuit(stream, circuit);
|
||||||
|
_controlConnection.AttachStream(stream.StreamID, circuit.CircuitID);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// This method chooses the circuit to attach to the specified stream
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected virtual Circuit GetCircuitForStream(Stream stream)
|
||||||
|
{
|
||||||
|
Circuit circ;
|
||||||
|
//Round Robin the next circuit
|
||||||
|
if (stream.Destination != null)
|
||||||
|
{
|
||||||
|
circ = Circuits.OrderBy(p => p.AttachedStreams.Count).FirstOrDefault(p => p.Routers.Last().Value.ExitPolicy.IsAcceptableDestination(stream.Destination));
|
||||||
|
if (circ != null)
|
||||||
|
return circ;
|
||||||
|
}
|
||||||
|
//return a circuit that won't necessarily exit successfully to avoid deadlocks and cycle for new circuits
|
||||||
|
return Circuits.OrderBy(p => p.AttachedStreams.Count).FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
50
Hermes/CircuitManagers/PersistedCircuitManager.cs
Normal file
50
Hermes/CircuitManagers/PersistedCircuitManager.cs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Hermes.CircuitManagers
|
||||||
|
{
|
||||||
|
public class PersistedCircuitManager : EventBasedCircuitManager
|
||||||
|
{
|
||||||
|
internal List<PersistanceStream> PersistedCircuitConnections { get; set; }
|
||||||
|
|
||||||
|
internal void SendMaintenanceRequest(PersistanceStream stream)
|
||||||
|
{
|
||||||
|
//Connections are persistent by default
|
||||||
|
const String request = "GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n";
|
||||||
|
|
||||||
|
stream.Writer.Write(request);
|
||||||
|
String response = stream.Reader.ReadToEnd();
|
||||||
|
}
|
||||||
|
private void persistanceManagementThread()
|
||||||
|
{
|
||||||
|
PersistedCircuitConnections.ForEach(p =>
|
||||||
|
{
|
||||||
|
if (DateTime.Now.Subtract(p.LastRefreshed) > new TimeSpan(0, 1, 0))
|
||||||
|
{
|
||||||
|
Action<PersistanceStream> task = new Action<PersistanceStream>(SendMaintenanceRequest);
|
||||||
|
task.BeginInvoke(p, null, null);
|
||||||
|
p.LastRefreshed = DateTime.Now;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
System.Threading.Thread.Sleep(1000);
|
||||||
|
}
|
||||||
|
internal class PersistanceStream
|
||||||
|
{
|
||||||
|
public PersistanceStream(Stream stream)
|
||||||
|
{
|
||||||
|
LastRefreshed = DateTime.Now;
|
||||||
|
Stream = stream;
|
||||||
|
Writer = new StreamWriter(Stream);
|
||||||
|
Reader = new StreamReader(Stream);
|
||||||
|
}
|
||||||
|
public DateTime LastRefreshed { get; set; }
|
||||||
|
public Stream Stream { get; set; }
|
||||||
|
public StreamWriter Writer { get; set; }
|
||||||
|
public StreamReader Reader { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
Hermes/Filters/BandwidthObservedFilter.cs
Normal file
46
Hermes/Filters/BandwidthObservedFilter.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
|
||||||
|
namespace Hermes.Filters
|
||||||
|
{
|
||||||
|
class BandwidthObservedFilter : RouterFilter
|
||||||
|
{
|
||||||
|
public BandwidthObservedFilter() { }
|
||||||
|
public BandwidthObservedFilter(RouterFilter previousFilter)
|
||||||
|
: base(previousFilter) { }
|
||||||
|
|
||||||
|
public override void Initialize(TorControlLibrary.ControlConnection connection, Dictionary<string, string> parameters)
|
||||||
|
{
|
||||||
|
Initialize(connection);
|
||||||
|
Int32 speed;
|
||||||
|
if (Int32.TryParse(parameters["MinimumObservableSpeed"], out speed))
|
||||||
|
_minimumSpeed = speed;
|
||||||
|
}
|
||||||
|
public override IEnumerable<Objects.Router> FilterRouters(IEnumerable<Objects.Router> fullRouterSet)
|
||||||
|
{
|
||||||
|
IEnumerable<Router> routers = base.FilterRouters(fullRouterSet);
|
||||||
|
List<Router> bandwidthRouters = new List<Router>();
|
||||||
|
foreach (Router router in routers)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TorControlLibrary.Responses.RouterDescription description;
|
||||||
|
//if (!String.IsNullOrEmpty(router.NickName) && !router.NickName.Equals("Unnamed"))
|
||||||
|
// description = Connection.GetRouterDescriptionByNickname(router.NickName);
|
||||||
|
//else
|
||||||
|
description = Connection.GetRouterDescriptionByNickname(String.Format("${0}", router.Identity));
|
||||||
|
if (description.BandwidthObserved > _minimumSpeed)
|
||||||
|
bandwidthRouters.Add(router);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{ //Router description not available
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bandwidthRouters;
|
||||||
|
}
|
||||||
|
private Int32 _minimumSpeed = 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
38
Hermes/Filters/CountryFilter.cs
Normal file
38
Hermes/Filters/CountryFilter.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
using Misc.Geolocation.API;
|
||||||
|
|
||||||
|
namespace Hermes.Filters
|
||||||
|
{
|
||||||
|
class CountryFilter : RouterFilter
|
||||||
|
{
|
||||||
|
public CountryFilter() { }
|
||||||
|
public CountryFilter(RouterFilter previousFilter)
|
||||||
|
: base(previousFilter) { }
|
||||||
|
|
||||||
|
public override void Initialize(TorControlLibrary.ControlConnection connection, Dictionary<string, string> parameters)
|
||||||
|
{
|
||||||
|
Initialize(connection);
|
||||||
|
CountryCodes = new List<String>(parameters["CountryCode"].Split(','));
|
||||||
|
}
|
||||||
|
public override IEnumerable<Router> FilterRouters(IEnumerable<Router> fullRouterSet)
|
||||||
|
{
|
||||||
|
Location routerLocation;
|
||||||
|
LookupService ls = new LookupService("GeoLiteCity.dat", LookupService.GEOIP_STANDARD);
|
||||||
|
List<Router> routers = new List<Router>(base.FilterRouters(fullRouterSet));
|
||||||
|
List<Router> countryRouters = new List<Router>();
|
||||||
|
foreach (Router router in routers)
|
||||||
|
{
|
||||||
|
routerLocation = ls.getLocation(router.Address);
|
||||||
|
if(routerLocation != null)
|
||||||
|
if(CountryCodes.Contains(routerLocation.countryCode))
|
||||||
|
countryRouters.Add(router);
|
||||||
|
}
|
||||||
|
return countryRouters;
|
||||||
|
}
|
||||||
|
public List<String> CountryCodes { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
47
Hermes/Filters/ExitPolicyFilter.cs
Normal file
47
Hermes/Filters/ExitPolicyFilter.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Net;
|
||||||
|
using Hermes.Objects;
|
||||||
|
|
||||||
|
namespace Hermes.Filters
|
||||||
|
{
|
||||||
|
class ExitPolicyFilter : RouterFilter
|
||||||
|
{
|
||||||
|
public ExitPolicyFilter() { }
|
||||||
|
public ExitPolicyFilter(RouterFilter previousFilter)
|
||||||
|
: base(previousFilter) { }
|
||||||
|
|
||||||
|
public override void Initialize(TorControlLibrary.ControlConnection connection, Dictionary<string, string> parameters)
|
||||||
|
{
|
||||||
|
String ep = parameters["ExitEndPoint"];
|
||||||
|
Initialize(connection);
|
||||||
|
|
||||||
|
Endpoint = new IPEndPoint(IPAddress.Parse(ep.Substring(0, ep.IndexOf(":"))),
|
||||||
|
Int32.Parse(ep.Substring(ep.IndexOf(":") + 1, ep.Length - (ep.IndexOf(":") + 1))));
|
||||||
|
}
|
||||||
|
public override IEnumerable<Objects.Router> FilterRouters(IEnumerable<Objects.Router> fullRouterSet)
|
||||||
|
{
|
||||||
|
List<Router> routers = new List<Router>();
|
||||||
|
foreach (Router router in base.FilterRouters(fullRouterSet))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!router.Flags.Contains("Exit"))
|
||||||
|
{ //non-exits are still added so circuits aren't composed of exit-only.
|
||||||
|
routers.Add(router);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (router.ExitPolicy == null)
|
||||||
|
router.ExitPolicy = Connection.GetRouterDescriptionByNickname(String.Format("${0}", router.Identity)).ExitPolicy;
|
||||||
|
if (router.ExitPolicy.IsAcceptableDestination(Endpoint))
|
||||||
|
routers.Add(router);
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
}
|
||||||
|
return routers;
|
||||||
|
}
|
||||||
|
public IPEndPoint Endpoint { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
44
Hermes/Filters/FlagFilter.cs
Normal file
44
Hermes/Filters/FlagFilter.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
|
||||||
|
namespace Hermes.Filters
|
||||||
|
{
|
||||||
|
class FlagFilter : RouterFilter
|
||||||
|
{
|
||||||
|
public FlagFilter() { }
|
||||||
|
public FlagFilter(RouterFilter previousFilter)
|
||||||
|
: base(previousFilter) { }
|
||||||
|
|
||||||
|
public override IEnumerable<Router> FilterRouters(IEnumerable<Router> fullRouterSet)
|
||||||
|
{
|
||||||
|
Routers = new List<Router>(base.FilterRouters(fullRouterSet));
|
||||||
|
return FilterByFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize(TorControlLibrary.ControlConnection connection, Dictionary<string, string> parameters)
|
||||||
|
{
|
||||||
|
Initialize(connection);
|
||||||
|
if (!parameters.ContainsKey("Flags"))
|
||||||
|
throw new ApplicationException();
|
||||||
|
if (!parameters.ContainsKey("AntiFlags"))
|
||||||
|
throw new ApplicationException();
|
||||||
|
|
||||||
|
Flags = new List<string>(parameters["Flags"].Split(','));
|
||||||
|
AntiFlags = new List<string>(parameters["AntiFlags"].Split(','));
|
||||||
|
}
|
||||||
|
protected virtual IEnumerable<Router> FilterByFlags()
|
||||||
|
{
|
||||||
|
foreach (String flag in Flags)
|
||||||
|
Routers.RemoveAll(p => !p.Flags.Contains(flag));
|
||||||
|
|
||||||
|
foreach (String flag in AntiFlags)
|
||||||
|
Routers.RemoveAll(p => p.Flags.Contains(flag));
|
||||||
|
return Routers;
|
||||||
|
}
|
||||||
|
public List<String> Flags { get; set; }
|
||||||
|
public List<String> AntiFlags { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
16
Hermes/Filters/IRouterFilter.cs
Normal file
16
Hermes/Filters/IRouterFilter.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
using TorControlLibrary;
|
||||||
|
|
||||||
|
namespace Hermes.Filters
|
||||||
|
{
|
||||||
|
public interface IRouterFilter
|
||||||
|
{
|
||||||
|
IEnumerable<Router> FilterRouters(IEnumerable<Router> fullRouterSet);
|
||||||
|
void Initialize(ControlConnection connection, Dictionary<String, String> parameters);
|
||||||
|
void Initialize(ControlConnection connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
45
Hermes/Filters/ProximityFilter.cs
Normal file
45
Hermes/Filters/ProximityFilter.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Misc.Geolocation.API;
|
||||||
|
using Hermes.Objects;
|
||||||
|
|
||||||
|
namespace Hermes.Filters
|
||||||
|
{
|
||||||
|
class ProximityFilter : RouterFilter
|
||||||
|
{
|
||||||
|
public ProximityFilter() { }
|
||||||
|
public ProximityFilter(RouterFilter previousFilter) : base(previousFilter) { }
|
||||||
|
|
||||||
|
public override void Initialize(TorControlLibrary.ControlConnection connection, Dictionary<string, string> parameters)
|
||||||
|
{
|
||||||
|
Initialize(connection);
|
||||||
|
|
||||||
|
String proximity = parameters["Proximity"];
|
||||||
|
if (!Double.TryParse(proximity, out maximumDistance))
|
||||||
|
throw new FormatException("The proximity argument was unable to be parsed in the ProximityFilter class.");
|
||||||
|
sourceAddress = parameters["SourceAddress"];
|
||||||
|
if (String.IsNullOrEmpty(sourceAddress))
|
||||||
|
throw new FormatException("Source Address was not specified for the ProximityFilter.");
|
||||||
|
}
|
||||||
|
public override IEnumerable<Objects.Router> FilterRouters(IEnumerable<Objects.Router> fullRouterSet)
|
||||||
|
{
|
||||||
|
Location routerLocation;
|
||||||
|
LookupService ls = new LookupService("GeoLiteCity.dat", LookupService.GEOIP_STANDARD);
|
||||||
|
Location sourceLocation = ls.getLocation(sourceAddress);
|
||||||
|
List<Router> routers = new List<Router>(base.FilterRouters(fullRouterSet));
|
||||||
|
List<Router> proximityRouters = new List<Router>();
|
||||||
|
foreach (Router router in routers)
|
||||||
|
{
|
||||||
|
routerLocation = ls.getLocation(router.Address);
|
||||||
|
if(routerLocation != null)
|
||||||
|
if (routerLocation.distance(sourceLocation) <= maximumDistance)
|
||||||
|
proximityRouters.Add(router);
|
||||||
|
}
|
||||||
|
return proximityRouters;
|
||||||
|
}
|
||||||
|
private double maximumDistance = 0;
|
||||||
|
private String sourceAddress = String.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
36
Hermes/Filters/RouterFitler.cs
Normal file
36
Hermes/Filters/RouterFitler.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
using TorControlLibrary;
|
||||||
|
|
||||||
|
namespace Hermes.Filters
|
||||||
|
{
|
||||||
|
abstract class RouterFilter : IRouterFilter
|
||||||
|
{
|
||||||
|
public RouterFilter() { }
|
||||||
|
public RouterFilter(RouterFilter previousFilter)
|
||||||
|
{
|
||||||
|
PreviousFilter = previousFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IEnumerable<Router> FilterRouters(IEnumerable<Router> fullRouterSet)
|
||||||
|
{
|
||||||
|
if (PreviousFilter != null)
|
||||||
|
return PreviousFilter.FilterRouters(fullRouterSet);
|
||||||
|
else
|
||||||
|
return fullRouterSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void Initialize(ControlConnection connection, Dictionary<string, string> parameters);
|
||||||
|
|
||||||
|
public virtual void Initialize(ControlConnection connection)
|
||||||
|
{
|
||||||
|
Connection = connection;
|
||||||
|
}
|
||||||
|
public List<Router> Routers { get; set; }
|
||||||
|
protected RouterFilter PreviousFilter { get; set; }
|
||||||
|
public ControlConnection Connection { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
47
Hermes/Filters/RouterStatusBasedFilter.cs
Normal file
47
Hermes/Filters/RouterStatusBasedFilter.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
using TorControlLibrary;
|
||||||
|
using TorControlLibrary.Responses;
|
||||||
|
|
||||||
|
namespace Hermes.Filters
|
||||||
|
{
|
||||||
|
[Obsolete()]
|
||||||
|
public abstract class RouterStatusBasedFilter
|
||||||
|
{
|
||||||
|
public RouterStatusBasedFilter()
|
||||||
|
{ }
|
||||||
|
public List<Router> GetFilteredRouterList()
|
||||||
|
{
|
||||||
|
if(_routerStatuses.Count == 0)
|
||||||
|
PopulateRouterStatuses();
|
||||||
|
return ParseRouterStatus(FilterRouters());
|
||||||
|
}
|
||||||
|
protected void PopulateRouterStatuses()
|
||||||
|
{
|
||||||
|
if (!Connection.Connected)
|
||||||
|
Connection.Connect();
|
||||||
|
_routerStatuses = Connection.GetAllRouterStatusInfo();
|
||||||
|
}
|
||||||
|
protected List<Router> ParseRouterStatus(List<RouterStatusResponse> statuses)
|
||||||
|
{
|
||||||
|
List<Router> routers = new List<Router>();
|
||||||
|
foreach (RouterStatusResponse resp in statuses)
|
||||||
|
routers.Add(new Router(resp));
|
||||||
|
//{
|
||||||
|
// Address = resp.Address,
|
||||||
|
// Digest = resp.Digest,
|
||||||
|
// Identity = resp.Identity,
|
||||||
|
// NickName = resp.NickName,
|
||||||
|
// Publication = resp.Publication,
|
||||||
|
// Flags = new List<String>(resp.Flags)
|
||||||
|
//});
|
||||||
|
return routers;
|
||||||
|
}
|
||||||
|
public abstract List<RouterStatusResponse> FilterRouters();
|
||||||
|
public ControlConnection Connection { get; set; }
|
||||||
|
protected List<RouterStatusResponse> _routerStatuses = new List<RouterStatusResponse>();
|
||||||
|
}
|
||||||
|
}
|
||||||
27
Hermes/Filters/WhitelistFilter.cs
Normal file
27
Hermes/Filters/WhitelistFilter.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
|
||||||
|
namespace Hermes.Filters
|
||||||
|
{
|
||||||
|
class WhitelistFilter : RouterFilter
|
||||||
|
{
|
||||||
|
public WhitelistFilter() { }
|
||||||
|
public WhitelistFilter(RouterFilter previousFilter)
|
||||||
|
: base(previousFilter) { }
|
||||||
|
|
||||||
|
public override void Initialize(TorControlLibrary.ControlConnection connection, Dictionary<string, string> parameters)
|
||||||
|
{
|
||||||
|
Initialize(connection);
|
||||||
|
_whitelistedRouters = new List<string>(parameters["WhitelistedRouters"].Split(','));
|
||||||
|
}
|
||||||
|
public override IEnumerable<Router> FilterRouters(IEnumerable<Router> fullRouterSet)
|
||||||
|
{
|
||||||
|
List<Router> routers = new List<Router>(base.FilterRouters(fullRouterSet));
|
||||||
|
return routers.Where(p => _whitelistedRouters.Contains(p.NickName));
|
||||||
|
}
|
||||||
|
private List<String> _whitelistedRouters;
|
||||||
|
}
|
||||||
|
}
|
||||||
98
Hermes/Hermes.csproj
Normal file
98
Hermes/Hermes.csproj
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||||
|
<ProductVersion>8.0.30703</ProductVersion>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>{3DE6415A-1DED-4F75-9202-39BDF012BB5A}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>Hermes</RootNamespace>
|
||||||
|
<AssemblyName>Hermes</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Misc.Geolocation.API, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>.\Misc.Geolocation.API.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="System.Configuration" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="CircuitManagers\CircuitManagerBase.cs" />
|
||||||
|
<Compile Include="CircuitManagers\EventBasedCircuitManager.cs" />
|
||||||
|
<Compile Include="CircuitManagers\HostSectionedCircuitManager.cs" />
|
||||||
|
<Compile Include="CircuitManagers\ICircuitManager.cs" />
|
||||||
|
<Compile Include="CircuitManagers\OneShotRoundRobinCircuitManager.cs" />
|
||||||
|
<Compile Include="CircuitManagers\PersistedCircuitManager.cs" />
|
||||||
|
<Compile Include="Filters\BandwidthObservedFilter.cs" />
|
||||||
|
<Compile Include="Filters\CountryFilter.cs" />
|
||||||
|
<Compile Include="Filters\ExitPolicyFilter.cs" />
|
||||||
|
<Compile Include="Filters\ProximityFilter.cs" />
|
||||||
|
<Compile Include="Filters\RouterFitler.cs" />
|
||||||
|
<Compile Include="Filters\RouterStatusBasedFilter.cs" />
|
||||||
|
<Compile Include="Filters\WhitelistFilter.cs" />
|
||||||
|
<Compile Include="Objects\Circuit.cs" />
|
||||||
|
<Compile Include="Filters\FlagFilter.cs" />
|
||||||
|
<Compile Include="Filters\IRouterFilter.cs" />
|
||||||
|
<Compile Include="Objects\Socks5Stream.cs" />
|
||||||
|
<Compile Include="Selectors\IRouteSelector.cs" />
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Objects\Router.cs" />
|
||||||
|
<Compile Include="Selectors\RandomTwoRouterCircuits.cs" />
|
||||||
|
<Compile Include="Objects\Stream.cs" />
|
||||||
|
<Compile Include="Selectors\RouteSelectorBase.cs" />
|
||||||
|
<Compile Include="Selectors\UniqueHighestSpeedSingleRouterSelector.cs" />
|
||||||
|
<Compile Include="Selectors\UniqueRouterHighestSpeedTwoRouterSelector.cs" />
|
||||||
|
<Compile Include="Selectors\UniqueRouteSelector.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\TorControlLibrary\TorControlLibrary.csproj">
|
||||||
|
<Project>{EF216A86-F64F-4C76-9A86-EEE8E5484EF9}</Project>
|
||||||
|
<Name>TorControlLibrary</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Misc.Geolocation.API.dll" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
||||||
BIN
Hermes/Misc.Geolocation.API.dll
Normal file
BIN
Hermes/Misc.Geolocation.API.dll
Normal file
Binary file not shown.
52
Hermes/Objects/Circuit.cs
Normal file
52
Hermes/Objects/Circuit.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using TorControlLibrary.Responses;
|
||||||
|
|
||||||
|
namespace Hermes.Objects
|
||||||
|
{
|
||||||
|
public class Circuit
|
||||||
|
{
|
||||||
|
public static Circuit ParseCircuit(EventResponse response)
|
||||||
|
{
|
||||||
|
Circuit circ = new Circuit() { CircuitID = response.ID };
|
||||||
|
String[] circParts = response.EventInformation.Split(' ');
|
||||||
|
//650 CIRC 21414 BUILT Strangelove,KiwiBirdSuperstar,svengunnarsrelay PURPOSE=GENERAL
|
||||||
|
if(circParts.Length >= 3)
|
||||||
|
{
|
||||||
|
foreach (String routerName in circParts[2].Split(','))
|
||||||
|
if (routerName.StartsWith("$"))
|
||||||
|
circ.AddNextRouter(new Router() { Identity = routerName });
|
||||||
|
else
|
||||||
|
circ.AddNextRouter(new Router() { NickName = routerName });
|
||||||
|
}
|
||||||
|
//Start at the first section of additional circuit information, and look for the purpose
|
||||||
|
for (int i = 3; i < circParts.Length; i++)
|
||||||
|
if (circParts[i].StartsWith("PURPOSE"))
|
||||||
|
circ.Purpose = circParts[i].Substring(circParts[i].IndexOf('=') + 1);
|
||||||
|
return circ;
|
||||||
|
}
|
||||||
|
public Circuit()
|
||||||
|
{
|
||||||
|
Routers = new SortedList<int, Router>();
|
||||||
|
AttachedStreams = new List<Stream>();
|
||||||
|
}
|
||||||
|
public override String ToString()
|
||||||
|
{
|
||||||
|
String routerCircuit = String.Empty;
|
||||||
|
for (int i = 0; i < Routers.Count; i++)
|
||||||
|
routerCircuit += String.Format("${0},", Routers[i + 1].Identity);
|
||||||
|
routerCircuit = routerCircuit.TrimEnd(new[] { ',' });
|
||||||
|
return routerCircuit;
|
||||||
|
}
|
||||||
|
public void AddNextRouter(Router router)
|
||||||
|
{
|
||||||
|
Routers.Add(Routers.Count + 1, router);
|
||||||
|
}
|
||||||
|
public Int32 CircuitID { get; set; }
|
||||||
|
public SortedList<Int32, Router> Routers { get; set; }
|
||||||
|
public List<Stream> AttachedStreams { get; set; }
|
||||||
|
public String Purpose { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
70
Hermes/Objects/Router.cs
Normal file
70
Hermes/Objects/Router.cs
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Net;
|
||||||
|
using TorControlLibrary.Responses;
|
||||||
|
using TorControlLibrary;
|
||||||
|
|
||||||
|
namespace Hermes.Objects
|
||||||
|
{
|
||||||
|
public class Router : IEquatable<Router>
|
||||||
|
{
|
||||||
|
public Router()
|
||||||
|
{ }
|
||||||
|
public Router(RouterStatusResponse resp)
|
||||||
|
{
|
||||||
|
Address = resp.Address;
|
||||||
|
Digest = resp.Digest;
|
||||||
|
Identity = resp.Identity;
|
||||||
|
NickName = resp.NickName;
|
||||||
|
Publication = resp.Publication;
|
||||||
|
Flags = new List<String>(resp.Flags);
|
||||||
|
}
|
||||||
|
public static List<Router> ParseRouterStatusResponses(List<RouterStatusResponse> responses)
|
||||||
|
{
|
||||||
|
List<Router> routers = new List<Router>();
|
||||||
|
foreach (RouterStatusResponse resp in responses)
|
||||||
|
routers.Add(new Router(resp));
|
||||||
|
return routers;
|
||||||
|
}
|
||||||
|
public void AddDescription(RouterDescription desc)
|
||||||
|
{
|
||||||
|
BandwidthObserved = desc.BandwidthObserved;
|
||||||
|
BandwidthAverage = desc.BandwidthAverage;
|
||||||
|
BandwidthBurst = desc.BandwidthBurst;
|
||||||
|
Uptime = desc.Uptime;
|
||||||
|
ExitPolicy = desc.ExitPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IEquatable<Router> Members
|
||||||
|
public bool Equals(Router other)
|
||||||
|
{
|
||||||
|
return this.Digest.Equals(other.Digest) || this.NickName.Equals(other.NickName) || this.Identity.Equals(other.Identity);
|
||||||
|
}
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj == null || !(obj is Router))
|
||||||
|
return false;
|
||||||
|
return Equals((Router)obj);
|
||||||
|
}
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return base.GetHashCode();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public String NickName { get; set; }
|
||||||
|
public String Identity { get; set; }
|
||||||
|
public String Digest { get; set; }
|
||||||
|
public DateTime Publication { get; set; }
|
||||||
|
public IPAddress Address { get; set; }
|
||||||
|
public List<String> Flags { get; set; }
|
||||||
|
//Extended information properties gathered from router description command
|
||||||
|
public Int32 BandwidthObserved { get; set; }
|
||||||
|
public Int32 BandwidthAverage { get; set; }
|
||||||
|
public Int32 BandwidthBurst { get; set; }
|
||||||
|
public TimeSpan Uptime { get; set; }
|
||||||
|
public ExitPolicy ExitPolicy { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
95
Hermes/Objects/Socks5Stream.cs
Normal file
95
Hermes/Objects/Socks5Stream.cs
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Hermes.Objects
|
||||||
|
{
|
||||||
|
public sealed class Socks5Stream : NetworkStream
|
||||||
|
{
|
||||||
|
public Socks5Stream(String proxyAddress, Int16 proxyPort, String destinationAddress, Int16 destinationPort, String socksUsername = null, String socksPassword = null)
|
||||||
|
: base(ConnectToSocks5Server(proxyAddress, proxyPort))
|
||||||
|
{
|
||||||
|
//This class is now connected to the SOCKS server
|
||||||
|
byte[] buffer = new byte[1500];
|
||||||
|
BinaryReader reader = new BinaryReader(this);
|
||||||
|
BinaryWriter writer = new BinaryWriter(this);
|
||||||
|
MemoryStream bufferStream = new MemoryStream(buffer);
|
||||||
|
BinaryWriter bufferWriter = new BinaryWriter(bufferStream);
|
||||||
|
|
||||||
|
//Initial negotiation - provide available authentication methods 0x00 = no auth, 0x02 = user/pass
|
||||||
|
if(socksUsername == null || socksPassword == null)
|
||||||
|
writer.Write(new byte[] { 0x05, 0x01, 0x00 });
|
||||||
|
else
|
||||||
|
writer.Write(new byte[] { 0x05, 0x02, 0x00, 0x02 });
|
||||||
|
|
||||||
|
reader.Read(buffer, 0, buffer.Length);
|
||||||
|
if (buffer[1] == 0x02)
|
||||||
|
{ //Authentication required
|
||||||
|
bufferStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
bufferWriter.Write((byte)0x01); //Version 1
|
||||||
|
bufferWriter.Write((byte)socksUsername.Length);
|
||||||
|
bufferWriter.Write(Encoding.ASCII.GetBytes(socksUsername));
|
||||||
|
bufferWriter.Write((byte)socksPassword.Length);
|
||||||
|
bufferWriter.Write(Encoding.ASCII.GetBytes(socksPassword));
|
||||||
|
writer.Write(buffer, 0, 3 + socksUsername.Length + socksPassword.Length);
|
||||||
|
|
||||||
|
reader.Read(buffer, 0, buffer.Length);
|
||||||
|
if (buffer[1] != 0x00)
|
||||||
|
throw new ApplicationException("The provided SOCKS credentials were not accepted by the server.");
|
||||||
|
}
|
||||||
|
//Authenticated, issue the CONNECT command
|
||||||
|
bufferStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
bufferWriter.Write((byte)0x05); //Version
|
||||||
|
bufferWriter.Write((byte)0x01); //CONNECT (versus BIND, UDP ASSOCIATE)
|
||||||
|
bufferWriter.Write((byte)0x00); //Reserved
|
||||||
|
bufferWriter.Write((byte)0x03); //Domain address (IP will be resolved just as well)
|
||||||
|
bufferWriter.Write((byte)destinationAddress.Length);
|
||||||
|
bufferWriter.Write(Encoding.ASCII.GetBytes(destinationAddress));
|
||||||
|
bufferWriter.Write(System.Net.IPAddress.HostToNetworkOrder(destinationPort));
|
||||||
|
writer.Write(buffer,0,5 + destinationAddress.Length + 2); //5 = first 5 bytes, 2 = port size
|
||||||
|
|
||||||
|
reader.Read(buffer, 0, buffer.Length);
|
||||||
|
if(buffer[1] != 0x00)
|
||||||
|
switch (buffer[1])
|
||||||
|
{
|
||||||
|
case 0x01:
|
||||||
|
throw new ApplicationException("The SOCKS server provided the error: General SOCKS server failure");
|
||||||
|
case 0x02:
|
||||||
|
throw new ApplicationException("The SOCKS server provided the error: connection not allowed by ruleset");
|
||||||
|
case 0x03:
|
||||||
|
throw new ApplicationException("The SOCKS server provided the error: Network unreachable");
|
||||||
|
case 0x04:
|
||||||
|
throw new ApplicationException("The SOCKS server provided the error: Host unreachable");
|
||||||
|
case 0x05:
|
||||||
|
throw new ApplicationException("The SOCKS server provided the error: Connection refused");
|
||||||
|
case 0x06:
|
||||||
|
throw new ApplicationException("The SOCKS server provided the error: TTL expired");
|
||||||
|
case 0x07:
|
||||||
|
throw new ApplicationException("The SOCKS server provided the error: Command not supported");
|
||||||
|
case 0x08:
|
||||||
|
throw new ApplicationException("The SOCKS server provided the error: Address type not supported");
|
||||||
|
default:
|
||||||
|
throw new ApplicationException(String.Format("The SOCKS server provided an unrecognized error of type: {0}",buffer[1]));
|
||||||
|
}
|
||||||
|
//At this point, the stream is connected to the end destination.
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Socket ConnectToSocks5Server(String proxyAddress, Int16 proxyPort)
|
||||||
|
{
|
||||||
|
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sock.Connect(proxyAddress, proxyPort);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
throw new ApplicationException(String.Format("There was a problem connecting with the socks server at {0}:{1}",proxyAddress,proxyPort));
|
||||||
|
}
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
Hermes/Objects/Stream.cs
Normal file
56
Hermes/Objects/Stream.cs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using TorControlLibrary.Responses;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace Hermes.Objects
|
||||||
|
{
|
||||||
|
public class Stream
|
||||||
|
{
|
||||||
|
public static Stream ParseStream(EventResponse resp)
|
||||||
|
{
|
||||||
|
Stream stream = new Stream() { StreamID = resp.ID, Attached = false };
|
||||||
|
String[] parts = resp.EventInformation.Split(' ');
|
||||||
|
Int32 circid;
|
||||||
|
|
||||||
|
if (Int32.TryParse(parts[2], out circid))
|
||||||
|
stream.CircuitID = circid;
|
||||||
|
if (parts.Length > 3 && parts[3].Contains(':'))
|
||||||
|
{
|
||||||
|
stream.DestinationHost = parts[3].Substring(0, parts[3].IndexOf(':'));
|
||||||
|
stream.DestinationPort = Int32.Parse(parts[3].Substring(parts[3].IndexOf(':') + 1));
|
||||||
|
}
|
||||||
|
if (resp.EventInformation.Contains("PURPOSE="))
|
||||||
|
{
|
||||||
|
Int32 startIndex = resp.EventInformation.IndexOf("PURPOSE=") + 8;
|
||||||
|
Int32 length = resp.EventInformation.IndexOf(' ', startIndex) - startIndex;
|
||||||
|
stream.Purpose = resp.EventInformation.Substring(startIndex, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
public Int32 StreamID { get; set; }
|
||||||
|
public Circuit Circuit { get; set; }
|
||||||
|
public Int32 CircuitID { get; set; }
|
||||||
|
public Boolean Attached { get; set; }
|
||||||
|
public String DestinationHost { get; set; }
|
||||||
|
public Int32 DestinationPort { get; set; }
|
||||||
|
public IPEndPoint Destination
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
//TODO: This is a big security risk for anonymity, need to figure out a way to get this through tor
|
||||||
|
IPAddress[] addresses = Dns.GetHostAddresses(DestinationHost);
|
||||||
|
if (addresses.Count() > 0)
|
||||||
|
{
|
||||||
|
return new IPEndPoint(addresses.First(), DestinationPort);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public String Purpose { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
361
Hermes/Program.cs
Normal file
361
Hermes/Program.cs
Normal file
@@ -0,0 +1,361 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using TorControlLibrary;
|
||||||
|
using TorControlLibrary.Responses;
|
||||||
|
using Misc.Geolocation.API;
|
||||||
|
using System.Configuration;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Hermes.Filters;
|
||||||
|
using Hermes.Selectors;
|
||||||
|
using Hermes.Objects;
|
||||||
|
using TorControlLibrary.Exceptions;
|
||||||
|
using Hermes.CircuitManagers;
|
||||||
|
|
||||||
|
namespace Hermes
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static IRouterFilter RouterFilter;
|
||||||
|
static IRouteSelector RouteSelector;
|
||||||
|
static List<Router> RouterList;
|
||||||
|
static ControlConnection ControlConnection;
|
||||||
|
//static CircuitManager CircuitManager;
|
||||||
|
static ICircuitManager CircuitManager;
|
||||||
|
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
IPAddress ip = IPAddress.Parse("127.0.0.1");
|
||||||
|
|
||||||
|
ControlConnection = new TorControlLibrary.ControlConnection();
|
||||||
|
//ControlConnection.Connect(new IPEndPoint(IPAddress.Parse("192.168.1.100"), 9090));
|
||||||
|
ControlConnection.Connect();
|
||||||
|
|
||||||
|
//CircuitManager = (ICircuitManager)new OneShotRoundRobinCircuitManager(); //new Hermes.CircuitManager();
|
||||||
|
//CircuitManager = (ICircuitManager)new HostSectionedCircuitManager();
|
||||||
|
CircuitManager = GetCircuitManager();
|
||||||
|
//CircuitManager.Initialize(ControlConnection, RouteSelector);
|
||||||
|
//ControlConnection.ServerEvent += new Action<EventResponse>(ControlConnection_ServerEvent);
|
||||||
|
RouterFilter = BuildRouterFilter();
|
||||||
|
DisableAutomaticCircuitsAndStreamAttachment();
|
||||||
|
InitializeRouterListAndSelector(CircuitManager);
|
||||||
|
Console.WriteLine(string.Format("There are {0} routers in the list. {1} of them are exit nodes.", RouterList.Count, RouterList.Count(p => p.Flags.Contains("Exit"))));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CloseExistingCircuitsAndStreams();
|
||||||
|
|
||||||
|
Console.WriteLine("Hermes started..");
|
||||||
|
ControlConnection.RequestEvents(new List<string>() { "EXTENDED STREAM", "EXTENDED CIRC" });
|
||||||
|
|
||||||
|
Int32 circuits = Int32.Parse(ConfigurationManager.AppSettings["Circuits"]);
|
||||||
|
var settings = new Dictionary<string, string>() { {"ExpectedCircuits", circuits.ToString() } };
|
||||||
|
CircuitManager.Initialize(ControlConnection, RouteSelector, settings);
|
||||||
|
//Create some initial circuits
|
||||||
|
for (int i = 0; i < circuits; i++)
|
||||||
|
{
|
||||||
|
//CreateNewCircuit();
|
||||||
|
CircuitManager.RequestNewCircuit();
|
||||||
|
System.Threading.Thread.Sleep(250);
|
||||||
|
}
|
||||||
|
int step = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (Console.KeyAvailable)
|
||||||
|
break;
|
||||||
|
|
||||||
|
//30 minutes
|
||||||
|
if (step == 1800)
|
||||||
|
{
|
||||||
|
RefreshActiveRouters();
|
||||||
|
step = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
step++;
|
||||||
|
System.Threading.Thread.Sleep(1000);
|
||||||
|
}
|
||||||
|
//Wait for a single key input, then quit
|
||||||
|
Console.ReadKey();
|
||||||
|
EnableAutomaticcircuitsAndStreamAttachment();
|
||||||
|
ControlConnection.Close();
|
||||||
|
}
|
||||||
|
static void InitializeRouterListAndSelector(ICircuitManager circuitManager)
|
||||||
|
{
|
||||||
|
//Get router responses
|
||||||
|
TimeSpan defaultTimeout = ControlConnection.Timeout;
|
||||||
|
ControlConnection.Timeout = TimeSpan.FromMinutes(5);
|
||||||
|
IEnumerable<Router> routers = Router.ParseRouterStatusResponses(ControlConnection.GetAllRouterStatusInfo());
|
||||||
|
routers = RouterFilter.FilterRouters(routers);
|
||||||
|
ControlConnection.Timeout = defaultTimeout;
|
||||||
|
RouterList = new List<Router>(routers);
|
||||||
|
|
||||||
|
String routerSelectorName = ConfigurationManager.AppSettings["RouteSelector"];
|
||||||
|
Type type = Type.GetType(String.Format("Hermes.Selectors.{0}", routerSelectorName));
|
||||||
|
if (type == null)
|
||||||
|
throw new ApplicationException(String.Format("RouteSelector of type {0} not found.", routerSelectorName));
|
||||||
|
|
||||||
|
RouteSelector = (IRouteSelector)Activator.CreateInstance(type);
|
||||||
|
RouteSelector.Initialize(ControlConnection, circuitManager);
|
||||||
|
RouteSelector.SetEffectiveRouterList(RouterList);
|
||||||
|
}
|
||||||
|
static void RefreshActiveRouters()
|
||||||
|
{
|
||||||
|
IEnumerable<Router> routers = Router.ParseRouterStatusResponses(ControlConnection.GetAllRouterStatusInfo());
|
||||||
|
routers = RouterFilter.FilterRouters(routers);
|
||||||
|
RouterList = new List<Router>(routers);
|
||||||
|
RouteSelector.SetEffectiveRouterList(RouterList);
|
||||||
|
}
|
||||||
|
static ICircuitManager GetCircuitManager()
|
||||||
|
{
|
||||||
|
ICircuitManager manager;
|
||||||
|
String circuitManagerName = ConfigurationManager.AppSettings["CircuitManager"];
|
||||||
|
Type type = Type.GetType(String.Format("Hermes.CircuitManagers.{0}", circuitManagerName));
|
||||||
|
if (type == null)
|
||||||
|
throw new ApplicationException(String.Format("CircuitManager of type {0} not found.", circuitManagerName));
|
||||||
|
manager = (ICircuitManager)Activator.CreateInstance(type);
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
static IRouterFilter BuildRouterFilter()
|
||||||
|
{
|
||||||
|
String filterNames = ConfigurationManager.AppSettings["Filters"];
|
||||||
|
object activatedFilter = null;
|
||||||
|
RouterFilter previousFilter = null;
|
||||||
|
RouterFilter firstFilter = null;
|
||||||
|
RouterFilter CurrentFilter = null;
|
||||||
|
foreach (String filterName in filterNames.Split(','))
|
||||||
|
{
|
||||||
|
Type type = Type.GetType(String.Format("Hermes.Filters.{0}",filterName));
|
||||||
|
if (type != null)
|
||||||
|
{
|
||||||
|
if (previousFilter != null)
|
||||||
|
activatedFilter = Activator.CreateInstance(type, new object[] { previousFilter });
|
||||||
|
else
|
||||||
|
{
|
||||||
|
activatedFilter = Activator.CreateInstance(type);
|
||||||
|
firstFilter = (RouterFilter)activatedFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentFilter = (RouterFilter)activatedFilter;
|
||||||
|
|
||||||
|
Dictionary<String, String> paramDictionary = new Dictionary<string, string>();
|
||||||
|
foreach (string key in ConfigurationManager.AppSettings.AllKeys)
|
||||||
|
paramDictionary.Add(key, ConfigurationManager.AppSettings[key]);
|
||||||
|
|
||||||
|
CurrentFilter.Initialize(ControlConnection, paramDictionary);
|
||||||
|
previousFilter = CurrentFilter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CurrentFilter;
|
||||||
|
}
|
||||||
|
static void DisableAutomaticCircuitsAndStreamAttachment()
|
||||||
|
{
|
||||||
|
ControlConnection.SetConfigurationEntry("__DisablePredictedCircuits", "1");
|
||||||
|
ControlConnection.SetConfigurationEntry("MaxOnionsPending", "0");
|
||||||
|
ControlConnection.SetConfigurationEntry("newcircuitperiod", "999999999");
|
||||||
|
ControlConnection.SetConfigurationEntry("maxcircuitdirtiness", "999999999");
|
||||||
|
ControlConnection.SetConfigurationEntry("__LeaveStreamsUnattached", "1");
|
||||||
|
//Hack to avoid having to handle microdescriptors atm TODO: Fix TorLibrary to use Microdescriptors
|
||||||
|
ControlConnection.SetConfigurationEntry("UseMicrodescriptors", "0");
|
||||||
|
ControlConnection.SetConfigurationEntry("FetchUselessDescriptors", "1");
|
||||||
|
}
|
||||||
|
static void EnableAutomaticcircuitsAndStreamAttachment()
|
||||||
|
{
|
||||||
|
ControlConnection.SendRawCommand("RESETCONF __DisablePredictedCircuits");
|
||||||
|
ControlConnection.SendRawCommand("RESETCONF MaxOnionsPending");
|
||||||
|
ControlConnection.SendRawCommand("RESETCONF newcircuitperiod");
|
||||||
|
ControlConnection.SendRawCommand("RESETCONF maxcircuitdirtiness");
|
||||||
|
ControlConnection.SendRawCommand("RESETCONF __LeaveStreamsUnattached");
|
||||||
|
ControlConnection.SendRawCommand("RESETCONF UseMicrodescriptors");
|
||||||
|
ControlConnection.SendRawCommand("RESETCONF FetchUselessDescriptors");
|
||||||
|
}
|
||||||
|
static void CloseExistingCircuitsAndStreams()
|
||||||
|
{
|
||||||
|
List<CircuitStatusResponse> circuits = ControlConnection.GetCircuitStatuses();
|
||||||
|
foreach (CircuitStatusResponse cirResponse in circuits)
|
||||||
|
ControlConnection.CloseCircuit(cirResponse.CircuitID);
|
||||||
|
|
||||||
|
List<StreamStatusResponse> streams = ControlConnection.GetStreamStatuses();
|
||||||
|
foreach (StreamStatusResponse streamResponse in streams)
|
||||||
|
ControlConnection.CloseStream(streamResponse.StreamID);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
static void ControlConnection_ServerEvent(EventResponse obj)
|
||||||
|
{
|
||||||
|
switch (obj.EventType)
|
||||||
|
{
|
||||||
|
case "STREAM":
|
||||||
|
switch (obj.Action)
|
||||||
|
{
|
||||||
|
case "NEW":
|
||||||
|
if (obj.EventInformation.EndsWith("PURPOSE=USER"))
|
||||||
|
ReattachStream(obj);
|
||||||
|
else
|
||||||
|
internalCircuits++;
|
||||||
|
break;
|
||||||
|
case "DETACHED":
|
||||||
|
DetachStream(obj);
|
||||||
|
ReattachStream(obj);
|
||||||
|
break;
|
||||||
|
case "CLOSED":
|
||||||
|
DetachStream(obj);
|
||||||
|
break;
|
||||||
|
case "FAILED":
|
||||||
|
DetachStream(obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "CIRC":
|
||||||
|
switch (obj.Action)
|
||||||
|
{
|
||||||
|
case "BUILT":
|
||||||
|
AddCircuit(obj);
|
||||||
|
break;
|
||||||
|
case "CLOSED":
|
||||||
|
CircuitManager.RemoveCircuit(CircuitManager.GetCircuit(obj.ID));
|
||||||
|
if (internalCircuits == 0)
|
||||||
|
CreateNewCircuit();
|
||||||
|
else
|
||||||
|
internalCircuits--;
|
||||||
|
break;
|
||||||
|
case "FAILED":
|
||||||
|
CircuitManager.RemoveCircuit(CircuitManager.GetCircuit(obj.ID));
|
||||||
|
if (internalCircuits == 0)
|
||||||
|
CreateNewCircuit();
|
||||||
|
else
|
||||||
|
internalCircuits--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void CreateNewCircuit()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lock (CircuitManager)
|
||||||
|
{
|
||||||
|
ControlConnection.CreateCircuit(
|
||||||
|
RouteSelector.CreateNewCircuit().ToString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (TorException)
|
||||||
|
{
|
||||||
|
//fails due to no longer online router
|
||||||
|
CreateNewCircuit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void AddCircuit(EventResponse resp)
|
||||||
|
{
|
||||||
|
String[] parts = resp.EventInformation.Split(' ');
|
||||||
|
String[] routers = parts[2].Split(',');
|
||||||
|
Circuit circ = new Circuit();
|
||||||
|
foreach (String router in routers)
|
||||||
|
circ.AddNextRouter(FindRouter(router));
|
||||||
|
circ.CircuitID = resp.ID;
|
||||||
|
CircuitManager.AddCircuit(circ);
|
||||||
|
}
|
||||||
|
static Router FindRouter(String identifier)
|
||||||
|
{
|
||||||
|
lock (RouterList)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (identifier.StartsWith("$"))
|
||||||
|
return RouterList.First(p => p.Identity.Equals(identifier.Substring(1)));
|
||||||
|
else
|
||||||
|
return RouterList.First(p => p.NickName.Equals(identifier));
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException)
|
||||||
|
{ //Not in router list
|
||||||
|
RouterStatusResponse resp = ControlConnection.GetRouterStatusInfoByNickname(identifier);
|
||||||
|
Router router = new Router(resp);
|
||||||
|
RouterList.Add(GetDescriptions(new [] { router}).First());
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static IEnumerable<Router> GetDescriptions(IEnumerable<Router> routers)
|
||||||
|
{
|
||||||
|
List<Router> descriptedRouters = new List<Router>();
|
||||||
|
foreach (Router router in routers)
|
||||||
|
{
|
||||||
|
if (router.ExitPolicy == null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RouterDescription desc = ControlConnection.GetRouterDescriptionByNickname(String.Format("${0}", router.Identity));
|
||||||
|
router.AddDescription(desc);
|
||||||
|
descriptedRouters.Add(router);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
router.ExitPolicy = new ExitPolicy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
descriptedRouters.Add(router);
|
||||||
|
}
|
||||||
|
return descriptedRouters;
|
||||||
|
}
|
||||||
|
static void ReattachStream(EventResponse resp, IEnumerable<Circuit> exclusionList = null)
|
||||||
|
{
|
||||||
|
if (resp.EventInformation.Contains(".exit"))
|
||||||
|
return;
|
||||||
|
Stream stream = Stream.ParseStream(resp);
|
||||||
|
|
||||||
|
|
||||||
|
if(stream.CircuitID != 0)
|
||||||
|
stream.Circuit = CircuitManager.GetCircuit(stream.CircuitID);
|
||||||
|
|
||||||
|
AttachStream(stream, exclusionList);
|
||||||
|
}
|
||||||
|
static void AttachStream(Stream stream, IEnumerable<Circuit> exclusionList)
|
||||||
|
{
|
||||||
|
Circuit circ = CircuitManager.AssignStreamToCircuit(stream, exclusionList, stream.Destination);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//Actually send request to attach
|
||||||
|
ControlConnection.AttachStream(stream.StreamID, circ.CircuitID);
|
||||||
|
}
|
||||||
|
catch (TorControlLibrary.Exceptions.TorUnknownCircuitException)
|
||||||
|
{ //Circuit is bad
|
||||||
|
CircuitManager.RemoveCircuit(circ);
|
||||||
|
//Try again
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CreateNewCircuit();
|
||||||
|
ControlConnection.CloseCircuit(circ.CircuitID);
|
||||||
|
} //sometimes things get so broke, this fails, resulting in it never attaching a stream again.
|
||||||
|
catch (Exception) { }
|
||||||
|
AttachStream(stream, exclusionList);
|
||||||
|
}
|
||||||
|
catch (TorControlLibrary.Exceptions.TorUnknownStreamException)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (TorControlLibrary.Exceptions.TorOneCircuitException)
|
||||||
|
{
|
||||||
|
//circuit is bad
|
||||||
|
CircuitManager.RemoveCircuit(circ);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CreateNewCircuit();
|
||||||
|
ControlConnection.CloseCircuit(circ.CircuitID);
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
//Try again
|
||||||
|
AttachStream(stream, exclusionList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void DetachStream(EventResponse obj)
|
||||||
|
{
|
||||||
|
string[] parts = obj.EventInformation.Split(' ');
|
||||||
|
Int32 circuitId;
|
||||||
|
if(Int32.TryParse(parts[2],out circuitId) && circuitId != 0)
|
||||||
|
CircuitManager.RemoveStream(circuitId, obj.ID);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
36
Hermes/Properties/AssemblyInfo.cs
Normal file
36
Hermes/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("Hermes")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("Microsoft")]
|
||||||
|
[assembly: AssemblyProduct("Hermes")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("1f2e8ef5-e389-4c81-888b-4c650c3c5108")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
21
Hermes/Selectors/IRouteSelector.cs
Normal file
21
Hermes/Selectors/IRouteSelector.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
using TorControlLibrary;
|
||||||
|
using Hermes.CircuitManagers;
|
||||||
|
|
||||||
|
namespace Hermes.Selectors
|
||||||
|
{
|
||||||
|
public interface IRouteSelector
|
||||||
|
{
|
||||||
|
void Initialize(ControlConnection connection, ICircuitManager circuitManager, Dictionary<String, String> parameters);
|
||||||
|
void Initialize(ControlConnection connection, ICircuitManager circuitManager);
|
||||||
|
void SetEffectiveRouterList(List<Router> routers);
|
||||||
|
Circuit CreateNewCircuit();
|
||||||
|
Circuit CreateNewCircuit(System.Net.IPEndPoint destination);
|
||||||
|
Router FindRouter(String identifier);
|
||||||
|
List<Router> RouterPool { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
44
Hermes/Selectors/RandomTwoRouterCircuits.cs
Normal file
44
Hermes/Selectors/RandomTwoRouterCircuits.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
using TorControlLibrary;
|
||||||
|
using TorControlLibrary.Responses;
|
||||||
|
|
||||||
|
namespace Hermes.Selectors
|
||||||
|
{
|
||||||
|
class RandomTwoRouterCircuits : RouteSelectorBase, IRouteSelector
|
||||||
|
{
|
||||||
|
|
||||||
|
public Circuit CreateNewCircuit()
|
||||||
|
{
|
||||||
|
Circuit circuit = new Circuit();
|
||||||
|
Random rand = new Random();
|
||||||
|
GetPoolReaderLock();
|
||||||
|
{
|
||||||
|
IEnumerable<Router> nonExits = RouterPool.Where(p => !p.Flags.Contains("Exit"));
|
||||||
|
circuit.AddNextRouter(nonExits.ElementAt(rand.Next(nonExits.Count())));
|
||||||
|
IEnumerable<Router> exits = RouterPool.Where(p => p.Flags.Contains("Exit"));
|
||||||
|
circuit.AddNextRouter(exits.ElementAt(rand.Next(exits.Count())));
|
||||||
|
}
|
||||||
|
ReleasePoolReaderLock();
|
||||||
|
return circuit;
|
||||||
|
}
|
||||||
|
public Circuit CreateNewCircuit(System.Net.IPEndPoint destination)
|
||||||
|
{
|
||||||
|
Random rand = new Random();
|
||||||
|
Circuit circuit = new Circuit();
|
||||||
|
GetPoolReaderLock();
|
||||||
|
{
|
||||||
|
IEnumerable<Router> nonExits = RouterPool.Where(p => !p.Flags.Contains("Exit"));
|
||||||
|
circuit.AddNextRouter(nonExits.ElementAt(rand.Next(nonExits.Count())));
|
||||||
|
IEnumerable<Router> exits = RouterPool.Where(p => p.Flags.Contains("Exit") && p.ExitPolicy != null && p.ExitPolicy.IsAcceptableDestination(destination));
|
||||||
|
circuit.AddNextRouter(exits.ElementAt(rand.Next(exits.Count())));
|
||||||
|
}
|
||||||
|
ReleasePoolReaderLock();
|
||||||
|
return circuit;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
123
Hermes/Selectors/RouteSelectorBase.cs
Normal file
123
Hermes/Selectors/RouteSelectorBase.cs
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
using TorControlLibrary.Responses;
|
||||||
|
using TorControlLibrary;
|
||||||
|
using Hermes.CircuitManagers;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Hermes.Selectors
|
||||||
|
{
|
||||||
|
public abstract class RouteSelectorBase
|
||||||
|
{
|
||||||
|
public RouteSelectorBase()
|
||||||
|
{ RouterPool = new List<Router>(); }
|
||||||
|
|
||||||
|
public virtual void Initialize(ControlConnection connection, ICircuitManager circuitManager, Dictionary<string, string> parameters)
|
||||||
|
{
|
||||||
|
Initialize(connection, circuitManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Initialize(ControlConnection connection, ICircuitManager circuitManager)
|
||||||
|
{
|
||||||
|
_controlConnection = connection;
|
||||||
|
_circuitManager = circuitManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void SetEffectiveRouterList(List<Router> routers)
|
||||||
|
{
|
||||||
|
GetPoolWriterLock();
|
||||||
|
{
|
||||||
|
RouterPool = routers;
|
||||||
|
RouterPool.ForEach(p => PopulateRouterDescription(ref p));
|
||||||
|
}
|
||||||
|
ReleasePoolWriterLock();
|
||||||
|
}
|
||||||
|
public virtual Router FindRouter(String identifier)
|
||||||
|
{
|
||||||
|
Router r;
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
GetPoolReaderLock();
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (identifier.Contains("=")) //Contains the Identity hash as well as the nickname $ident=nickname
|
||||||
|
{
|
||||||
|
identifier = identifier.Substring(1, identifier.IndexOf('=') - 1);
|
||||||
|
r = RouterPool.First(p => p.Identity.Equals(identifier));
|
||||||
|
}
|
||||||
|
else if (identifier.Contains("~")) // Contains the identity hash, but also includes the "Unnamed" nickname
|
||||||
|
{
|
||||||
|
identifier = identifier.Substring(1, identifier.IndexOf('~') - 1);
|
||||||
|
r = RouterPool.First(p => p.Identity.Equals(identifier));
|
||||||
|
}
|
||||||
|
else if (identifier.StartsWith("$")) //Just the identity hash
|
||||||
|
{
|
||||||
|
identifier = identifier.Substring(1);
|
||||||
|
r = RouterPool.First(p => p.Identity.Equals(identifier));
|
||||||
|
}
|
||||||
|
else //just the nickname
|
||||||
|
r = RouterPool.First(p => p.NickName.Equals(identifier));
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException)
|
||||||
|
{ //Not in router list
|
||||||
|
//TODO: UpgradeToWriterLock()
|
||||||
|
ReleasePoolReaderLock();
|
||||||
|
GetPoolWriterLock();
|
||||||
|
{
|
||||||
|
RouterStatusResponse resp = _controlConnection.GetRouterStatusInfoByNickname(identifier);
|
||||||
|
Router router = new Router(resp);
|
||||||
|
PopulateRouterDescription(ref router);
|
||||||
|
RouterPool.Add(router);
|
||||||
|
r = router;
|
||||||
|
}
|
||||||
|
ReleasePoolWriterLock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ReleasePoolReaderLock();
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
protected virtual void PopulateRouterDescription(ref Router router)
|
||||||
|
{
|
||||||
|
//If the Exit Policy is populated, then the router already has been described
|
||||||
|
if (router.ExitPolicy == null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RouterDescription desc = _controlConnection.GetRouterDescriptionByNickname(String.Format("${0}", router.Identity));
|
||||||
|
router.AddDescription(desc);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
router.ExitPolicy = new ExitPolicy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected void GetPoolReaderLock()
|
||||||
|
{
|
||||||
|
_routerPoolLock.TryEnterReadLock(5000);
|
||||||
|
}
|
||||||
|
protected void GetPoolWriterLock()
|
||||||
|
{
|
||||||
|
_routerPoolLock.TryEnterWriteLock(6000);
|
||||||
|
}
|
||||||
|
protected void ReleasePoolReaderLock()
|
||||||
|
{
|
||||||
|
if(_routerPoolLock.IsReadLockHeld)
|
||||||
|
_routerPoolLock.ExitReadLock();
|
||||||
|
}
|
||||||
|
protected void ReleasePoolWriterLock()
|
||||||
|
{
|
||||||
|
if(_routerPoolLock.IsWriteLockHeld)
|
||||||
|
_routerPoolLock.ExitWriteLock();
|
||||||
|
}
|
||||||
|
public List<Router> RouterPool { get; set; }
|
||||||
|
protected ControlConnection _controlConnection;
|
||||||
|
protected ICircuitManager _circuitManager;
|
||||||
|
private ReaderWriterLockSlim _routerPoolLock = new ReaderWriterLockSlim();
|
||||||
|
}
|
||||||
|
}
|
||||||
57
Hermes/Selectors/UniqueHighestSpeedSingleRouterSelector.cs
Normal file
57
Hermes/Selectors/UniqueHighestSpeedSingleRouterSelector.cs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
|
||||||
|
namespace Hermes.Selectors
|
||||||
|
{
|
||||||
|
public class UniqueHighestSpeedSingleRouterSelector : UniqueRouteSelector, IRouteSelector
|
||||||
|
{
|
||||||
|
#region IRouteSelector Members
|
||||||
|
|
||||||
|
public Circuit CreateNewCircuit()
|
||||||
|
{
|
||||||
|
Circuit circuit = new Circuit();
|
||||||
|
GetPoolReaderLock();
|
||||||
|
{
|
||||||
|
lock (UsedRouters)
|
||||||
|
{
|
||||||
|
IEnumerable<Router> exits = RouterPool.Where(p => p.Flags.Contains("Exit") && !UsedRouters.Contains(p));
|
||||||
|
if (exits.Count() == 0)
|
||||||
|
exits = RouterPool.Where(p => p.Flags.Contains("Exit"));
|
||||||
|
|
||||||
|
circuit.AddNextRouter(exits.OrderByDescending(p => p.BandwidthObserved).First());
|
||||||
|
UsedRouters.AddRange(circuit.Routers.Values.ToList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ReleasePoolReaderLock();
|
||||||
|
return circuit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Circuit CreateNewCircuit(System.Net.IPEndPoint destination)
|
||||||
|
{
|
||||||
|
Circuit circuit = new Circuit();
|
||||||
|
GetPoolReaderLock();
|
||||||
|
{
|
||||||
|
lock (UsedRouters)
|
||||||
|
{
|
||||||
|
IEnumerable<Router> exits = RouterPool.Where(p => p.Flags.Contains("Exit") && p.ExitPolicy != null && p.ExitPolicy.IsAcceptableDestination(destination) && !UsedRouters.Contains(p));
|
||||||
|
if (exits.Count() == 0)
|
||||||
|
{
|
||||||
|
exits = RouterPool.Where(p => p.Flags.Contains("Exit") && p.ExitPolicy != null && p.ExitPolicy.IsAcceptableDestination(destination));
|
||||||
|
circuit.AddNextRouter(exits.OrderByDescending(p => p.BandwidthObserved).First());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
circuit.AddNextRouter(exits.OrderByDescending(p => p.BandwidthObserved).First());
|
||||||
|
|
||||||
|
UsedRouters.AddRange(circuit.Routers.Values.ToList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ReleasePoolReaderLock();
|
||||||
|
return circuit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
44
Hermes/Selectors/UniqueRouteSelector.cs
Normal file
44
Hermes/Selectors/UniqueRouteSelector.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
using Hermes.CircuitManagers;
|
||||||
|
|
||||||
|
namespace Hermes.Selectors
|
||||||
|
{
|
||||||
|
public abstract class UniqueRouteSelector : RouteSelectorBase
|
||||||
|
{
|
||||||
|
protected List<Router> UsedRouters;
|
||||||
|
public UniqueRouteSelector()
|
||||||
|
{
|
||||||
|
UsedRouters = new List<Router>();
|
||||||
|
}
|
||||||
|
public override void Initialize(TorControlLibrary.ControlConnection connection, ICircuitManager circuitManager)
|
||||||
|
{
|
||||||
|
connection.ServerEvent += new Action<TorControlLibrary.Responses.EventResponse>(connection_ServerEvent);
|
||||||
|
base.Initialize(connection, circuitManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
void connection_ServerEvent(TorControlLibrary
|
||||||
|
.Responses.EventResponse obj)
|
||||||
|
{
|
||||||
|
if(obj.EventType == "CIRC")
|
||||||
|
switch (obj.Action)
|
||||||
|
{
|
||||||
|
case "CLOSED":
|
||||||
|
case "FAILED":
|
||||||
|
lock(UsedRouters)
|
||||||
|
{
|
||||||
|
Circuit circ = _circuitManager.GetCircuit(obj.ID);
|
||||||
|
if (circ != null)
|
||||||
|
{
|
||||||
|
foreach (Router r in circ.Routers.Values)
|
||||||
|
UsedRouters.Remove(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Hermes.Objects;
|
||||||
|
|
||||||
|
namespace Hermes.Selectors
|
||||||
|
{
|
||||||
|
class UniqueHighestSpeedTwoNodeSelector : UniqueRouteSelector, IRouteSelector
|
||||||
|
{
|
||||||
|
public UniqueHighestSpeedTwoNodeSelector()
|
||||||
|
: base()
|
||||||
|
{}
|
||||||
|
|
||||||
|
#region IRouteSelector Members
|
||||||
|
|
||||||
|
public Circuit CreateNewCircuit()
|
||||||
|
{
|
||||||
|
Random rand = new Random();
|
||||||
|
Circuit circuit = new Circuit();
|
||||||
|
GetPoolReaderLock();
|
||||||
|
{
|
||||||
|
lock (UsedRouters)
|
||||||
|
{
|
||||||
|
//Try to use unused routers
|
||||||
|
IEnumerable<Router> nonExits = RouterPool.Where(p => !p.Flags.Contains("Exit") && !UsedRouters.Contains(p));
|
||||||
|
if (nonExits.Count() == 0)
|
||||||
|
{
|
||||||
|
nonExits = RouterPool.Where(p => !p.Flags.Contains("Exit"));
|
||||||
|
circuit.AddNextRouter(nonExits.ElementAt(rand.Next(nonExits.Count())));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
circuit.AddNextRouter(nonExits.OrderByDescending(p => p.BandwidthObserved).First());
|
||||||
|
|
||||||
|
IEnumerable<Router> exits = RouterPool.Where(p => p.Flags.Contains("Exit") && !UsedRouters.Contains(p));
|
||||||
|
if (exits.Count() == 0)
|
||||||
|
{
|
||||||
|
exits = RouterPool.Where(p => p.Flags.Contains("Exit"));
|
||||||
|
circuit.AddNextRouter(exits.ElementAt(rand.Next(exits.Count())));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
circuit.AddNextRouter(exits.OrderByDescending(p => p.BandwidthObserved).First());
|
||||||
|
|
||||||
|
UsedRouters.AddRange(circuit.Routers.Values.ToList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ReleasePoolReaderLock();
|
||||||
|
return circuit;
|
||||||
|
}
|
||||||
|
public Circuit CreateNewCircuit(System.Net.IPEndPoint destination)
|
||||||
|
{
|
||||||
|
Random rand = new Random();
|
||||||
|
Circuit circuit = new Circuit();
|
||||||
|
|
||||||
|
GetPoolReaderLock();
|
||||||
|
{
|
||||||
|
lock (UsedRouters)
|
||||||
|
{
|
||||||
|
//Try to use unused routers
|
||||||
|
IEnumerable<Router> nonExits = RouterPool.Where(p => !p.Flags.Contains("Exit") && !UsedRouters.Contains(p));
|
||||||
|
if (nonExits.Count() == 0)
|
||||||
|
{
|
||||||
|
nonExits = RouterPool.Where(p => !p.Flags.Contains("Exit"));
|
||||||
|
circuit.AddNextRouter(nonExits.ElementAt(rand.Next(nonExits.Count())));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
circuit.AddNextRouter(nonExits.OrderByDescending(p => p.BandwidthObserved).First());
|
||||||
|
|
||||||
|
IEnumerable<Router> exits = RouterPool.Where(p => p.Flags.Contains("Exit") && p.ExitPolicy != null && p.ExitPolicy.IsAcceptableDestination(destination) && !UsedRouters.Contains(p));
|
||||||
|
if (exits.Count() == 0)
|
||||||
|
{
|
||||||
|
exits = RouterPool.Where(p => p.Flags.Contains("Exit") && p.ExitPolicy != null && p.ExitPolicy.IsAcceptableDestination(destination));
|
||||||
|
circuit.AddNextRouter(exits.ElementAt(rand.Next(exits.Count())));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
circuit.AddNextRouter(exits.OrderByDescending(p => p.BandwidthObserved).First());
|
||||||
|
|
||||||
|
UsedRouters.AddRange(circuit.Routers.Values.ToList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ReleasePoolReaderLock();
|
||||||
|
return circuit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
10
Local.testsettings
Normal file
10
Local.testsettings
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<TestSettings name="Local" id="4d78ee4f-c4de-418f-ab28-25d07aafbb05" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
|
||||||
|
<Description>These are default test settings for a local test run.</Description>
|
||||||
|
<Deployment enabled="false" />
|
||||||
|
<Execution>
|
||||||
|
<TestTypeSpecific />
|
||||||
|
<AgentRule name="Execution Agents">
|
||||||
|
</AgentRule>
|
||||||
|
</Execution>
|
||||||
|
</TestSettings>
|
||||||
80
Tor.sln
Normal file
80
Tor.sln
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||||
|
# Visual Studio 2010
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TorControlLibrary", "TorControlLibrary\TorControlLibrary.csproj", "{EF216A86-F64F-4C76-9A86-EEE8E5484EF9}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TorLibraryTest", "TorLibraryTest\TorLibraryTest.csproj", "{020A074C-B1F5-498A-8C1D-B1D90C79D50D}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{312F224D-6CC1-480A-971F-A485FEA8C867}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
Local.testsettings = Local.testsettings
|
||||||
|
Tor.vsmdi = Tor.vsmdi
|
||||||
|
TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hermes", "Hermes\Hermes.csproj", "{3DE6415A-1DED-4F75-9202-39BDF012BB5A}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CircuitLoadTest", "CircuitLoadTest\CircuitLoadTest.csproj", "{124BEFA2-D0CB-4D6D-AD53-166DE405CC60}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(TestCaseManagementSettings) = postSolution
|
||||||
|
CategoryFile = Tor.vsmdi
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|Mixed Platforms = Debug|Mixed Platforms
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|Mixed Platforms = Release|Mixed Platforms
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{EF216A86-F64F-4C76-9A86-EEE8E5484EF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EF216A86-F64F-4C76-9A86-EEE8E5484EF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{EF216A86-F64F-4C76-9A86-EEE8E5484EF9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{EF216A86-F64F-4C76-9A86-EEE8E5484EF9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{EF216A86-F64F-4C76-9A86-EEE8E5484EF9}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{EF216A86-F64F-4C76-9A86-EEE8E5484EF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{EF216A86-F64F-4C76-9A86-EEE8E5484EF9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{EF216A86-F64F-4C76-9A86-EEE8E5484EF9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{EF216A86-F64F-4C76-9A86-EEE8E5484EF9}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{EF216A86-F64F-4C76-9A86-EEE8E5484EF9}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{020A074C-B1F5-498A-8C1D-B1D90C79D50D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{020A074C-B1F5-498A-8C1D-B1D90C79D50D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{020A074C-B1F5-498A-8C1D-B1D90C79D50D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{020A074C-B1F5-498A-8C1D-B1D90C79D50D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{020A074C-B1F5-498A-8C1D-B1D90C79D50D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{020A074C-B1F5-498A-8C1D-B1D90C79D50D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{020A074C-B1F5-498A-8C1D-B1D90C79D50D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{020A074C-B1F5-498A-8C1D-B1D90C79D50D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{020A074C-B1F5-498A-8C1D-B1D90C79D50D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{020A074C-B1F5-498A-8C1D-B1D90C79D50D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{3DE6415A-1DED-4F75-9202-39BDF012BB5A}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||||
|
{3DE6415A-1DED-4F75-9202-39BDF012BB5A}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
|
||||||
|
{3DE6415A-1DED-4F75-9202-39BDF012BB5A}.Debug|Mixed Platforms.Build.0 = Debug|x86
|
||||||
|
{3DE6415A-1DED-4F75-9202-39BDF012BB5A}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{3DE6415A-1DED-4F75-9202-39BDF012BB5A}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{3DE6415A-1DED-4F75-9202-39BDF012BB5A}.Release|Any CPU.ActiveCfg = Release|x86
|
||||||
|
{3DE6415A-1DED-4F75-9202-39BDF012BB5A}.Release|Mixed Platforms.ActiveCfg = Release|x86
|
||||||
|
{3DE6415A-1DED-4F75-9202-39BDF012BB5A}.Release|Mixed Platforms.Build.0 = Release|x86
|
||||||
|
{3DE6415A-1DED-4F75-9202-39BDF012BB5A}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{3DE6415A-1DED-4F75-9202-39BDF012BB5A}.Release|x86.Build.0 = Release|x86
|
||||||
|
{124BEFA2-D0CB-4D6D-AD53-166DE405CC60}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||||
|
{124BEFA2-D0CB-4D6D-AD53-166DE405CC60}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
|
||||||
|
{124BEFA2-D0CB-4D6D-AD53-166DE405CC60}.Debug|Mixed Platforms.Build.0 = Debug|x86
|
||||||
|
{124BEFA2-D0CB-4D6D-AD53-166DE405CC60}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{124BEFA2-D0CB-4D6D-AD53-166DE405CC60}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{124BEFA2-D0CB-4D6D-AD53-166DE405CC60}.Release|Any CPU.ActiveCfg = Release|x86
|
||||||
|
{124BEFA2-D0CB-4D6D-AD53-166DE405CC60}.Release|Mixed Platforms.ActiveCfg = Release|x86
|
||||||
|
{124BEFA2-D0CB-4D6D-AD53-166DE405CC60}.Release|Mixed Platforms.Build.0 = Release|x86
|
||||||
|
{124BEFA2-D0CB-4D6D-AD53-166DE405CC60}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{124BEFA2-D0CB-4D6D-AD53-166DE405CC60}.Release|x86.Build.0 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SubversionScc) = preSolution
|
||||||
|
Svn-Managed = True
|
||||||
|
Manager = AnkhSVN - Subversion Support for Visual Studio
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
6
Tor.vsmdi
Normal file
6
Tor.vsmdi
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<TestLists xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
|
||||||
|
<TestList name="Lists of Tests" id="8c43106b-9dc1-4907-a29f-aa66a61bf5b6">
|
||||||
|
<RunConfiguration id="4d78ee4f-c4de-418f-ab28-25d07aafbb05" name="Local" storage="local.testsettings" type="Microsoft.VisualStudio.TestTools.Common.TestRunConfiguration, Microsoft.VisualStudio.QualityTools.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||||
|
</TestList>
|
||||||
|
</TestLists>
|
||||||
382
TorControlLibrary/ControlConnection.cs
Normal file
382
TorControlLibrary/ControlConnection.cs
Normal file
@@ -0,0 +1,382 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Net;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Threading;
|
||||||
|
using TorControlLibrary.Responses;
|
||||||
|
using TorControlLibrary.Exceptions;
|
||||||
|
|
||||||
|
namespace TorControlLibrary
|
||||||
|
{
|
||||||
|
public class ControlConnection
|
||||||
|
{
|
||||||
|
public ControlConnection()
|
||||||
|
{
|
||||||
|
Host = new IPEndPoint(IPAddress.Loopback, 9051);
|
||||||
|
Timeout = new TimeSpan(0, 0, 90);
|
||||||
|
HashedControlPassword = String.Empty;
|
||||||
|
}
|
||||||
|
public void Connect(IPEndPoint host)
|
||||||
|
{
|
||||||
|
Host = host;
|
||||||
|
Connect();
|
||||||
|
}
|
||||||
|
public void Connect(String authenticationPassword)
|
||||||
|
{
|
||||||
|
HashedControlPassword = authenticationPassword;
|
||||||
|
Connect();
|
||||||
|
}
|
||||||
|
public void Connect(IPEndPoint host, String hashedControlPassword)
|
||||||
|
{
|
||||||
|
Host = host;
|
||||||
|
HashedControlPassword = hashedControlPassword;
|
||||||
|
Connect();
|
||||||
|
}
|
||||||
|
public void Connect()
|
||||||
|
{
|
||||||
|
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||||
|
sock.Connect(Host);
|
||||||
|
socketStream = new NetworkStream(sock);
|
||||||
|
socketReader = new StreamReader(socketStream);
|
||||||
|
socketWriter = new StreamWriter(socketStream);
|
||||||
|
socketWriter.AutoFlush = true;
|
||||||
|
|
||||||
|
recvThread = new Thread(new ParameterizedThreadStart(receiveLoop));
|
||||||
|
recvThread.IsBackground = true;
|
||||||
|
recvThread.Name = "Tor Control Library Receive Loop";
|
||||||
|
recvThread.Start();
|
||||||
|
|
||||||
|
Authenticate();
|
||||||
|
}
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
sock.Close();
|
||||||
|
}
|
||||||
|
protected void Authenticate()
|
||||||
|
{
|
||||||
|
CommandResponse resp = SendCommand(String.Format("AUTHENTICATE \"{0}\"",HashedControlPassword));
|
||||||
|
if (resp.StatusCode != 250)
|
||||||
|
throw new TorAuthenticationException() { ErrorDescription = "There was a problem authenticating with the Tor control port.", HashedPassword = _hashedControlPassword, ServerResponse = resp.Response, StatusCode = resp.StatusCode };
|
||||||
|
}
|
||||||
|
public List<CircuitStatusResponse> GetCircuitStatuses()
|
||||||
|
{
|
||||||
|
List<CircuitStatusResponse> circuitResponses = new List<CircuitStatusResponse>();
|
||||||
|
CommandResponse resp = SendCommand("GETINFO circuit-status");
|
||||||
|
StringReader sr = new StringReader(resp.Response);
|
||||||
|
String line = sr.ReadLine();
|
||||||
|
if (!line.Contains("circuit-status"))
|
||||||
|
throw TorException.Parse(resp.Response);
|
||||||
|
if (line[3] == '+' || line.EndsWith("="))
|
||||||
|
line = sr.ReadLine();
|
||||||
|
while (line != null)
|
||||||
|
{
|
||||||
|
if (line.Equals(".") || line.Equals("250 OK"))
|
||||||
|
break;
|
||||||
|
if (line.Contains("circuit-status"))
|
||||||
|
line = line.Substring(line.IndexOf('=') + 1);
|
||||||
|
circuitResponses.Add(CircuitStatusResponse.Parse(line));
|
||||||
|
line = sr.ReadLine();
|
||||||
|
}
|
||||||
|
return circuitResponses;
|
||||||
|
}
|
||||||
|
public List<StreamStatusResponse> GetStreamStatuses()
|
||||||
|
{
|
||||||
|
List<StreamStatusResponse> streamResponses = new List<StreamStatusResponse>();
|
||||||
|
CommandResponse resp = SendCommand("GETINFO stream-status");
|
||||||
|
StringReader sr = new StringReader(resp.Response);
|
||||||
|
String line = sr.ReadLine();
|
||||||
|
if (!line.Contains("stream-status"))
|
||||||
|
throw TorException.Parse(resp.Response);
|
||||||
|
if (line[3] == '+' || line.EndsWith("="))
|
||||||
|
line = sr.ReadLine();
|
||||||
|
while (line != null)
|
||||||
|
{
|
||||||
|
if (line.Equals(".") || line.Equals("250 OK"))
|
||||||
|
break;
|
||||||
|
if (line.Contains("stream-status"))
|
||||||
|
line = line.Substring(line.IndexOf('=') + 1);
|
||||||
|
streamResponses.Add(StreamStatusResponse.Parse(line));
|
||||||
|
line = sr.ReadLine();
|
||||||
|
}
|
||||||
|
return streamResponses;
|
||||||
|
}
|
||||||
|
public List<RouterStatusResponse> GetAllRouterStatusInfo()
|
||||||
|
{
|
||||||
|
List<RouterStatusResponse> routerResponses = new List<RouterStatusResponse>();
|
||||||
|
CommandResponse resp = SendCommand("GETINFO ns/all");
|
||||||
|
StringReader sr = new StringReader(resp.Response);
|
||||||
|
String line = sr.ReadLine(), routerLine = String.Empty, flagLine = String.Empty;
|
||||||
|
if (!line.Contains("ns/all"))
|
||||||
|
throw TorException.Parse(resp.Response);
|
||||||
|
|
||||||
|
while (line != null)
|
||||||
|
{
|
||||||
|
line = sr.ReadLine();
|
||||||
|
if (line.Equals("."))
|
||||||
|
break;
|
||||||
|
switch (line.Substring(0, 1))
|
||||||
|
{
|
||||||
|
case "r":
|
||||||
|
routerLine = line;
|
||||||
|
continue;
|
||||||
|
case "s":
|
||||||
|
flagLine = line;
|
||||||
|
routerResponses.Add(RouterStatusResponse.Parse(routerLine, flagLine));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//I'm not currently parsing "w" or "p" lines. p doesn't describe a complete exit policy, and "w" doesn't describe all the available bandwidth metrics. That's retrieved via GETINFO desc
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
sr.Close();
|
||||||
|
return routerResponses;
|
||||||
|
}
|
||||||
|
public RouterStatusResponse GetRouterStatusInfoByNickname(String nickname)
|
||||||
|
{
|
||||||
|
RouterStatusResponse response = null;
|
||||||
|
CommandResponse resp = SendCommand(String.Format("GETINFO ns/name/{0}", nickname));
|
||||||
|
StringReader sr = new StringReader(resp.Response);
|
||||||
|
String line = sr.ReadLine(), routerLine = String.Empty, flagLine = String.Empty;
|
||||||
|
if (!line.Contains("ns/name"))
|
||||||
|
throw TorException.Parse(resp.Response);
|
||||||
|
|
||||||
|
while (line != null)
|
||||||
|
{
|
||||||
|
line = sr.ReadLine();
|
||||||
|
if (line == null || line.Equals("."))
|
||||||
|
break;
|
||||||
|
switch (line.Substring(0, 1))
|
||||||
|
{
|
||||||
|
case "r":
|
||||||
|
routerLine = line;
|
||||||
|
continue;
|
||||||
|
case "s":
|
||||||
|
flagLine = line;
|
||||||
|
response = RouterStatusResponse.Parse(routerLine, flagLine);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//I'm not currently parsing "w" or "p" lines. p doesn't describe a complete exit policy, and "w" doesn't describe all the available bandwidth metrics. That's retrieved via GETINFO desc
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
sr.Close();
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
public RouterDescription GetRouterDescriptionByNickname(String nickname)
|
||||||
|
{
|
||||||
|
RouterDescription routerDescription = new RouterDescription(nickname);
|
||||||
|
|
||||||
|
CommandResponse resp = SendCommand(String.Format("GETINFO desc/name/{0}", nickname));
|
||||||
|
if (resp.StatusCode != 250)
|
||||||
|
throw TorException.Parse(resp.Response);
|
||||||
|
using (StringReader reader = new StringReader(resp.Response))
|
||||||
|
{
|
||||||
|
string line;
|
||||||
|
String policy = String.Empty;
|
||||||
|
while ((line = reader.ReadLine()) != null)
|
||||||
|
{
|
||||||
|
if (!line.Contains(' ')) continue;
|
||||||
|
Int32 firstSpace = line.IndexOf(' ');
|
||||||
|
string key = line.Substring(0, firstSpace).Trim();
|
||||||
|
string value = line.Substring(firstSpace, line.Length - firstSpace).Trim();
|
||||||
|
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case "uptime":
|
||||||
|
routerDescription.Uptime = new TimeSpan(0, 0, Int32.Parse(value));
|
||||||
|
break;
|
||||||
|
case "bandwidth":
|
||||||
|
String[] values = value.Split(' ');
|
||||||
|
routerDescription.BandwidthAverage = Int32.Parse(values[0]);
|
||||||
|
routerDescription.BandwidthBurst = Int32.Parse(values[1]);
|
||||||
|
routerDescription.BandwidthObserved = Int32.Parse(values[2]);
|
||||||
|
break;
|
||||||
|
case "reject":
|
||||||
|
case "accept":
|
||||||
|
policy += line + Environment.NewLine;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
routerDescription.ExitPolicy = new ExitPolicy(policy);
|
||||||
|
}
|
||||||
|
return routerDescription;
|
||||||
|
}
|
||||||
|
public RouterStatusResponse GetRouterStatusInfoByID(String identity)
|
||||||
|
{
|
||||||
|
CommandResponse resp = SendCommand(String.Format("GETINFO ns/id/{0}", identity));
|
||||||
|
StringReader sr = new StringReader(resp.Response);
|
||||||
|
String line = sr.ReadLine();
|
||||||
|
if (!line.Contains("ns/id"))
|
||||||
|
throw TorException.Parse(resp.Response);
|
||||||
|
|
||||||
|
line = sr.ReadLine();
|
||||||
|
String flagLine = sr.ReadLine();
|
||||||
|
RouterStatusResponse routerResponse = RouterStatusResponse.Parse(line, flagLine);
|
||||||
|
sr.Close();
|
||||||
|
return routerResponse;
|
||||||
|
}
|
||||||
|
public void SetConfigurationEntry(String key, String value)
|
||||||
|
{
|
||||||
|
SendCommand(String.Format("SETCONF {0}={1}",key,value));
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Starts the process of creating a new circuit
|
||||||
|
/// NOTE: The circuit is not usable until the BUILT event occurs
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="circuit">The new circuit ID</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Int32 CreateCircuit(String circuit)
|
||||||
|
{
|
||||||
|
CommandResponse resp = SendCommand(String.Format("EXTENDCIRCUIT 0 {0}", circuit));
|
||||||
|
if (resp.StatusCode == 250)
|
||||||
|
{
|
||||||
|
string[] parts = resp.Response.Split(' ');
|
||||||
|
Int32 circuitID;
|
||||||
|
if(Int32.TryParse(parts[parts.Length - 1],out circuitID))
|
||||||
|
return circuitID;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
public void AttachStream(Int32 streamId, Int32 circuitId)
|
||||||
|
{
|
||||||
|
SendCommand(String.Format("ATTACHSTREAM {0} {1}", streamId, circuitId));
|
||||||
|
}
|
||||||
|
public void CloseCircuit(Int32 circuitID)
|
||||||
|
{
|
||||||
|
SendCommand(String.Format("CLOSECIRCUIT {0}", circuitID));
|
||||||
|
}
|
||||||
|
public void CloseStream(Int32 streamID)
|
||||||
|
{
|
||||||
|
SendCommand(String.Format("CLOSESTREAM {0} 1", streamID));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandResponse SendRawCommand(String command)
|
||||||
|
{
|
||||||
|
return SendCommand(command);
|
||||||
|
}
|
||||||
|
public void RequestEvents(List<String> events)
|
||||||
|
{
|
||||||
|
SendRawCommand(String.Format("SETEVENTS {0}", String.Join(" ", events)));
|
||||||
|
}
|
||||||
|
private CommandResponse SendCommand(String command)
|
||||||
|
{
|
||||||
|
CommandResponse resp;
|
||||||
|
lock (requestLock)
|
||||||
|
{
|
||||||
|
socketWriter.WriteLine(command);
|
||||||
|
resp = GetLastCommandResponse();
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
private CommandResponse GetLastCommandResponse()
|
||||||
|
{
|
||||||
|
if (responseEvent.WaitOne(Timeout))
|
||||||
|
{
|
||||||
|
CommandResponse resp = responseQueue.Dequeue();
|
||||||
|
if (!resp.StatusCode.ToString().StartsWith("2"))
|
||||||
|
throw TorException.Parse(resp.Response);
|
||||||
|
else return resp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new TimeoutException();
|
||||||
|
}
|
||||||
|
private void receiveLoop(object param)
|
||||||
|
{
|
||||||
|
String line;
|
||||||
|
while (sock.Connected)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
line = socketReader.ReadLine();
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
if (e.InnerException is SocketException &&
|
||||||
|
((SocketException)e.InnerException).SocketErrorCode == SocketError.ConnectionAborted)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
throw new ApplicationException();
|
||||||
|
}
|
||||||
|
if (line == null)
|
||||||
|
break;
|
||||||
|
if (line.Equals("") || line.Length < 5)
|
||||||
|
continue;
|
||||||
|
switch (line.Substring(0, 3))
|
||||||
|
{
|
||||||
|
//Command response
|
||||||
|
case "250":
|
||||||
|
case "246":
|
||||||
|
case "249":
|
||||||
|
CommandResponse resp = new CommandResponse(Int32.Parse(line.Substring(0,3)),line);
|
||||||
|
|
||||||
|
while (!line.Equals("250 OK") && !line.StartsWith("250 "))
|
||||||
|
{
|
||||||
|
line = socketReader.ReadLine();
|
||||||
|
resp.AppendResponse(line);
|
||||||
|
}
|
||||||
|
responseQueue.Enqueue(resp);
|
||||||
|
responseEvent.Set();
|
||||||
|
break;
|
||||||
|
//server-generated events
|
||||||
|
case "650":
|
||||||
|
EventResponse eventResp = EventResponse.Parse(line);
|
||||||
|
if(ServerEvent != null)
|
||||||
|
foreach (Action<EventResponse> serverEventResponse in ServerEvent.GetInvocationList())
|
||||||
|
{
|
||||||
|
serverEventResponse.BeginInvoke(eventResp, null, null);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (line.StartsWith("5"))
|
||||||
|
{
|
||||||
|
responseQueue.Enqueue(new ErrorResponse(Int32.Parse(line.Substring(0, 3)), line));
|
||||||
|
responseEvent.Set();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new ApplicationException();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPEndPoint Host { get; set; }
|
||||||
|
public TimeSpan Timeout { get; set; }
|
||||||
|
public event Action<EventResponse> ServerEvent;
|
||||||
|
public Boolean Connected
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return sock.Connected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public String HashedControlPassword
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _hashedControlPassword;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!String.IsNullOrEmpty(value) && !value.StartsWith("16:"))
|
||||||
|
throw new TorException() { ErrorDescription = "You must pass the already hashed version of the tor control port's password. You can obtain this by running the following command: tor.exe --hash-password mypass" };
|
||||||
|
_hashedControlPassword = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String _hashedControlPassword;
|
||||||
|
private StreamReader socketReader;
|
||||||
|
private StreamWriter socketWriter;
|
||||||
|
private NetworkStream socketStream;
|
||||||
|
private Socket sock;
|
||||||
|
private Thread recvThread;
|
||||||
|
private readonly object requestLock = new object();
|
||||||
|
private AutoResetEvent responseEvent = new AutoResetEvent(false);
|
||||||
|
private Queue<CommandResponse> responseQueue = new Queue<CommandResponse>();
|
||||||
|
}
|
||||||
|
}
|
||||||
13
TorControlLibrary/Exceptions/TorAuthenticationException.cs
Normal file
13
TorControlLibrary/Exceptions/TorAuthenticationException.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TorControlLibrary.Exceptions
|
||||||
|
{
|
||||||
|
public class TorAuthenticationException : TorException
|
||||||
|
{
|
||||||
|
public String HashedPassword { get; set; }
|
||||||
|
public String ServerResponse { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
48
TorControlLibrary/Exceptions/TorException.cs
Normal file
48
TorControlLibrary/Exceptions/TorException.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TorControlLibrary.Exceptions
|
||||||
|
{
|
||||||
|
public class TorException : System.Exception
|
||||||
|
{
|
||||||
|
public static TorException Parse(String errorLine)
|
||||||
|
{
|
||||||
|
TorException ex = null;
|
||||||
|
switch (errorLine.Substring(0, 3))
|
||||||
|
{
|
||||||
|
case "552":
|
||||||
|
if (errorLine.Contains("Unknown stream"))
|
||||||
|
ex = new TorUnknownStreamException()
|
||||||
|
{
|
||||||
|
StreamID = Int32.Parse(errorLine.Substring(errorLine.IndexOf('"') + 1, errorLine.Length - (errorLine.LastIndexOf('"') + 1)))
|
||||||
|
};
|
||||||
|
else if (errorLine.Contains("Unknown circuit"))
|
||||||
|
ex = new TorUnknownCircuitException()
|
||||||
|
{
|
||||||
|
CircuitID = Int32.Parse(errorLine.Substring(errorLine.IndexOf('"') + 1, errorLine.Length - (errorLine.LastIndexOf('"') + 1)))
|
||||||
|
};
|
||||||
|
else
|
||||||
|
ex = new TorException();
|
||||||
|
break;
|
||||||
|
case "551":
|
||||||
|
if (errorLine.Contains("one-hop circuit"))
|
||||||
|
{
|
||||||
|
ex = new TorOneCircuitException();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "515":
|
||||||
|
ex = new TorAuthenticationException();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ApplicationException("Unhandled exception from TOR control port");
|
||||||
|
}
|
||||||
|
ex.ErrorDescription = errorLine.Substring(4);
|
||||||
|
ex.StatusCode = Int32.Parse(errorLine.Substring(0, 3));
|
||||||
|
return ex;
|
||||||
|
}
|
||||||
|
public Int32 StatusCode { get; set; }
|
||||||
|
public String ErrorDescription { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
11
TorControlLibrary/Exceptions/TorOneCircuitException.cs
Normal file
11
TorControlLibrary/Exceptions/TorOneCircuitException.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TorControlLibrary.Exceptions
|
||||||
|
{
|
||||||
|
public class TorOneCircuitException : TorException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
12
TorControlLibrary/Exceptions/TorUnknownCircuitException.cs
Normal file
12
TorControlLibrary/Exceptions/TorUnknownCircuitException.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TorControlLibrary.Exceptions
|
||||||
|
{
|
||||||
|
public class TorUnknownCircuitException : TorException
|
||||||
|
{
|
||||||
|
public Int32 CircuitID { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
12
TorControlLibrary/Exceptions/TorUnknownStreamException.cs
Normal file
12
TorControlLibrary/Exceptions/TorUnknownStreamException.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TorControlLibrary.Exceptions
|
||||||
|
{
|
||||||
|
public class TorUnknownStreamException : TorException
|
||||||
|
{
|
||||||
|
public Int32 StreamID { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
118
TorControlLibrary/ExitPolicy.cs
Normal file
118
TorControlLibrary/ExitPolicy.cs
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace TorControlLibrary
|
||||||
|
{
|
||||||
|
public class ExitPolicy
|
||||||
|
{
|
||||||
|
public ExitPolicy() { }
|
||||||
|
public ExitPolicy(String policy)
|
||||||
|
{
|
||||||
|
ParsePolicy(policy);
|
||||||
|
}
|
||||||
|
public void ParsePolicy(String policy)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
StringReader sr = new StringReader(policy);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
String line = sr.ReadLine();
|
||||||
|
if (String.IsNullOrEmpty(line))
|
||||||
|
break;
|
||||||
|
Policy.Add(count++, new PolicyLine(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Boolean IsAcceptableDestination(IPEndPoint destination)
|
||||||
|
{
|
||||||
|
return checkAddress((UInt32)System.Net.IPAddress.HostToNetworkOrder(BitConverter.ToInt32(destination.Address.GetAddressBytes(), 0)), (UInt16)destination.Port);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean IsAcceptableDestination(IPAddress address, UInt16 port)
|
||||||
|
{
|
||||||
|
return checkAddress((UInt32)System.Net.IPAddress.HostToNetworkOrder(BitConverter.ToInt32(address.GetAddressBytes(), 0)), port);
|
||||||
|
}
|
||||||
|
private Boolean checkAddress(UInt32 address, UInt16 port)
|
||||||
|
{
|
||||||
|
//the first match dictates the appropriate action
|
||||||
|
for (int i = 0; i < Policy.Count; i++)
|
||||||
|
{
|
||||||
|
if (Policy[i].AddressRangeStart <= address &&
|
||||||
|
Policy[i].AddressRangeEnd >= address)
|
||||||
|
if (Policy[i].PortRangeStart <= port &&
|
||||||
|
Policy[i].PortRangeEnd >= port)
|
||||||
|
return Policy[i].Action.Equals("accept");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
private SortedList<Int32, PolicyLine> Policy = new SortedList<int,PolicyLine>();
|
||||||
|
|
||||||
|
class PolicyLine
|
||||||
|
{
|
||||||
|
public PolicyLine(String line)
|
||||||
|
{
|
||||||
|
Int32 ptr = line.IndexOf(' ');
|
||||||
|
Action = line.Substring(0, ptr);
|
||||||
|
ptr++;
|
||||||
|
//Address
|
||||||
|
String address = line.Substring(ptr, line.IndexOf(':') - ptr);
|
||||||
|
if (address.Equals("*"))
|
||||||
|
{
|
||||||
|
AddressRangeStart = UInt32.MinValue;
|
||||||
|
AddressRangeEnd = UInt32.MaxValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (address.Contains("/"))
|
||||||
|
{ //range
|
||||||
|
String[] rangeParts = address.Split('/');
|
||||||
|
System.Net.IPAddress ipAddress = System.Net.IPAddress.Parse(rangeParts[0]);
|
||||||
|
|
||||||
|
UInt32 mask = ((UInt32)0xFFFFFFFF << (32 - Int32.Parse(rangeParts[1])));
|
||||||
|
AddressRangeStart = BitConverter.ToUInt32(ipAddress.GetAddressBytes(), 0);
|
||||||
|
//Cast to int to avoid long overload
|
||||||
|
AddressRangeStart = (UInt32)System.Net.IPAddress.HostToNetworkOrder((int)AddressRangeStart);
|
||||||
|
|
||||||
|
AddressRangeEnd = AddressRangeStart | ~(UInt32)mask;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ //Single IP
|
||||||
|
System.Net.IPAddress ipAddress = System.Net.IPAddress.Parse(address);
|
||||||
|
AddressRangeStart = BitConverter.ToUInt32(ipAddress.GetAddressBytes(),0);
|
||||||
|
AddressRangeEnd = BitConverter.ToUInt32(ipAddress.GetAddressBytes(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Port
|
||||||
|
ptr = line.IndexOf(':') + 1;
|
||||||
|
String port = line.Substring(ptr);
|
||||||
|
if (port.Equals("*"))
|
||||||
|
{
|
||||||
|
PortRangeStart = UInt16.MinValue;
|
||||||
|
PortRangeEnd = UInt16.MaxValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (port.Contains("-"))
|
||||||
|
{ //range
|
||||||
|
String[] portParts = port.Split('-');
|
||||||
|
PortRangeStart = UInt16.Parse(portParts[0]);
|
||||||
|
PortRangeEnd = UInt16.Parse(portParts[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PortRangeStart = UInt16.Parse(port);
|
||||||
|
PortRangeEnd = UInt16.Parse(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public String Action { get; set; }
|
||||||
|
public UInt32 AddressRangeStart { get; set; }
|
||||||
|
public UInt32 AddressRangeEnd { get; set; }
|
||||||
|
public UInt16 PortRangeStart { get; set; }
|
||||||
|
public UInt16 PortRangeEnd { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
36
TorControlLibrary/Properties/AssemblyInfo.cs
Normal file
36
TorControlLibrary/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("TorControlLibrary")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("Microsoft")]
|
||||||
|
[assembly: AssemblyProduct("TorControlLibrary")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("f259a6ba-c1f0-4849-ada7-324eddd89739")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
37
TorControlLibrary/Responses/CircuitStatusResponse.cs
Normal file
37
TorControlLibrary/Responses/CircuitStatusResponse.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TorControlLibrary.Responses
|
||||||
|
{
|
||||||
|
public class CircuitStatusResponse : CommandResponse
|
||||||
|
{
|
||||||
|
public CircuitStatusResponse()
|
||||||
|
{
|
||||||
|
Nodes = new SortedList<int, string>();
|
||||||
|
}
|
||||||
|
public static CircuitStatusResponse Parse(String line)
|
||||||
|
{
|
||||||
|
CircuitStatusResponse resp = new CircuitStatusResponse();
|
||||||
|
resp.PopulateData(line, resp);
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
protected SortedList<Int32, String> ParseNodes(String data)
|
||||||
|
{
|
||||||
|
SortedList<Int32, String> nodes = new SortedList<int, string>();
|
||||||
|
String[] nodeList = data.Split(',');
|
||||||
|
for (int i = 0; i < nodeList.Length; i++)
|
||||||
|
nodes.Add(i, nodeList[i]);
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
[ParseAttribute(1)]
|
||||||
|
public Int32 CircuitID { get; set; }
|
||||||
|
[ParseAttribute(2)]
|
||||||
|
public String Status { get; set; }
|
||||||
|
[ParseAttribute(3, CustomParser="ParseNodes")]
|
||||||
|
public SortedList<Int32,String> Nodes { get; set; }
|
||||||
|
[ParseAttribute(4)]
|
||||||
|
public String Purpose { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
57
TorControlLibrary/Responses/CommandResponse.cs
Normal file
57
TorControlLibrary/Responses/CommandResponse.cs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace TorControlLibrary.Responses
|
||||||
|
{
|
||||||
|
public class CommandResponse
|
||||||
|
{
|
||||||
|
public CommandResponse()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public CommandResponse(Int32 status, String response)
|
||||||
|
{
|
||||||
|
StatusCode = status;
|
||||||
|
Response = response.EndsWith(Environment.NewLine) ? response : response + Environment.NewLine;
|
||||||
|
}
|
||||||
|
public virtual void AppendResponse(String line)
|
||||||
|
{
|
||||||
|
Response += line + Environment.NewLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void PopulateData(String dataLine, CommandResponse response)
|
||||||
|
{
|
||||||
|
String[] parts = dataLine.Split(' ');
|
||||||
|
List<PropertyInfo> props = response.GetType().GetProperties().Where(p => p.GetCustomAttributes(typeof(ParseAttribute), true).Any())
|
||||||
|
.OrderBy(p => ((ParseAttribute)p.GetCustomAttributes(typeof(ParseAttribute), true).FirstOrDefault()).Order).ToList();
|
||||||
|
|
||||||
|
foreach (PropertyInfo prop in props)
|
||||||
|
{
|
||||||
|
ParseAttribute attribute = (ParseAttribute)prop.GetCustomAttributes(true).FirstOrDefault();
|
||||||
|
String value = String.Empty;
|
||||||
|
for (int i = 0; i < (attribute.DataElementsToRead == 0 ? 1 : attribute.DataElementsToRead ); i++)
|
||||||
|
value += parts[(i + attribute.Order) - 1] + " ";
|
||||||
|
value = value.Trim();
|
||||||
|
|
||||||
|
MethodInfo parseMethod;
|
||||||
|
if (!String.IsNullOrWhiteSpace(attribute.CustomParser))
|
||||||
|
{
|
||||||
|
parseMethod = response.GetType().GetMethod(attribute.CustomParser,BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
if (parseMethod != null)
|
||||||
|
prop.SetValue(response, parseMethod.Invoke(response, new object[] { value }), null);
|
||||||
|
}
|
||||||
|
else if (prop.PropertyType == typeof(string))
|
||||||
|
prop.SetValue(response, value, null);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parseMethod = prop.PropertyType.GetMethod("Parse", new Type[] { typeof(String) });
|
||||||
|
prop.SetValue(response, parseMethod.Invoke(null, new object[] { value }), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Int32 StatusCode { get; set; }
|
||||||
|
public String Response { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
14
TorControlLibrary/Responses/ErrorResponse.cs
Normal file
14
TorControlLibrary/Responses/ErrorResponse.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TorControlLibrary.Responses
|
||||||
|
{
|
||||||
|
public class ErrorResponse : CommandResponse
|
||||||
|
{
|
||||||
|
public ErrorResponse(Int32 errorCode, String line)
|
||||||
|
: base(errorCode, line)
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
}
|
||||||
29
TorControlLibrary/Responses/EventResponse.cs
Normal file
29
TorControlLibrary/Responses/EventResponse.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TorControlLibrary.Responses
|
||||||
|
{
|
||||||
|
public class EventResponse
|
||||||
|
{
|
||||||
|
public static EventResponse Parse(String line)
|
||||||
|
{
|
||||||
|
EventResponse resp = new EventResponse();
|
||||||
|
string[] parts = line.Split(' ');
|
||||||
|
Int32 id;
|
||||||
|
resp.EventType = parts[1];
|
||||||
|
if (Int32.TryParse(parts[2], out id))
|
||||||
|
resp.ID = id;
|
||||||
|
resp.Action = parts[3];
|
||||||
|
for (int i = 2; i < parts.Length; i++)
|
||||||
|
resp.EventInformation += parts[i] + ' ';
|
||||||
|
resp.EventInformation = resp.EventInformation.Trim();
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
public String EventType { get; set; }
|
||||||
|
public String Action { get; set; }
|
||||||
|
public Int32 ID { get; set; }
|
||||||
|
public String EventInformation { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
12
TorControlLibrary/Responses/EventTypes.cs
Normal file
12
TorControlLibrary/Responses/EventTypes.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TorControlLibrary.Responses
|
||||||
|
{
|
||||||
|
public enum EventTypes
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
18
TorControlLibrary/Responses/ParseAttribute.cs
Normal file
18
TorControlLibrary/Responses/ParseAttribute.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TorControlLibrary.Responses
|
||||||
|
{
|
||||||
|
public class ParseAttribute : System.Attribute
|
||||||
|
{
|
||||||
|
public ParseAttribute(Int32 order)
|
||||||
|
{
|
||||||
|
Order = order;
|
||||||
|
}
|
||||||
|
public Int32 DataElementsToRead { get; set; }
|
||||||
|
public String CustomParser { get; set; }
|
||||||
|
public readonly Int32 Order;
|
||||||
|
}
|
||||||
|
}
|
||||||
22
TorControlLibrary/Responses/RouterDescription.cs
Normal file
22
TorControlLibrary/Responses/RouterDescription.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TorControlLibrary.Responses
|
||||||
|
{
|
||||||
|
public class RouterDescription : CommandResponse
|
||||||
|
{
|
||||||
|
public RouterDescription(String nickname)
|
||||||
|
{
|
||||||
|
this.NickName = nickname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Int32 BandwidthObserved { get; set; }
|
||||||
|
public Int32 BandwidthAverage { get; set; }
|
||||||
|
public Int32 BandwidthBurst { get; set; }
|
||||||
|
public TimeSpan Uptime { get; set; }
|
||||||
|
public String NickName { get; set; }
|
||||||
|
public ExitPolicy ExitPolicy { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
45
TorControlLibrary/Responses/RouterStatusResponse.cs
Normal file
45
TorControlLibrary/Responses/RouterStatusResponse.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TorControlLibrary.Responses
|
||||||
|
{
|
||||||
|
public class RouterStatusResponse : CommandResponse
|
||||||
|
{
|
||||||
|
public static RouterStatusResponse Parse(String routerLine, String flagLine)
|
||||||
|
{
|
||||||
|
RouterStatusResponse resp = new RouterStatusResponse();
|
||||||
|
|
||||||
|
resp.PopulateData(routerLine, resp);
|
||||||
|
resp.Flags = flagLine.Substring(2).Split(' ');
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
protected String ParseEncodedHashes(String value)
|
||||||
|
{
|
||||||
|
if (value.Length % 2 != 0)
|
||||||
|
value += "=";
|
||||||
|
Byte[] digest = Convert.FromBase64String(value);
|
||||||
|
String hash = String.Empty;
|
||||||
|
for (int i = 0; i < digest.Length; i++)
|
||||||
|
hash += String.Format("{0:X2}", digest[i]);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
//Starts at 2, line is r <data>
|
||||||
|
[ParseAttribute(2)]
|
||||||
|
public String NickName { get; set; }
|
||||||
|
[ParseAttribute(3, CustomParser="ParseEncodedHashes")]
|
||||||
|
public String Identity { get; set; }
|
||||||
|
[ParseAttribute(4, CustomParser = "ParseEncodedHashes")]
|
||||||
|
public String Digest { get; set; }
|
||||||
|
[ParseAttribute(5,DataElementsToRead=2)]
|
||||||
|
public DateTime Publication { get; set; }
|
||||||
|
[ParseAttribute(7)]
|
||||||
|
public System.Net.IPAddress Address { get; set; }
|
||||||
|
[ParseAttribute(8)]
|
||||||
|
public Int32 ORPort { get; set; }
|
||||||
|
[ParseAttribute(9)]
|
||||||
|
public Int32 DirPort { get; set; }
|
||||||
|
public String[] Flags { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
33
TorControlLibrary/Responses/StreamStatusResponse.cs
Normal file
33
TorControlLibrary/Responses/StreamStatusResponse.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Net;
|
||||||
|
namespace TorControlLibrary.Responses
|
||||||
|
{
|
||||||
|
public class StreamStatusResponse : CommandResponse
|
||||||
|
{
|
||||||
|
public static StreamStatusResponse Parse(String line)
|
||||||
|
{
|
||||||
|
StreamStatusResponse resp = new StreamStatusResponse();
|
||||||
|
resp.PopulateData(line, resp);
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
[Obsolete()]
|
||||||
|
protected IPEndPoint ParseIPEndPoint(String data)
|
||||||
|
{
|
||||||
|
return new IPEndPoint(IPAddress.Parse(data.Substring(0, data.IndexOf(':'))),
|
||||||
|
Int32.Parse(data.Substring(data.IndexOf(':') + 1)));
|
||||||
|
}
|
||||||
|
[ParseAttribute(1)]
|
||||||
|
public Int32 StreamID { get; set; }
|
||||||
|
[ParseAttribute(2)]
|
||||||
|
public String StreamStatus { get; set; }
|
||||||
|
[ParseAttribute(3)]
|
||||||
|
public Int32 CircuitID { get; set; }
|
||||||
|
[ParseAttribute(4)]
|
||||||
|
public String Target { get; set; }
|
||||||
|
//[ParseAttribute(4, CustomParser="ParseIPEndPoint")]
|
||||||
|
//public IPEndPoint Target { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
73
TorControlLibrary/TorControlLibrary.csproj
Normal file
73
TorControlLibrary/TorControlLibrary.csproj
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProductVersion>8.0.30703</ProductVersion>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>{EF216A86-F64F-4C76-9A86-EEE8E5484EF9}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>TorControlLibrary</RootNamespace>
|
||||||
|
<AssemblyName>TorControlLibrary</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<SccProjectName>Svn</SccProjectName>
|
||||||
|
<SccLocalPath>Svn</SccLocalPath>
|
||||||
|
<SccAuxPath>Svn</SccAuxPath>
|
||||||
|
<SccProvider>SubversionScc</SccProvider>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Exceptions\TorAuthenticationException.cs" />
|
||||||
|
<Compile Include="Exceptions\TorOneCircuitException.cs" />
|
||||||
|
<Compile Include="Exceptions\TorUnknownCircuitException.cs" />
|
||||||
|
<Compile Include="Exceptions\TorException.cs" />
|
||||||
|
<Compile Include="Exceptions\TorUnknownStreamException.cs" />
|
||||||
|
<Compile Include="ExitPolicy.cs" />
|
||||||
|
<Compile Include="Responses\CircuitStatusResponse.cs" />
|
||||||
|
<Compile Include="ControlConnection.cs" />
|
||||||
|
<Compile Include="Responses\CommandResponse.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Responses\ErrorResponse.cs" />
|
||||||
|
<Compile Include="Responses\EventResponse.cs" />
|
||||||
|
<Compile Include="Responses\EventTypes.cs" />
|
||||||
|
<Compile Include="Responses\ParseAttribute.cs" />
|
||||||
|
<Compile Include="Responses\RouterDescription.cs" />
|
||||||
|
<Compile Include="Responses\RouterStatusResponse.cs" />
|
||||||
|
<Compile Include="Responses\StreamStatusResponse.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
||||||
41
TorLibraryTest/App.config
Normal file
41
TorLibraryTest/App.config
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<system.diagnostics>
|
||||||
|
<trace autoflush="true" />
|
||||||
|
<sources>
|
||||||
|
<source name="System.Net">
|
||||||
|
<listeners>
|
||||||
|
<add name="System.Net"/>
|
||||||
|
</listeners>
|
||||||
|
</source>
|
||||||
|
<source name="System.Net.HttpListener">
|
||||||
|
<listeners>
|
||||||
|
<add name="System.Net"/>
|
||||||
|
</listeners>
|
||||||
|
</source>
|
||||||
|
<source name="System.Net.Sockets">
|
||||||
|
<listeners>
|
||||||
|
<add name="System.Net"/>
|
||||||
|
</listeners>
|
||||||
|
</source>
|
||||||
|
<source name="System.Net.Cache">
|
||||||
|
<listeners>
|
||||||
|
<add name="System.Net"/>
|
||||||
|
</listeners>
|
||||||
|
</source>
|
||||||
|
</sources>
|
||||||
|
<sharedListeners>
|
||||||
|
<add
|
||||||
|
name="System.Net"
|
||||||
|
type="System.Diagnostics.TextWriterTraceListener"
|
||||||
|
initializeData="C:\\TorTrace.log" traceOutputOptions = "DateTime" />
|
||||||
|
</sharedListeners>
|
||||||
|
<switches>
|
||||||
|
<add name="System.Net" value="Verbose" />
|
||||||
|
<add name="System.Net.Sockets" value="Verbose" />
|
||||||
|
<add name="System.Net.Cache" value="Verbose" />
|
||||||
|
<add name="System.Net.HttpListener" value="Verbose" />
|
||||||
|
</switches>
|
||||||
|
</system.diagnostics>
|
||||||
|
|
||||||
|
</configuration>
|
||||||
111
TorLibraryTest/ControlConnectionUnitTests.cs
Normal file
111
TorLibraryTest/ControlConnectionUnitTests.cs
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using TorControlLibrary;
|
||||||
|
using TorControlLibrary.Responses;
|
||||||
|
using System.Threading;
|
||||||
|
using Hermes.Objects;
|
||||||
|
|
||||||
|
namespace TorLibraryTest
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ControlConnectionUnitTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void Connect()
|
||||||
|
{
|
||||||
|
ControlConnection connection = new ControlConnection();
|
||||||
|
connection.Connect();
|
||||||
|
connection.Close();
|
||||||
|
}
|
||||||
|
[TestMethod]
|
||||||
|
public void GetCircuitStatuses()
|
||||||
|
{
|
||||||
|
ControlConnection connection = new ControlConnection();
|
||||||
|
connection.Connect();
|
||||||
|
List<CircuitStatusResponse> circuits = connection.GetCircuitStatuses();
|
||||||
|
connection.Close();
|
||||||
|
}
|
||||||
|
[TestMethod]
|
||||||
|
public void GetStreamStatuses()
|
||||||
|
{
|
||||||
|
ControlConnection connection = new ControlConnection();
|
||||||
|
connection.Connect();
|
||||||
|
List<StreamStatusResponse> circuits = connection.GetStreamStatuses();
|
||||||
|
connection.Close();
|
||||||
|
}
|
||||||
|
[TestMethod]
|
||||||
|
public void GetRouterStatuses()
|
||||||
|
{
|
||||||
|
ControlConnection connection = new ControlConnection();
|
||||||
|
connection.Connect();
|
||||||
|
List<RouterStatusResponse> routerInfo = connection.GetAllRouterStatusInfo();
|
||||||
|
connection.Close();
|
||||||
|
}
|
||||||
|
[TestMethod]
|
||||||
|
public void GetRouterStatusByName()
|
||||||
|
{
|
||||||
|
ControlConnection connection = new ControlConnection();
|
||||||
|
connection.Connect();
|
||||||
|
RouterStatusResponse routerInfo = connection.GetRouterStatusInfoByNickname("moria1");
|
||||||
|
connection.Close();
|
||||||
|
Assert.AreEqual("moria1", routerInfo.NickName);
|
||||||
|
}
|
||||||
|
[TestMethod]
|
||||||
|
public void GetRouterDescriptionByName()
|
||||||
|
{
|
||||||
|
ControlConnection connection = new ControlConnection();
|
||||||
|
connection.Connect();
|
||||||
|
RouterDescription routerInfo = connection.GetRouterDescriptionByNickname("desync");
|
||||||
|
connection.Close();
|
||||||
|
Assert.AreEqual("desync", routerInfo.NickName);
|
||||||
|
}
|
||||||
|
[TestMethod]
|
||||||
|
public void GetRouterStatusByID()
|
||||||
|
{
|
||||||
|
ControlConnection connection = new ControlConnection();
|
||||||
|
connection.Connect();
|
||||||
|
RouterStatusResponse routerInfo = connection.GetRouterStatusInfoByID("03C0FB35B3A0D3D12410475C5FDB8F525B7342CD");
|
||||||
|
connection.Close();
|
||||||
|
Assert.AreEqual("zagon", routerInfo.NickName);
|
||||||
|
}
|
||||||
|
[TestMethod]
|
||||||
|
public void SendRawCommand()
|
||||||
|
{
|
||||||
|
ControlConnection connection = new ControlConnection();
|
||||||
|
connection.Connect();
|
||||||
|
CommandResponse resp = connection.SendRawCommand("getinfo version");
|
||||||
|
Assert.AreEqual(250, resp.StatusCode);
|
||||||
|
Assert.IsTrue(resp.Response.Contains("version"));
|
||||||
|
}
|
||||||
|
[TestMethod]
|
||||||
|
public void SimpleEventTest()
|
||||||
|
{
|
||||||
|
ControlConnection connection = new ControlConnection();
|
||||||
|
connection.Connect();
|
||||||
|
connection.ServerEvent += new Action<EventResponse>(connection_ServerEvent);
|
||||||
|
connection.SendRawCommand("SETEVENTS BW");
|
||||||
|
Assert.IsTrue(eventTest.WaitOne(60000));
|
||||||
|
connection.Close();
|
||||||
|
}
|
||||||
|
[TestMethod]
|
||||||
|
public void SocksTest()
|
||||||
|
{
|
||||||
|
Socks5Stream stream = new Socks5Stream("localhost", 9050, "www.google.com", 80);
|
||||||
|
System.IO.StreamWriter writer = new System.IO.StreamWriter(stream);
|
||||||
|
System.IO.StreamReader reader = new System.IO.StreamReader(stream);
|
||||||
|
writer.Write("GET / HTTP 1.1\r\nHost: www.google.com\r\n\r\n");
|
||||||
|
writer.Flush();
|
||||||
|
String results = reader.ReadLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
void connection_ServerEvent(EventResponse obj)
|
||||||
|
{
|
||||||
|
if (obj.EventType.Equals("BW"))
|
||||||
|
eventTest.Set();
|
||||||
|
}
|
||||||
|
private AutoResetEvent eventTest = new AutoResetEvent(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
35
TorLibraryTest/Properties/AssemblyInfo.cs
Normal file
35
TorLibraryTest/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("TorLibraryTest")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("Microsoft")]
|
||||||
|
[assembly: AssemblyProduct("TorLibraryTest")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("e3648bd4-b12a-46ee-8dda-e53d4ed94cd5")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
72
TorLibraryTest/TorLibraryTest.csproj
Normal file
72
TorLibraryTest/TorLibraryTest.csproj
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProductVersion>
|
||||||
|
</ProductVersion>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>{020A074C-B1F5-498A-8C1D-B1D90C79D50D}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>TorLibraryTest</RootNamespace>
|
||||||
|
<AssemblyName>TorLibraryTest</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core">
|
||||||
|
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
|
||||||
|
<Visible>False</Visible>
|
||||||
|
</CodeAnalysisDependentAssemblyPaths>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="ControlConnectionUnitTests.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Hermes\Hermes.csproj">
|
||||||
|
<Project>{3DE6415A-1DED-4F75-9202-39BDF012BB5A}</Project>
|
||||||
|
<Name>Hermes</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\TorControlLibrary\TorControlLibrary.csproj">
|
||||||
|
<Project>{EF216A86-F64F-4C76-9A86-EEE8E5484EF9}</Project>
|
||||||
|
<Name>TorControlLibrary</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
||||||
21
TraceAndTestImpact.testsettings
Normal file
21
TraceAndTestImpact.testsettings
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<TestSettings name="Trace and Test Impact" id="5ba24034-a020-438c-a132-b604db130426" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
|
||||||
|
<Description>These are test settings for Trace and Test Impact.</Description>
|
||||||
|
<Execution>
|
||||||
|
<TestTypeSpecific />
|
||||||
|
<AgentRule name="Execution Agents">
|
||||||
|
<DataCollectors>
|
||||||
|
<DataCollector uri="datacollector://microsoft/SystemInfo/1.0" assemblyQualifiedName="Microsoft.VisualStudio.TestTools.DataCollection.SystemInfo.SystemInfoDataCollector, Microsoft.VisualStudio.TestTools.DataCollection.SystemInfo, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" friendlyName="System Information">
|
||||||
|
</DataCollector>
|
||||||
|
<DataCollector uri="datacollector://microsoft/ActionLog/1.0" assemblyQualifiedName="Microsoft.VisualStudio.TestTools.ManualTest.ActionLog.ActionLogPlugin, Microsoft.VisualStudio.TestTools.ManualTest.ActionLog, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" friendlyName="Actions">
|
||||||
|
</DataCollector>
|
||||||
|
<DataCollector uri="datacollector://microsoft/HttpProxy/1.0" assemblyQualifiedName="Microsoft.VisualStudio.TraceCollector.HttpProxyCollector, Microsoft.VisualStudio.TraceCollector, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" friendlyName="ASP.NET Client Proxy for IntelliTrace and Test Impact">
|
||||||
|
</DataCollector>
|
||||||
|
<DataCollector uri="datacollector://microsoft/TestImpact/1.0" assemblyQualifiedName="Microsoft.VisualStudio.TraceCollector.TestImpactDataCollector, Microsoft.VisualStudio.TraceCollector, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" friendlyName="Test Impact">
|
||||||
|
</DataCollector>
|
||||||
|
<DataCollector uri="datacollector://microsoft/TraceDebugger/1.0" assemblyQualifiedName="Microsoft.VisualStudio.TraceCollector.TraceDebuggerDataCollector, Microsoft.VisualStudio.TraceCollector, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" friendlyName="IntelliTrace">
|
||||||
|
</DataCollector>
|
||||||
|
</DataCollectors>
|
||||||
|
</AgentRule>
|
||||||
|
</Execution>
|
||||||
|
</TestSettings>
|
||||||
Reference in New Issue
Block a user