Skip to content

Commit

Permalink
fixup: cachePath and use client everywhere
Browse files Browse the repository at this point in the history
  • Loading branch information
aarani committed Oct 28, 2023
1 parent 20413b3 commit 4aac077
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 180 deletions.
59 changes: 34 additions & 25 deletions NOnion.Tests/HiddenServicesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using NOnion.Network;
using NOnion.Http;
using NOnion.Cells.Relay;
using NOnion.Client;
using NOnion.Directory;
using NOnion.Tests.Utility;
using NOnion.Services;
Expand All @@ -24,6 +25,23 @@ namespace NOnion.Tests
{
public class HiddenServicesTests
{
[SetUp]
public void Init()
{
cachePath =
new DirectoryInfo(
Path.Combine(
Path.GetTempPath(),
Path.GetFileNameWithoutExtension(
Path.GetRandomFileName()
)
)
);
cachePath.Create();
}

private DirectoryInfo cachePath = null;

/* It's possible that the router returned by GetRandomFallbackDirectory or
* GetRandomRoutersForDirectoryBrowsing be inaccessable so we need to continue
* retrying if an exceptions happened to make sure the issues are not related
Expand All @@ -33,11 +51,8 @@ public class HiddenServicesTests

private async Task CreateIntroductionCircuit()
{
var node = (CircuitNodeDetail.Create)(await CircuitHelper.GetRandomRoutersForDirectoryBrowsingWithRetry()).First();
using TorGuard guard = await TorGuard.NewClientAsync(node.EndPoint);
var circuit = new TorCircuit(guard);

await circuit.CreateAsync(CircuitNodeDetail.FastCreate);
using TorClient torClient = await TorClient.BootstrapWithGithubAsync(cachePath);
var circuit = await torClient.CreateCircuitAsync(1, CircuitPurpose.Unknown, FSharpOption<CircuitNodeDetail>.None);
await circuit.RegisterAsIntroductionPointAsync(FSharpOption<AsymmetricCipherKeyPair>.None, StubCallback, DisconnectionCallback);
}

Expand All @@ -61,12 +76,8 @@ private async Task CreateRendezvousCircuit()
var array = new byte[Constants.RendezvousCookieLength];
RandomNumberGenerator.Create().GetNonZeroBytes(array);

var nodes = await CircuitHelper.GetRandomRoutersForDirectoryBrowsingWithRetry(2);
using TorGuard guard = await TorGuard.NewClientAsync(((CircuitNodeDetail.Create)nodes[0]).EndPoint);
var circuit = new TorCircuit(guard);

await circuit.CreateAsync(nodes[0]);
await circuit.ExtendAsync(nodes[1]);
using TorClient torClient = await TorClient.BootstrapWithGithubAsync(cachePath);
var circuit = await torClient.CreateCircuitAsync(2, CircuitPurpose.Unknown, FSharpOption<CircuitNodeDetail>.None);
await circuit.RegisterAsRendezvousPointAsync(array);
}

Expand All @@ -92,10 +103,10 @@ private async Task<int> ReadExact(TorStream stream, byte[] buffer, int off, int

public async Task BrowseFacebookOverHS()
{
TorDirectory directory = await TorDirectory.BootstrapAsync(FallbackDirectorySelector.GetRandomFallbackDirectory(), new DirectoryInfo(Path.GetTempPath()));
using TorClient torClient = await TorClient.BootstrapWithGithubAsync(cachePath);

var client = await TorServiceClient.ConnectAsync(directory, "facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd.onion");
var httpClient = new TorHttpClient(client.GetStream(), "facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd.onion");
var serviceClient = await TorServiceClient.ConnectAsync(torClient, "facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd.onion");
var httpClient = new TorHttpClient(serviceClient.GetStream(), "facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd.onion");

try
{
Expand All @@ -117,11 +128,11 @@ public void CanBrowseFacebookOverHS()

public async Task BrowseFacebookOverHSWithTLS()
{
TorDirectory directory = await TorDirectory.BootstrapAsync(FallbackDirectorySelector.GetRandomFallbackDirectory(), new DirectoryInfo(Path.GetTempPath()));

var client = await TorServiceClient.ConnectAsync(directory, "facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd.onion:443");
using TorClient torClient = await TorClient.BootstrapWithGithubAsync(cachePath);
var serviceClient = await TorServiceClient.ConnectAsync(torClient, "facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd.onion:443");

var sslStream = new SslStream(client.GetStream(), true, (sender, cert, chain, sslPolicyErrors) => true);
var sslStream = new SslStream(serviceClient.GetStream(), true, (sender, cert, chain, sslPolicyErrors) => true);
await sslStream.AuthenticateAsClientAsync(string.Empty, null, SslProtocols.Tls12, false);

var httpClientOverSslStream = new TorHttpClient(sslStream, "www.facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd.onion");
Expand All @@ -147,18 +158,16 @@ public void CanBrowseFacebookOverHSWithTLS()

public async Task EstablishAndCommunicateOverHSConnectionOnionStyle()
{
int descriptorUploadRetryLimit = 2;

TorDirectory directory = await TorDirectory.BootstrapAsync(FallbackDirectorySelector.GetRandomFallbackDirectory(), new DirectoryInfo(Path.GetTempPath()));

using TorClient torClient = await TorClient.BootstrapWithGithubAsync(cachePath);

TorLogger.Log("Finished bootstraping");

SecureRandom random = new SecureRandom();
Ed25519KeyPairGenerator kpGen = new Ed25519KeyPairGenerator();
kpGen.Init(new Ed25519KeyGenerationParameters(random));
Ed25519PrivateKeyParameters masterPrivateKey = (Ed25519PrivateKeyParameters)kpGen.GenerateKeyPair().Private;

TorServiceHost host = new TorServiceHost(directory, descriptorUploadRetryLimit, TestsRetryCount, FSharpOption<Ed25519PrivateKeyParameters>.Some(masterPrivateKey));
TorServiceHost host = new TorServiceHost(torClient, FSharpOption<Ed25519PrivateKeyParameters>.Some(masterPrivateKey));
await host.StartAsync();

TorLogger.Log("Finished starting HS host");
Expand All @@ -175,8 +184,8 @@ public async Task EstablishAndCommunicateOverHSConnectionOnionStyle()

var clientSide =
Task.Run(async () => {
var client = await TorServiceClient.ConnectAsync(directory, host.ExportUrl());
var stream = client.GetStream();
var serviceClient = await TorServiceClient.ConnectAsync(torClient, host.ExportUrl());
var stream = serviceClient.GetStream();
var lengthBytes = new byte[sizeof(int)];
await ReadExact(stream, lengthBytes, 0, lengthBytes.Length);
var length = BitConverter.ToInt32(lengthBytes);
Expand Down
31 changes: 24 additions & 7 deletions NOnion.Tests/TorClientTests.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
using System;
using System.Collections.Generic;
using Microsoft.FSharp.Core;
using System.IO;
using System.Text;
using System.Threading.Tasks;

using NUnit.Framework;

using NOnion.Directory;
using NOnion.Client;

using Microsoft.FSharp.Core;

namespace NOnion.Tests
{
public class TorClientTests
{
private async Task BootstrapWithGithub()
{
await TorClient.BootstrapWithGithubAsync(FSharpOption<DirectoryInfo>.None);
}

[Test]
public void CanBootstrapWithGithub()
{
Assert.DoesNotThrowAsync(BootstrapWithGithub);
}

private async Task BootstrapWithEmbeddedList()
{
await TorClient.BootstrapWithEmbeddedListAsync(FSharpOption<DirectoryInfo>.None);
}

[Test]
public void CanBootstrapWithEmbeddedList()
{
Assert.DoesNotThrowAsync(BootstrapWithEmbeddedList);
}

private async Task CreateCircuit()
{
var client = await TorClient.BootstrapWithEmbeddedListAsync();
using TorClient client = await TorClient.BootstrapWithEmbeddedListAsync(FSharpOption<DirectoryInfo>.None);
await client.CreateCircuitAsync(3, CircuitPurpose.Unknown, FSharpOption<Network.CircuitNodeDetail>.None);
}

Expand Down
63 changes: 42 additions & 21 deletions NOnion/Client/TorClient.fs
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,31 @@ type TorClient internal (directory: TorDirectory) =
)
|> Seq.toList

static let BootstrapDirectory(ipEndPointList: List<IPEndPoint>) =
static let BootstrapDirectory
(cachePath: Option<DirectoryInfo>)
(ipEndPointList: List<IPEndPoint>)
=
async {
let rec tryBootstrap(ipEndPointList: List<IPEndPoint>) =
async {
match ipEndPointList with
| ipEndPoint :: tail ->
try
let cacheDirectory =
match cachePath with
| None ->
DirectoryInfo(
Path.Combine(
Path.GetTempPath(),
Path.GetFileNameWithoutExtension(
Path.GetRandomFileName()
)
)
)
| Some path -> path

let! directory =
TorDirectory.Bootstrap
ipEndPoint
(Path.GetTempPath() |> DirectoryInfo)
TorDirectory.Bootstrap ipEndPoint cacheDirectory

return directory
with
Expand All @@ -62,33 +76,40 @@ type TorClient internal (directory: TorDirectory) =
return! tryBootstrap ipEndPointList
}

static let CreateClientFromFallbackString(fallbackListString: string) =
static let CreateClientFromFallbackString
(fallbackListString: string)
(cachePath: Option<DirectoryInfo>)
=
async {
let! directory =
fallbackListString
|> ConvertFallbackIncToList
|> SelectRandomEndpoints
|> BootstrapDirectory
|> BootstrapDirectory cachePath

return new TorClient(directory)
}

let guardsToDispose = ConcurrentBag<TorGuard>()

static member AsyncBootstrapWithEmbeddedList() =
static member AsyncBootstrapWithEmbeddedList
(cachePath: Option<DirectoryInfo>)
=
async {
let fallbackListString =
EmbeddedResourceUtility.ExtractEmbeddedResourceFileContents(
"fallback_dirs.inc"
)

return! CreateClientFromFallbackString fallbackListString
return! CreateClientFromFallbackString fallbackListString cachePath
}

static member BootstrapWithEmbeddedListAsync() =
TorClient.AsyncBootstrapWithEmbeddedList() |> Async.StartAsTask
static member BootstrapWithEmbeddedListAsync
(cachePath: Option<DirectoryInfo>)
=
TorClient.AsyncBootstrapWithEmbeddedList cachePath |> Async.StartAsTask

static member AsyncBootstrapWithGithub() =
static member AsyncBootstrapWithGithub(cachePath: Option<DirectoryInfo>) =
async {
// Don't put this inside the fallbackListString or it gets disposed
// before the task gets executed
Expand All @@ -97,17 +118,18 @@ type TorClient internal (directory: TorDirectory) =
let! fallbackListString =
let urlToTorServerList =
"https://raw.githubusercontent.com/torproject/tor/main/src/app/config/fallback_dirs.inc"

httpClient.GetStringAsync urlToTorServerList |> Async.AwaitTask

return! CreateClientFromFallbackString fallbackListString
return! CreateClientFromFallbackString fallbackListString cachePath
}

static member BootstrapWithGithubAsync() =
TorClient.AsyncBootstrapWithGithub() |> Async.StartAsTask
static member BootstrapWithGithubAsync(cachePath: Option<DirectoryInfo>) =
TorClient.AsyncBootstrapWithGithub cachePath |> Async.StartAsTask

member __.Directory = directory

member __.CreateCircuit
member __.AsyncCreateCircuit
(hopsCount: int)
(purpose: CircuitPurpose)
(extendByNodeOpt: Option<CircuitNodeDetail>)
Expand All @@ -134,10 +156,7 @@ type TorClient internal (directory: TorDirectory) =
let rec tryCreateCircuit(tryNumber: int) =
async {
if tryNumber > maximumExtendByNodeRetry then
return
raise
<| NOnionException
"Destination node can't be reached"
return raise <| DestinationNodeCantBeReachedException()
else
try
let! guard, guardDetail = createNewGuard()
Expand Down Expand Up @@ -205,7 +224,8 @@ type TorClient internal (directory: TorDirectory) =
| :? NOnionException ->
return
raise
DestinationNodeCantBeReachedException
<| DestinationNodeCantBeReachedException
()
| None -> ()

return circuit
Expand All @@ -231,7 +251,8 @@ type TorClient internal (directory: TorDirectory) =
purpose: CircuitPurpose,
extendByNode: Option<CircuitNodeDetail>
) =
self.CreateCircuit hopsCount purpose extendByNode |> Async.StartAsTask
self.AsyncCreateCircuit hopsCount purpose extendByNode
|> Async.StartAsTask


interface IDisposable with
Expand Down
3 changes: 2 additions & 1 deletion NOnion/Exceptions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@ type NOnionSocketException
innerException
)

exception internal DestinationNodeCantBeReachedException
type DestinationNodeCantBeReachedException() =
inherit NOnionException("Destination node can't be reached")
Loading

0 comments on commit 4aac077

Please sign in to comment.