Knapcode.TorSharp
2.14.0
dotnet add package Knapcode.TorSharp --version 2.14.0
NuGet\Install-Package Knapcode.TorSharp -Version 2.14.0
<PackageReference Include="Knapcode.TorSharp" Version="2.14.0" />
paket add Knapcode.TorSharp --version 2.14.0
#r "nuget: Knapcode.TorSharp, 2.14.0"
// Install Knapcode.TorSharp as a Cake Addin #addin nuget:?package=Knapcode.TorSharp&version=2.14.0 // Install Knapcode.TorSharp as a Cake Tool #tool nuget:?package=Knapcode.TorSharp&version=2.14.0
TorSharp
Use Tor for your C# HTTP clients. Use Privoxy or .NET 6+ SOCKS support to proxy HTTP traffic.
All you need is client code that can use a simple HTTP proxy.
Notice
This product is produced independently from the Tor® anonymity software and carries no guarantee from The Tor Project about quality, suitability or anything else.
Details
- Supports:
- .NET Core (.NET Standard 2.0 and later, including .NET 5+)
- .NET Framework (.NET Framework 4.6.2 and later)
- Windows
- ✔️ Windows 10 version 1903
- ✔️ Windows 11 version 21H2
- Older Windows should work too
- Linux
- ✔️ Ubuntu 20.04
- ✔️ Ubuntu 18.04
- ✔️ Ubuntu 16.04
- ✔️ Debian 10
- ⚠️ Debian 9 (confirmed by a user but may have issues)
- ⚠️ CentOS 7 supported via
ExecutablePathOverride
(see below)
- ❌ Mac OS X support is not planned. I don't have a Mac 😕
- Uses Privoxy to redirect HTTP proxy traffic to Tor (can be disabled).
- On Windows, uses virtual desktops to manage Tor and Privoxy processes and hide the windows so it's cleaner.
- Optionally downloads the latest version of Tor and Privoxy for you.
Install
dotnet add package Knapcode.TorSharp
Example using .NET 6+ SOCKS support
Starting on .NET 6, there is built-in support for SOCKS proxies. This means you don't need Privoxy. Thanks, .NET team!
See samples/NativeSocksProxy/Program.cs
for a working sample.
var settings = new TorSharpSettings
{
PrivoxySettings = { Disable = true }
};
// download Tor
using (var httpClient = new HttpClient())
{
var fetcher = new TorSharpToolFetcher(settings, httpClient);
await fetcher.FetchAsync();
}
// execute
using (var proxy = new TorSharpProxy(settings))
{
await proxy.ConfigureAndStartAsync();
var handler = new HttpClientHandler
{
Proxy = new WebProxy(new Uri("socks5://localhost:" + settings.TorSettings.SocksPort))
};
using (handler)
using (var httpClient = new HttpClient(handler))
{
var result = await httpClient.GetStringAsync("https://check.torproject.org/api/ip");
Console.WriteLine();
Console.WriteLine("Are we using Tor?");
Console.WriteLine(result);
}
proxy.Stop();
}
Example using Privoxy
See samples/TorSharp.Sandbox/Program.cs
for a working sample.
// configure
var settings = new TorSharpSettings
{
ZippedToolsDirectory = Path.Combine(Path.GetTempPath(), "TorZipped"),
ExtractedToolsDirectory = Path.Combine(Path.GetTempPath(), "TorExtracted"),
PrivoxySettings = { Port = 1337 },
TorSettings =
{
SocksPort = 1338,
ControlPort = 1339,
ControlPassword = "foobar",
},
};
// download tools
await new TorSharpToolFetcher(settings, new HttpClient()).FetchAsync();
// execute
var proxy = new TorSharpProxy(settings);
var handler = new HttpClientHandler
{
Proxy = new WebProxy(new Uri("http://localhost:" + settings.PrivoxySettings.Port))
};
var httpClient = new HttpClient(handler);
await proxy.ConfigureAndStartAsync();
Console.WriteLine(await httpClient.GetStringAsync("http://api.ipify.org"));
await proxy.GetNewIdentityAsync();
Console.WriteLine(await httpClient.GetStringAsync("http://api.ipify.org"));
proxy.Stop();
FAQ
The tool fetcher is throwing an exception. What do I do?
This most likely is happening because the URLs where we fetch Tor or Privoxy from are down or have changed. I would recommend:
Open an issue so I can look into it.
Work around the issue by setting up the tools manually and not using
TorSharpToolFetcher
. See below.Investigate the issue yourself. The TorSharp.Sandbox project is helpful for this. Pull requests accepted 🏆.
How do I set up the tools manually?
If you don't want to use the TorSharpToolFetcher
to download the latest version of the tools for you or if you want to use a specific version of Tor and Privoxy, follow these steps.
- Make a directory that will hold the zipped Tor and Privoxy binaries.
- Put a Tor Win32 ZIP in that folder with the file name like:
tor-win32-{version}.zip
{version}
must be parsable as aSystem.Version
meaning it ismajor.minor[.build[.revision]]
.- Example:
tor-win32-0.3.5.8.zip
- The ZIP is expected to have
Tor\tor.exe
.
- Put a Privoxy Win32 ZIP in that folder with a file name like:
privoxy-win32-{version}.zip
- Again,
{version}
must be parsable as aSystem.Version
. - Example:
privoxy-win32-3.0.26.zip
- The ZIP is expected to have
privoxy.exe
.
- Again,
- Initialize a
TorSharpSettings
instance whereZippedToolsDirectory
is the directory created above. - Pass this settings instance to the
TorSharpProxy
constructor.
Can I run multiple instances in parallel?
Yes, you can. See this sample: samples/MultipleInstances/Program.cs
.
However, you need to adhere to the following guidance.
None of the types in this library should be considered thread safe. Use separate instances for each parallel task/thread.
TorSharpProxy
: this is stateful and should not be shared.TorSharpSettings
: the values held in the settings class need to be different for parallel threads, so it doesn't make sense to share instances.TorSharpToolFetcher
: this is stateless so it may be safe, but I would keep this a singleton since you shouldn't have multiple copies of the zipped tools (just multiple copies of the extracted tools).
Parallel threads must have different values for these settings. The defaults will not work.
- Must be made unique by you:
TorSharpSettings.ExtractedToolsDirectory
: this is the parent directory of the tool working directories. Specify a different value for each thread. In the sample above, I see each parallel task to be a sibling directory, e.g.{some_root}/a
,{some_root}/b
, etc.TorSharpSettings.PrivoxySettings.Port
: this is the Privoxy listen port. Each Privoxy process needs its own port. Can be ignored ifTorSharpSettings.PrivoxySettings.Disable
istrue
.TorSharpSettings.TorSettings.SocksPort
: this is the Tor SOCKS listen port. Each Tor process needs its own port.
- Must be unique, but only if you set them:
TorSharpSettings.VirtualDesktopName
: this is automatically generated based onExtractedToolsDirectory
, but if you manually set it, it must be unique.TorSharpSettings.TorSettings.ControlPort
: this is the Tor SOCKS listen port. Each Tor process needs its own port.TorSharpSettings.TorSettings.AdditionalSockPorts
: if used, it must have unique values.TorSharpSettings.TorSettings.HttpTunnelPort
: if used, it must have a unique value.TorSharpSettings.TorSettings.DataDirectory
: the default is basedExtractedToolsDirectory
, but if you manually set it, it must be unique.
In general, directory configuration values must be different from all of the other directories, except TorSharpSettings.ZippedToolsDirectory
which should not be downloaded to in parallel by TorSharpToolFetcher
but can be read from in parallel with multiple TorSharpProxy
instances. Port configuration values need to all be unique.
How do I change what TorSharp logs?
By default, TorSharp lets the tools (Tor, Privoxy) log to the main process stdout and stderr. If you want to disable this behavior, set TorSharpSettings.WriteToConsole
to false
. If you want to intercept the output from the tools, attach to the TorSharpProxy.OutputDataReceived
(for stdout) and TorSharpProxy.ErrorDataReceived
(for stderr) events. In your event handler, you can log to some external sink or enqueue the line for processing. The event handlers are fired from a task using the default task scheduler so this blocks one of the shared worker threads. Don't do too much heavy lifting there, I guess! If you want to know which tool sent the log message, look at the DataEventArgs.ExecutablePath
property.
For a full sample, see this: samples/CustomLogging/Program.cs
.
Privoxy fetched by TorSharp fails to start? Try installing missing dependencies.
It's possible some expected shared libraries aren't there. Try to look at the error message and judge which library needs to be installed from your distro's package repository.
Ubuntu 20.04
Problem: On Ubuntu 20.04 the following errors may appear:
/tmp/TorExtracted/privoxy-linux64-3.0.29/usr/sbin/privoxy: error while loading shared libraries: libmbedtls.so.12: cannot open shared object file: No such file or directory
Solution: install the missing dependencies. Note that these steps install packages from the Debian repository. This is very much not recommended by official guidance. For my own testing, it works well enough. I use this trick in the GitHub Action workflow. ⚠️ Do this at your own risk!
[joel@ubuntu]$ curl -O http://ftp.us.debian.org/debian/pool/main/m/mbedtls/libmbedcrypto3_2.16.0-1_amd64.deb
[joel@ubuntu]$ curl -O http://ftp.us.debian.org/debian/pool/main/m/mbedtls/libmbedx509-0_2.16.0-1_amd64.deb
[joel@ubuntu]$ curl -O http://ftp.us.debian.org/debian/pool/main/m/mbedtls/libmbedtls12_2.16.0-1_amd64.deb
[joel@ubuntu]$ echo "eb6751c98adfdf0e7a5a52fbd1b5a284ffd429e73abb4f0a4497374dd9f142c7 libmbedcrypto3_2.16.0-1_amd64.deb" > SHA256SUMS
[joel@ubuntu]$ echo "e8ea5dd71b27591c0f55c1d49f597d3d3b5c747bde25d3b3c3b03ca281fc3045 libmbedx509-0_2.16.0-1_amd64.deb" >> SHA256SUMS
[joel@ubuntu]$ echo "786c7e7805a51f3eccd449dd44936f735afa97fc5f3702411090d8b40f0e9eda libmbedtls12_2.16.0-1_amd64.deb" >> SHA256SUMS
[joel@ubuntu]$ sha256sum -c SHA256SUMS || { echo "Checksum failed. Aborting."; exit 1; }
[joel@ubuntu]$ sudo apt-get install -y --allow-downgrades ./*.deb
I have the checksum verification in there because these pages have SSL problems and the advertised URL is HTTP not HTTPS (by design I think).
Debian 10
Problem: On Debian 10 the following errors may appear:
/tmp/TorExtracted/privoxy-linux64-3.0.29/usr/sbin/privoxy: error while loading shared libraries: libbrotlidec.so.1: cannot open shared object file: No such file or directory
/tmp/TorExtracted/privoxy-linux64-3.0.29/usr/sbin/privoxy: error while loading shared libraries: libmbedtls.so.12: cannot open shared object file: No such file or directory
Solution: install two missing dependencies. Thanks for the heads up, @cod3rshotout!
[joel@debian10]$ sudo apt-get install -y libbrotli1 libmbedtls-dev
Privoxy fetched by TorSharp fails to start? Try ExecutablePathOverride
.
On Linux, the Privoxy binaries fetched seem to be built for the latest Debian and Ubuntu distributions. I can confirm that some other distributions don't work.
I'm no Linux expert but my guess is that there are missing shared libraries that are different on the running platform than the Debian platform that Privoxy was compiled for. The easiest workaround is to install Privoxy to your system and set the TorSharpSettings.PrivoxySetting.ExecutablePathOverride
configuration setting to "privoxy"
(i.e. use Privoxy from PATH).
After you install it, make sure privoxy
is in the PATH.
[joel@linux]$ which privoxy
/usr/sbin/privoxy
After this is done, just configure TorSharp to use the system Privoxy with the ExecutablePathOverride
setting:
var settings = new TorSharpSettings();
settings.PrivoxySettings.ExecutablePathOverride = "privoxy";
Note that you may encounter warning or error messages in the output due to new configuration being used with an older executable. I haven't ran into any problems with this myself but it's possible things could get weird.
CentOS 7
Problem: the following error appears:
/tmp/TorExtracted/privoxy-linux64-3.0.28/usr/sbin/privoxy: error while loading shared libraries: libpcre.so.3: cannot open shared object file: No such file or directory
Solution: install Privoxy. It is available on epel-release
.
[joel@centos]$ sudo yum install epel-release -y
...
[joel@centos]$ sudo yum install privoxy -y
Debian 9
Problem: the following errors may appear:
/tmp/TorExtracted/privoxy-linux64-3.0.29/usr/sbin/privoxy: error while loading shared libraries: libbrotlidec.so.1: cannot open shared object file: No such file or directory
/tmp/TorExtracted/privoxy-linux64-3.0.29/usr/sbin/privoxy: error while loading shared libraries: libmbedtls.so.12: cannot open shared object file: No such file or directory
Solution: install Privoxy. It is available in the default source lists.
[joel@debian9]$ sudo apt-get install privoxy -y
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 is compatible. net463 was computed. net47 was computed. net471 was computed. net472 is compatible. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.6.2
- SharpCompress (>= 0.32.2)
-
.NETFramework 4.7.2
- SharpCompress (>= 0.32.2)
-
.NETStandard 2.0
- SharpCompress (>= 0.32.2)
- System.ServiceModel.Syndication (>= 6.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
2.14.0 | 0 | 8/8/2023 |
* 2.14.0 Fix bug where relative directory paths didn't work right.
* 2.13.0 Fix release build problem where it was building for x64 for not MSIL (x64 preferred).
* 2.12.0 Fix bug with ExitNodes Tor setting having wrong GeoIP file path, add default Tor control password.
* 2.11.0 Add ability to intercept and silence tool logging to stdout and stderr.
* 2.10.0 Allow Privoxy to be disabled (.NET 6 supports SOCKS natively), fix some parallel bugs.
* 2.9.0 Update to new Tor URLs, fixing tool fetcher, drop .NET 4.5 and add .NET 4.6.2.
* 2.8.1 Fix potential deadlock in UI apps due to unnecessary Task.Yield.
* 2.8.0 Add HttpTunnelPort Tor setting, use tor-win64, add .NET Framework 4.7.2 target.
* 2.7.0 Separate proxy Configure and Start steps, support old behavior with extension method.
* 2.6.0 Make SendCommandAsync public and add AdditionalSocksPorts.
* 2.5.0 Don't try to use virtual desktops on Windows 7 or earlier.
* 2.4.0 Add support for custom Tor bridges, allow configurable max Privoxy connections.
* 2.3.0 Add support for Tor bridges (e.g. obfs4).
* 2.2.0 Add Tor control methods to get traffic read and written, fix config bug.
* 2.1.0 Allow override of executable paths (enables using tools from PATH).
* 2.0.1 Fix bug in Windows Privoxy zipped tool prefix (was "win32", should be "win32-").
* 2.0.0 Add support .NET Core on Linux.
* 2.0.0-beta1 Add support for .NET Core on Windows.
* 1.9.1 Fix null reference exception in TorControlClient.Dispose().
* 1.9.0 Add UseExistingTools and CheckForUpdatesAsync so that TorSharpToolFetcher can not download so much.
* 1.8.6 Improve error experience when one of the tool ZIP files is invalid.
* 1.8.5 Add ListenAddress to TorSharpPrivoxySettings to allow external connections.
* 1.8.4 Improve missing tool message and don't fail due to a SecurityProtocolType not being supported.
* 1.8.3 Ignore version directories that don't just have digits.
* 1.8.2 Enable three different ways of downloading Privoxy. Fastest one wins.
* 1.8.1 Use Privoxy RSS feed for fetching tools instead of SourceForge.
* 1.8.0 Add support for HTTPS proxy in Tor and organize TorSettings.
* 1.7.0 Default Tor DataDirectory to a path relative to the Tor executable.
* 1.6.2 Fix a bug where ToolRunnerType.VirtualDesktop was breaking on Windows 10 (version 1709).
* 1.6.1 Fix a bug in the Tor fetcher caused by Tor versions with no Windows build.
* 1.6.0 Add configuration API for tor exit nodes.
* 1.5.3 Fix P/Invoke stubs to work on x64 so ToolRunnerType.VirtualDesktop works.
* 1.5.2 Paths now fully work when they have spaces in them.
* 1.5.1 Fix bug where usernames with spaces in them are not supported.
* 1.5.0 Hash Tor passwords in process (by duplicating the hash algorithm).
* 1.4.0 Add tool runner without jobs, configure Tor data directory, fix file system race condition.
* 1.3.1 Fix dispose issue in TorControlClient.
* 1.3.0 Extract interfaces and rename ToolFetcher to TorSharpToolFetcher.
* 1.2.0 Add tool to download the latest Tor and Privoxy.
* 1.1.0 Target .NET 4.5 instead of .NET 4.5.2.
* 1.0.0 Initial release.