Skip to content

Commit

Permalink
Tests: introduce HS compat test with TOR client
Browse files Browse the repository at this point in the history
This commit introduces a test to make sure our
hidden service hosts are accessible by official
tor client.

Testing only with NOnion's TorServiceClient can
cause mask problems because it shares lots of
code with TorServiceHost (especially crypto stuff)
and mistakes there can go unnoticed.

Upgrade to .NET 6 was necessary to be able
to use SocksV5 (which is what tor gives us)
as proxy for HttpClient.

Due to some problem with NUnit not writing test-by-test
output (whether it passed or failed), I had to upgrade
even furthur into .NET 7.
  • Loading branch information
aarani committed Apr 25, 2023
1 parent 6069c42 commit 657c560
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 10 deletions.
26 changes: 21 additions & 5 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,36 @@ jobs:
build_and_test:
name: Build & Test
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
include:
- dotnet_version: "3.1.x"
flag: ""
- dotnet_version: "7.0.x"
flag: "-p:NET7=true"
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Setup .NET Core SDK 3.1.x
- name: Setup .NET SDK ${{ matrix.dotnet_version }}
uses: actions/[email protected]
with:
dotnet-version: '3.1.x'
dotnet-version: ${{ matrix.dotnet_version }}
- name: Install dependencies
run: dotnet restore
run: dotnet restore ${{ matrix.flag }}
- name: Build
run: dotnet build --configuration Release --no-restore
run: dotnet build --configuration Release --no-restore ${{ matrix.flag }}
# Please keep in mind that NOnion DOES NOT require tor client to function
# tor client is only installed here for testing purposes.
- name: Install Tor and wait for startup
run: |
sudo apt install tor
echo -e "SOCKSPort 127.0.0.1:9050" | sudo tee -a /etc/tor/torrc
sudo systemctl restart tor
sleep 2m
- name: Test
run: dotnet test --no-restore --verbosity normal
run: dotnet test --no-restore --verbosity normal ${{ matrix.flag }}

sanity_check:
name: Sanity Check
Expand Down
74 changes: 73 additions & 1 deletion NOnion.Tests/HiddenServicesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

using NUnit.Framework;
Expand Down Expand Up @@ -133,7 +136,7 @@ public void CanBrowseFacebookOverHSWithTLS()
Assert.DoesNotThrowAsync(BrowseFacebookOverHSWithTLS);
}

public async Task EstablishAndCommunicateOverHSConnectionOnionStyle()
private async Task<(TorDirectory, TorServiceHost)> BootstrapDirectoryAndStartHost()
{
int descriptorUploadRetryLimit = 2;

Expand All @@ -151,6 +154,13 @@ public async Task EstablishAndCommunicateOverHSConnectionOnionStyle()

TorLogger.Log("Finished starting HS host");

return (directory, host);
}

public async Task EstablishAndCommunicateOverHSConnectionOnionStyle()
{
(var directory, var host) = await BootstrapDirectoryAndStartHost();

var dataToSendAndReceive = new byte[] { 1, 2, 3, 4 };

var serverSide =
Expand Down Expand Up @@ -185,6 +195,68 @@ public void CanEstablishAndCommunicateOverHSConnectionOnionStyle()
{
Assert.DoesNotThrowAsync(EstablishAndCommunicateOverHSConnectionOnionStyle);
}

#if NET6_0_OR_GREATER
[Test]
[Retry(TestsRetryCount)]
public void CanConnectToHiddenServiceUsingTorClient()
{
Assert.DoesNotThrowAsync(ConnectToHiddenServiceUsingTorClient);
}

private async Task ConnectToHiddenServiceUsingTorClient()
{
(_, var host) = await BootstrapDirectoryAndStartHost();

var stringToSendAndReceive =
"We are using tor!";

var serverSide =
Task.Run(async () => {
var stream = await host.AcceptClientAsync();
var httpResponse =
"HTTP/1.1 200 OK\r\n" +
"Server: NOnion\r\n" +
$"Content-Length: {stringToSendAndReceive.Length}\r\n" +
"Connection: close\r\n" +
"Content-Type: text/plain" +
"\r\n" +
"\r\n" +
stringToSendAndReceive +
"\r\n";
var httpResponseBytes =
Encoding.ASCII.GetBytes(httpResponse);
await stream.WriteAsync(httpResponseBytes, 0, httpResponseBytes.Length);
await stream.EndAsync();
});

var clientSide =
Task.Run(async () => {
var handler = new HttpClientHandler
{
Proxy = new WebProxy(new Uri("socks5://localhost:9050"))
};
TestContext.Progress.WriteLine("Trying to connect to hidden service...");
using (handler)
using (var httpClient = new HttpClient(handler))
{
// Sometimes tor client takes a while to bootstrap and stalls
// the request.
httpClient.Timeout = TimeSpan.FromMinutes(20);
var result = await httpClient.GetStringAsync("http://" + host.ExportUrl());
Assert.AreEqual(result, stringToSendAndReceive);
}
}
);

await TaskUtils.WhenAllFailFast(serverSide, clientSide);

((IDisposable)host).Dispose();
}
#endif
}
}

8 changes: 4 additions & 4 deletions NOnion.Tests/NOnion.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>

<TargetFramework Condition="'$(NET7)' != 'true'">netcoreapp3.1</TargetFramework>
<TargetFramework Condition="'$(NET7)' == 'true'">net7.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="Portable.BouncyCastle" Version="1.8.10" />
</ItemGroup>
Expand Down

0 comments on commit 657c560

Please sign in to comment.