├── .gitattributes ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── Tor4NET.Sandbox ├── Program.cs └── Tor4NET.Sandbox.csproj ├── Tor4NET.sln ├── Tor4NET ├── Tor.cs ├── Tor │ ├── Circuits │ │ ├── Circuit.cs │ │ └── Enumerators │ │ │ ├── CircuitBuildFlags.cs │ │ │ ├── CircuitHSState.cs │ │ │ ├── CircuitPurpose.cs │ │ │ ├── CircuitReason.cs │ │ │ └── CircuitStatus.cs │ ├── Client.cs │ ├── ClientCreateParams.cs │ ├── ClientRemoteParams.cs │ ├── Configuration │ │ ├── Attributes │ │ │ └── ConfigurationAssocAttribute.cs │ │ ├── Configuration.cs │ │ └── Enumerators │ │ │ ├── ConfigurationNames.cs │ │ │ └── ConfigurationValidation.cs │ ├── Controller │ │ ├── Base │ │ │ ├── Command.cs │ │ │ └── Response.cs │ │ ├── Commands │ │ │ ├── CloseCircuitCommand.cs │ │ │ ├── CloseStreamCommand.cs │ │ │ ├── CreateCircuitCommand.cs │ │ │ ├── ExtendCircuitCommand.cs │ │ │ ├── GetAllRouterStatusCommand.cs │ │ │ ├── GetConfCommand.cs │ │ │ ├── GetInfoCommand.cs │ │ │ ├── GetRouterStatusCommand.cs │ │ │ ├── SaveConfCommand.cs │ │ │ ├── SetConfCommand.cs │ │ │ ├── SignalClearDNSCacheCommand.cs │ │ │ ├── SignalHaltCommand.cs │ │ │ └── SignalNewCircuitCommand.cs │ │ ├── Connection │ │ │ ├── Connection.cs │ │ │ └── ConnectionResponse.cs │ │ ├── Control.cs │ │ └── Enumerators │ │ │ └── StatusCode.cs │ ├── Core │ │ ├── Bytes.cs │ │ ├── Converters │ │ │ ├── BytesTypeConverter.cs │ │ │ ├── HostAuthTypeConverter.cs │ │ │ └── HostTypeConverter.cs │ │ ├── Enumerators │ │ │ ├── Auto.cs │ │ │ └── Bits.cs │ │ ├── Exceptions │ │ │ └── TorException.cs │ │ ├── Helpers │ │ │ ├── ReflectionHelper.cs │ │ │ └── StringHelper.cs │ │ ├── Host.cs │ │ └── HostAuth.cs │ ├── Events │ │ ├── Attributes │ │ │ └── EventAssocAttribute.cs │ │ ├── Base │ │ │ └── Dispatcher.cs │ │ ├── Dispatchers │ │ │ ├── BandwidthDispatcher.cs │ │ │ ├── CircuitDispatcher.cs │ │ │ ├── ConfigChangedDispatcher.cs │ │ │ ├── LogDispatcher.cs │ │ │ ├── ORConnectionDispatcher.cs │ │ │ └── StreamDispatcher.cs │ │ ├── Enumerators │ │ │ ├── Event.cs │ │ │ └── Events.cs │ │ ├── Event.cs │ │ ├── Events.cs │ │ └── Events │ │ │ ├── BandwidthEvent.cs │ │ │ ├── CircuitEvent.cs │ │ │ ├── ConfigurationChangedEvent.cs │ │ │ ├── LogEvent.cs │ │ │ ├── ORConnectionEvent.cs │ │ │ └── StreamEvent.cs │ ├── IO │ │ └── Socks5Stream.cs │ ├── Logging │ │ └── Logging.cs │ ├── Net │ │ ├── Processors │ │ │ └── Socks5Processor.cs │ │ └── Socket │ │ │ └── ForwardSocket.cs │ ├── ORConnections │ │ ├── Enumerators │ │ │ ├── ORReason.cs │ │ │ └── ORStatus.cs │ │ └── ORConnection.cs │ ├── Proxy │ │ ├── Connection │ │ │ └── Connection.cs │ │ ├── Processors │ │ │ ├── ConnectionProcessor.cs │ │ │ └── Socks5Processor.cs │ │ ├── Proxy.cs │ │ ├── Socket │ │ │ └── ForwardSocket.cs │ │ └── Socks5Proxy.cs │ ├── Routers │ │ ├── Enumerators │ │ │ └── RouterFlags.cs │ │ └── Router.cs │ ├── Status │ │ └── Status.cs │ └── Streams │ │ ├── Enumerators │ │ ├── StreamPurpose.cs │ │ ├── StreamReason.cs │ │ └── StreamStatus.cs │ │ └── Stream.cs ├── Tor4NET.csproj ├── TorUpdater.cs └── publish.bat └── icons ├── Tor4NET.png ├── Tor4NET.xcf ├── Tor4NET_icon.png └── Tor4NET_small.png /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015/2017 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # Visual Studio 2017 auto generated files 34 | Generated\ Files/ 35 | 36 | # MSTest test Results 37 | [Tt]est[Rr]esult*/ 38 | [Bb]uild[Ll]og.* 39 | 40 | # NUNIT 41 | *.VisualState.xml 42 | TestResult.xml 43 | 44 | # Build Results of an ATL Project 45 | [Dd]ebugPS/ 46 | [Rr]eleasePS/ 47 | dlldata.c 48 | 49 | # Benchmark Results 50 | BenchmarkDotNet.Artifacts/ 51 | 52 | # .NET Core 53 | project.lock.json 54 | project.fragment.lock.json 55 | artifacts/ 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_h.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *_wpftmp.csproj 81 | *.log 82 | *.vspscc 83 | *.vssscc 84 | .builds 85 | *.pidb 86 | *.svclog 87 | *.scc 88 | 89 | # Chutzpah Test files 90 | _Chutzpah* 91 | 92 | # Visual C++ cache files 93 | ipch/ 94 | *.aps 95 | *.ncb 96 | *.opendb 97 | *.opensdf 98 | *.sdf 99 | *.cachefile 100 | *.VC.db 101 | *.VC.VC.opendb 102 | 103 | # Visual Studio profiler 104 | *.psess 105 | *.vsp 106 | *.vspx 107 | *.sap 108 | 109 | # Visual Studio Trace Files 110 | *.e2e 111 | 112 | # TFS 2012 Local Workspace 113 | $tf/ 114 | 115 | # Guidance Automation Toolkit 116 | *.gpState 117 | 118 | # ReSharper is a .NET coding add-in 119 | _ReSharper*/ 120 | *.[Rr]e[Ss]harper 121 | *.DotSettings.user 122 | 123 | # JustCode is a .NET coding add-in 124 | .JustCode 125 | 126 | # TeamCity is a build add-in 127 | _TeamCity* 128 | 129 | # DotCover is a Code Coverage Tool 130 | *.dotCover 131 | 132 | # AxoCover is a Code Coverage Tool 133 | .axoCover/* 134 | !.axoCover/settings.json 135 | 136 | # Visual Studio code coverage results 137 | *.coverage 138 | *.coveragexml 139 | 140 | # NCrunch 141 | _NCrunch_* 142 | .*crunch*.local.xml 143 | nCrunchTemp_* 144 | 145 | # MightyMoose 146 | *.mm.* 147 | AutoTest.Net/ 148 | 149 | # Web workbench (sass) 150 | .sass-cache/ 151 | 152 | # Installshield output folder 153 | [Ee]xpress/ 154 | 155 | # DocProject is a documentation generator add-in 156 | DocProject/buildhelp/ 157 | DocProject/Help/*.HxT 158 | DocProject/Help/*.HxC 159 | DocProject/Help/*.hhc 160 | DocProject/Help/*.hhk 161 | DocProject/Help/*.hhp 162 | DocProject/Help/Html2 163 | DocProject/Help/html 164 | 165 | # Click-Once directory 166 | publish/ 167 | 168 | # Publish Web Output 169 | *.[Pp]ublish.xml 170 | *.azurePubxml 171 | # Note: Comment the next line if you want to checkin your web deploy settings, 172 | # but database connection strings (with potential passwords) will be unencrypted 173 | *.pubxml 174 | *.publishproj 175 | 176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 177 | # checkin your Azure Web App publish settings, but sensitive information contained 178 | # in these scripts will be unencrypted 179 | PublishScripts/ 180 | 181 | # NuGet Packages 182 | *.nupkg 183 | # The packages folder can be ignored because of Package Restore 184 | **/[Pp]ackages/* 185 | # except build/, which is used as an MSBuild target. 186 | !**/[Pp]ackages/build/ 187 | # Uncomment if necessary however generally it will be regenerated when needed 188 | #!**/[Pp]ackages/repositories.config 189 | # NuGet v3's project.json files produces more ignorable files 190 | *.nuget.props 191 | *.nuget.targets 192 | 193 | # Microsoft Azure Build Output 194 | csx/ 195 | *.build.csdef 196 | 197 | # Microsoft Azure Emulator 198 | ecf/ 199 | rcf/ 200 | 201 | # Windows Store app package directories and files 202 | AppPackages/ 203 | BundleArtifacts/ 204 | Package.StoreAssociation.xml 205 | _pkginfo.txt 206 | *.appx 207 | 208 | # Visual Studio cache files 209 | # files ending in .cache can be ignored 210 | *.[Cc]ache 211 | # but keep track of directories ending in .cache 212 | !*.[Cc]ache/ 213 | 214 | # Others 215 | ClientBin/ 216 | ~$* 217 | *~ 218 | *.dbmdl 219 | *.dbproj.schemaview 220 | *.jfm 221 | *.pfx 222 | *.publishsettings 223 | orleans.codegen.cs 224 | 225 | # Including strong name files can present a security risk 226 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 227 | #*.snk 228 | 229 | # Since there are multiple workflows, uncomment next line to ignore bower_components 230 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 231 | #bower_components/ 232 | 233 | # RIA/Silverlight projects 234 | Generated_Code/ 235 | 236 | # Backup & report files from converting an old project file 237 | # to a newer Visual Studio version. Backup files are not needed, 238 | # because we have git ;-) 239 | _UpgradeReport_Files/ 240 | Backup*/ 241 | UpgradeLog*.XML 242 | UpgradeLog*.htm 243 | ServiceFabricBackup/ 244 | *.rptproj.bak 245 | 246 | # SQL Server files 247 | *.mdf 248 | *.ldf 249 | *.ndf 250 | 251 | # Business Intelligence projects 252 | *.rdl.data 253 | *.bim.layout 254 | *.bim_*.settings 255 | *.rptproj.rsuser 256 | 257 | # Microsoft Fakes 258 | FakesAssemblies/ 259 | 260 | # GhostDoc plugin setting file 261 | *.GhostDoc.xml 262 | 263 | # Node.js Tools for Visual Studio 264 | .ntvs_analysis.dat 265 | node_modules/ 266 | 267 | # Visual Studio 6 build log 268 | *.plg 269 | 270 | # Visual Studio 6 workspace options file 271 | *.opt 272 | 273 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 274 | *.vbw 275 | 276 | # Visual Studio LightSwitch build output 277 | **/*.HTMLClient/GeneratedArtifacts 278 | **/*.DesktopClient/GeneratedArtifacts 279 | **/*.DesktopClient/ModelManifest.xml 280 | **/*.Server/GeneratedArtifacts 281 | **/*.Server/ModelManifest.xml 282 | _Pvt_Extensions 283 | 284 | # Paket dependency manager 285 | .paket/paket.exe 286 | paket-files/ 287 | 288 | # FAKE - F# Make 289 | .fake/ 290 | 291 | # JetBrains Rider 292 | .idea/ 293 | *.sln.iml 294 | 295 | # CodeRush personal settings 296 | .cr/personal 297 | 298 | # Python Tools for Visual Studio (PTVS) 299 | __pycache__/ 300 | *.pyc 301 | 302 | # Cake - Uncomment if you are using it 303 | # tools/** 304 | # !tools/packages.config 305 | 306 | # Tabs Studio 307 | *.tss 308 | 309 | # Telerik's JustMock configuration file 310 | *.jmconfig 311 | 312 | # BizTalk build output 313 | *.btp.cs 314 | *.btm.cs 315 | *.odx.cs 316 | *.xsd.cs 317 | 318 | # OpenCover UI analysis results 319 | OpenCover/ 320 | 321 | # Azure Stream Analytics local run output 322 | ASALocalRun/ 323 | 324 | # MSBuild Binary and Structured Log 325 | *.binlog 326 | 327 | # NVidia Nsight GPU debugger configuration file 328 | *.nvuser 329 | 330 | # MFractors (Xamarin productivity tool) working folder 331 | .mfractor/ 332 | 333 | # Local History for Visual Studio 334 | .localhistory/ 335 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: csharp 2 | solution: Tor4NET.sln 3 | mono: none 4 | dotnet: 2.1.809 5 | script: 6 | - dotnet build -c Debug 7 | - dotnet build -c Release -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Kamil Monicz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ![Zaczero/Tor4NET logo](https://github.com/Zaczero/Tor4NET/blob/master/icons/Tor4NET_small.png) 2 | 3 | [![Build Status](https://travis-ci.com/Zaczero/Tor4NET.svg?branch=master)](https://travis-ci.com/Zaczero/Tor4NET) 4 | [![GitHub Release](https://img.shields.io/github/v/release/Zaczero/Tor4NET)](https://github.com/Zaczero/Tor4NET/releases/latest) 5 | [![NuGet Release](https://img.shields.io/nuget/v/Tor4NET)](https://www.nuget.org/packages/Tor4NET/) 6 | [![License](https://img.shields.io/github/license/Zaczero/Tor4NET)](https://github.com/Zaczero/Tor4NET/blob/master/LICENSE) 7 | 8 | An all-in-one solution to fulfill your .NET dark web needs. 9 | 10 | Learn more about Tor [here](https://www.torproject.org/). 11 | This library is built over [Tor.NET](https://www.codeproject.com/Articles/1072864/%2fArticles%2f1072864%2fTor-NET-A-managed-Tor-network-library) *- thanks to Chris Copeland*. 12 | 13 | ## 🌤️ Installation 14 | 15 | ### Install with NuGet (recommended) 16 | 17 | `Install-Package Tor4NET` 18 | 19 | ### Install with dotnet 20 | 21 | `dotnet add PROJECT package Tor4NET` 22 | 23 | ### Install manually 24 | 25 | [Browse latest GitHub release](https://github.com/Zaczero/Tor4NET/releases/latest) 26 | 27 | ## 🏁 Getting started 28 | 29 | ### Sample code 30 | 31 | ```cs 32 | // Directory where Tor files are going to be stored. 33 | // If the directory does not exist, it will create one. 34 | var torDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Tor4NET"); 35 | 36 | // Use 64-bit Tor with 64-bit process. 37 | // It's *very* important for the architecture of Tor process match the one used by your app. 38 | // If no parameter is given Tor constructor will check Environment.Is64BitProcess property (the same one as below). 39 | var is32Bit = !Environment.Is64BitProcess; 40 | 41 | var tor = new Tor(torDirectory, is32Bit); 42 | 43 | // Check for updates and install latest version. 44 | if (tor.CheckForUpdates().Result) 45 | tor.Install().Wait(); 46 | 47 | // Disposing the client will exit the Tor process automatically. 48 | using (var client = tor.InitializeClient()) 49 | { 50 | var http = new WebClient 51 | { 52 | // And now let's use Tor as a proxy. 53 | Proxy = client.Proxy.WebProxy 54 | }; 55 | 56 | var html = http.DownloadString("http://facebookcorewwwi.onion"); 57 | } 58 | 59 | // Finally, you can remove all previously downloaded Tor files (optional). 60 | tor.Uninstall(); 61 | ``` 62 | 63 | ## Footer 64 | 65 | ### 📧 Contact 66 | 67 | * Email: [kamil@monicz.pl](mailto:kamil@monicz.pl) 68 | * PGP: [0x9D7BC5B97BB0A707](https://gist.github.com/Zaczero/158da01bfd5b6d236f2b8ceb62dd9698) 69 | 70 | ### 📃 License 71 | 72 | * [Zaczero/Tor4NET](https://github.com/Zaczero/Tor4NET/blob/master/LICENSE) 73 | * [Tor.NET](https://www.codeproject.com/info/cpol10.aspx) -------------------------------------------------------------------------------- /Tor4NET.Sandbox/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Net; 5 | 6 | namespace Tor4NET.Sandbox 7 | { 8 | public static class Program 9 | { 10 | public static void Main(string[] args) 11 | { 12 | // Directory where Tor files are going to be stored. 13 | // If the directory does not exist, it will create one. 14 | var torDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Tor4NET"); 15 | 16 | // Use 64-bit Tor with 64-bit process. 17 | // It's *very* important for the architecture of Tor process match the one used by your app. 18 | // If no parameter is given Tor constructor will check Environment.Is64BitProcess property (the same one as below). 19 | var is32Bit = !Environment.Is64BitProcess; 20 | 21 | var tor = new Tor(torDirectory, is32Bit); 22 | 23 | // Check for updates and install latest version. 24 | if (tor.CheckForUpdates().Result) 25 | tor.Install().Wait(); 26 | 27 | // Disposing the client will exit the Tor process automatically. 28 | using (var client = tor.InitializeClient()) 29 | { 30 | var http = new WebClient 31 | { 32 | // And now let's use Tor as a proxy. 33 | Proxy = client.Proxy.WebProxy 34 | }; 35 | 36 | var html = http.DownloadString("http://facebookcorewwwi.onion"); 37 | Debugger.Break(); 38 | } 39 | 40 | // Finally, you can remove all previously downloaded Tor files (optional). 41 | tor.Uninstall(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Tor4NET.Sandbox/Tor4NET.Sandbox.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Tor4NET.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.28407.52 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tor4NET", "Tor4NET\Tor4NET.csproj", "{93DC626F-2D7B-46ED-8C3D-08D61212E877}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tor4NET.Sandbox", "Tor4NET.Sandbox\Tor4NET.Sandbox.csproj", "{E51F2050-A7CB-4616-9E06-1F0948262153}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {93DC626F-2D7B-46ED-8C3D-08D61212E877}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {93DC626F-2D7B-46ED-8C3D-08D61212E877}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {93DC626F-2D7B-46ED-8C3D-08D61212E877}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {93DC626F-2D7B-46ED-8C3D-08D61212E877}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {E51F2050-A7CB-4616-9E06-1F0948262153}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {E51F2050-A7CB-4616-9E06-1F0948262153}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {E51F2050-A7CB-4616-9E06-1F0948262153}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {E51F2050-A7CB-4616-9E06-1F0948262153}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {0CFB1655-B1FA-41A3-9F0C-D514E98259A3} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Tor4NET/Tor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.IO.Compression; 5 | using System.Net; 6 | using System.Net.Http; 7 | using System.Security.Authentication; 8 | using System.Text.RegularExpressions; 9 | using System.Threading.Tasks; 10 | using Tor; 11 | 12 | namespace Tor4NET 13 | { 14 | public class Tor 15 | { 16 | private readonly Regex versionRegex = new Regex(@"Tor version (?\S+)"); 17 | private readonly TorUpdater torUpdater; 18 | 19 | private readonly string torDirectory; 20 | private readonly string torExecutable; 21 | 22 | private readonly int socksPort; 23 | private readonly int controlPort; 24 | private readonly string controlPassword; 25 | 26 | public Tor(string torDirectory, bool? x86 = null, int socksPort = 9450, int controlPort = 9451, string controlPassword = "") 27 | { 28 | if (!x86.HasValue) 29 | x86 = !Environment.Is64BitProcess; 30 | 31 | var httpHandler = new HttpClientHandler 32 | { 33 | AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, 34 | SslProtocols = SslProtocols.Tls11 | SslProtocols.Tls12, 35 | AllowAutoRedirect = false, 36 | }; 37 | 38 | var httpClient = new HttpClient(httpHandler); 39 | httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("Tor4NET (+https://github.com/Zaczero/Tor4NET)"); 40 | 41 | torUpdater = new TorUpdater(httpClient, x86.Value); 42 | 43 | this.torDirectory = torDirectory; 44 | torExecutable = $@"{this.torDirectory}\Tor\tor.exe"; 45 | 46 | this.socksPort = socksPort; 47 | this.controlPort = controlPort; 48 | this.controlPassword = controlPassword; 49 | } 50 | 51 | private bool IsTorRunning() 52 | { 53 | var torProcesses = Process.GetProcessesByName("tor"); 54 | 55 | foreach (var torProcess in torProcesses) 56 | { 57 | try 58 | { 59 | if (torProcess.MainModule.FileName == torExecutable) 60 | return true; 61 | } 62 | catch 63 | { } 64 | } 65 | 66 | return false; 67 | } 68 | 69 | private void KillTorProcess() 70 | { 71 | var torProcesses = Process.GetProcessesByName("tor"); 72 | 73 | foreach (var torProcess in torProcesses) 74 | { 75 | try 76 | { 77 | if (torProcess.MainModule.FileName == torExecutable) 78 | { 79 | torProcess.Kill(); 80 | torProcess.WaitForExit(); 81 | } 82 | } 83 | catch 84 | { } 85 | } 86 | } 87 | 88 | private async Task GetCurrentVersion() 89 | { 90 | if (!File.Exists(torExecutable)) 91 | return string.Empty; 92 | 93 | var psi = new ProcessStartInfo 94 | { 95 | FileName = torExecutable, 96 | Arguments = "--version", 97 | CreateNoWindow = true, 98 | UseShellExecute = false, 99 | RedirectStandardOutput = true, 100 | }; 101 | 102 | var process = Process.Start(psi); 103 | var output = await process.StandardOutput.ReadToEndAsync(); 104 | var match = versionRegex.Match(output); 105 | 106 | return match.Groups["version"].Value; 107 | } 108 | 109 | public async Task CheckForUpdates() 110 | { 111 | var currentVersion = await GetCurrentVersion(); 112 | if (currentVersion == string.Empty) 113 | return true; 114 | 115 | var (_, latestVersion) = await torUpdater.GetLatestVersion(); 116 | if (latestVersion == string.Empty) 117 | return false; 118 | 119 | return !currentVersion.Equals(latestVersion, StringComparison.Ordinal); 120 | } 121 | 122 | public async Task Install() 123 | { 124 | if (!Directory.Exists(torDirectory)) 125 | Directory.CreateDirectory(torDirectory); 126 | else 127 | KillTorProcess(); 128 | 129 | var updateZip = await torUpdater.DownloadUpdate(); 130 | var archive = new ZipArchive(updateZip); 131 | 132 | foreach (var entry in archive.Entries) 133 | { 134 | var path = $@"{torDirectory}\{entry.FullName}"; 135 | if (entry.CompressedLength == 0) 136 | { 137 | // Directory 138 | if (!Directory.Exists(path)) 139 | Directory.CreateDirectory(path); 140 | } 141 | else 142 | { 143 | // File 144 | var s = entry.Open(); 145 | var fs = new FileStream(path, FileMode.Create); 146 | 147 | await s.CopyToAsync(fs); 148 | 149 | fs.Dispose(); 150 | s.Dispose(); 151 | } 152 | } 153 | } 154 | 155 | public void Uninstall() 156 | { 157 | KillTorProcess(); 158 | 159 | if (Directory.Exists(torDirectory)) 160 | Directory.Delete(torDirectory, true); 161 | } 162 | 163 | public Client InitializeClient(bool killExistingTor = false) 164 | { 165 | Client client; 166 | 167 | if (!killExistingTor && IsTorRunning()) 168 | { 169 | var createParams = new ClientRemoteParams("127.0.0.1", controlPort, controlPassword); 170 | client = Client.CreateForRemote(createParams); 171 | } 172 | else 173 | { 174 | KillTorProcess(); 175 | 176 | var createParams = new ClientCreateParams(torExecutable, controlPort, controlPassword); 177 | client = Client.Create(createParams); 178 | } 179 | 180 | client.Configuration.ClientUseIPv6 = true; 181 | client.Configuration.HardwareAcceleration = true; 182 | client.Configuration.SocksPort = socksPort; 183 | client.Configuration.Save(); 184 | 185 | return client; 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Circuits/Circuit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Collections.ObjectModel; 6 | using Tor.Controller; 7 | using System.Net; 8 | using Tor.Helpers; 9 | using System.ComponentModel; 10 | 11 | namespace Tor 12 | { 13 | /// 14 | /// A class containing information regarding a circuit within the tor service. 15 | /// 16 | public sealed class Circuit : MarshalByRefObject 17 | { 18 | private readonly Client client; 19 | private readonly int id; 20 | private readonly object synchronize; 21 | 22 | private CircuitBuildFlags buildFlags; 23 | private CircuitHSState hsState; 24 | private List paths; 25 | private CircuitPurpose purpose; 26 | private CircuitReason reason; 27 | private RouterCollection routers; 28 | private CircuitStatus status; 29 | private DateTime timeCreated; 30 | 31 | /// 32 | /// Initializes a new instance of the class. 33 | /// 34 | /// The client for which the circuit belongs. 35 | /// The unique identifier of the circuit within the tor session. 36 | internal Circuit(Client client, int id) 37 | { 38 | this.buildFlags = CircuitBuildFlags.None; 39 | this.client = client; 40 | this.hsState = CircuitHSState.None; 41 | this.id = id; 42 | this.paths = new List(); 43 | this.purpose = CircuitPurpose.None; 44 | this.reason = CircuitReason.None; 45 | this.synchronize = new object(); 46 | this.timeCreated = DateTime.MinValue; 47 | } 48 | 49 | #region Properties 50 | 51 | /// 52 | /// Gets the build flags associated with the circuit. 53 | /// 54 | public CircuitBuildFlags BuildFlags 55 | { 56 | get { return buildFlags; } 57 | internal set { buildFlags = value; } 58 | } 59 | 60 | /// 61 | /// Gets the hidden-service state of the circuit. 62 | /// 63 | public CircuitHSState HSState 64 | { 65 | get { return hsState; } 66 | internal set { hsState = value; } 67 | } 68 | 69 | /// 70 | /// Gets the unique identifier of the circuit in the tor session. 71 | /// 72 | public int ID 73 | { 74 | get { return id; } 75 | } 76 | 77 | /// 78 | /// Gets the purpose of the circuit. 79 | /// 80 | public CircuitPurpose Purpose 81 | { 82 | get { return purpose; } 83 | internal set { purpose = value; } 84 | } 85 | 86 | /// 87 | /// Gets the reason associated with the circuit, usually assigned upon closed or failed events. 88 | /// 89 | public CircuitReason Reason 90 | { 91 | get { return reason; } 92 | internal set { reason = value; } 93 | } 94 | 95 | /// 96 | /// Gets the routers associated with the circuit. 97 | /// 98 | public RouterCollection Routers 99 | { 100 | get { return routers; } 101 | } 102 | 103 | /// 104 | /// Gets the status of the circuit. 105 | /// 106 | public CircuitStatus Status 107 | { 108 | get { return status; } 109 | internal set { status = value; } 110 | } 111 | 112 | /// 113 | /// Gets the date and time the circuit was created. 114 | /// 115 | public DateTime TimeCreated 116 | { 117 | get { return timeCreated; } 118 | internal set { timeCreated = value; } 119 | } 120 | 121 | /// 122 | /// Gets or sets the collection containing the paths associated with the circuit. 123 | /// 124 | internal List Paths 125 | { 126 | get { lock (synchronize) return paths; } 127 | set { lock (synchronize) paths = value; } 128 | } 129 | 130 | #endregion 131 | 132 | /// 133 | /// Sends a request to the associated tor client to close the circuit. 134 | /// 135 | /// true if the circuit is closed successfully; otherwise, false. 136 | public bool Close() 137 | { 138 | return client.Controller.CloseCircuit(this); 139 | } 140 | 141 | /// 142 | /// Sends a request to the associated tor client to extend the circuit. 143 | /// 144 | /// The list of identities or nicknames to extend onto this circuit. 145 | /// true if the circuit is extended successfully; otherwise, false. 146 | public bool Extend(params string[] routers) 147 | { 148 | return client.Controller.ExtendCircuit(this, routers); 149 | } 150 | 151 | /// 152 | /// Sends a request to the associated tor client to extend the circuit. 153 | /// 154 | /// The list of routers to extend onto this circuit. 155 | /// true if the circuit is extended successfully; otherwise, false. 156 | public bool Extend(params Router[] routers) 157 | { 158 | string[] nicknames = new string[routers.Length]; 159 | 160 | for (int i = 0, length = routers.Length; i < length; i++) 161 | nicknames[i] = routers[i].Nickname; 162 | 163 | return client.Controller.ExtendCircuit(this, nicknames); 164 | } 165 | 166 | /// 167 | /// Gets the routers associated with the circuit. 168 | /// 169 | /// A object instance. 170 | internal RouterCollection GetRouters() 171 | { 172 | lock (synchronize) 173 | { 174 | List routers = new List(); 175 | 176 | if (paths == null || paths.Count == 0) 177 | { 178 | this.routers = new RouterCollection(routers); 179 | return this.routers; 180 | } 181 | 182 | foreach (string path in paths) 183 | { 184 | string trimmed = path; 185 | 186 | if (trimmed == null) 187 | continue; 188 | 189 | if (trimmed.StartsWith("$")) 190 | trimmed = trimmed.Substring(1); 191 | if (trimmed.Contains("~")) 192 | trimmed = trimmed.Substring(0, trimmed.IndexOf("~")); 193 | 194 | if (string.IsNullOrWhiteSpace(trimmed)) 195 | continue; 196 | 197 | GetRouterStatusCommand command = new GetRouterStatusCommand(trimmed); 198 | GetRouterStatusResponse response = command.Dispatch(client); 199 | 200 | if (response.Success && response.Router != null) 201 | routers.Add(response.Router); 202 | } 203 | 204 | this.routers = new RouterCollection(routers); 205 | return this.routers; 206 | } 207 | } 208 | } 209 | 210 | /// 211 | /// A class containing a read-only collection of objects. 212 | /// 213 | public sealed class CircuitCollection : ReadOnlyCollection 214 | { 215 | /// 216 | /// Initializes a new instance of the class. 217 | /// 218 | /// The list of circuits. 219 | internal CircuitCollection(IList list) : base(list) 220 | { 221 | } 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Circuits/Enumerators/CircuitBuildFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | namespace Tor 8 | { 9 | /// 10 | /// An enumerator containing the possible values specified against the BUILD_FLAGS parameter. 11 | /// 12 | [Flags] 13 | public enum CircuitBuildFlags : int 14 | { 15 | /// 16 | /// No build flags were specified. 17 | /// 18 | [Description(null)] 19 | None = 0x000, 20 | 21 | /// 22 | /// The circuit is a one hop circuit used to fetch directory information. 23 | /// 24 | [Description("ONEHOP_TUNNEL")] 25 | OneHopTunnel = 0x001, 26 | 27 | /// 28 | /// The circuit will not be used for client traffic. 29 | /// 30 | [Description("IS_INTERNAL")] 31 | IsInternal = 0x002, 32 | 33 | /// 34 | /// The circuit only includes high capacity relays. 35 | /// 36 | [Description("NEED_CAPACITY")] 37 | NeedCapacity = 0x004, 38 | 39 | /// 40 | /// The circuit only includes relays with high uptime. 41 | /// 42 | [Description("NEED_UPTIME")] 43 | NeedUpTime = 0x008, 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Circuits/Enumerators/CircuitHSState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | namespace Tor 8 | { 9 | /// 10 | /// An enumerator containing the possible values specified against the HS_STATE parameter. The HS_STATE indicates the 11 | /// different states that a hidden service circuit may have. 12 | /// 13 | public enum CircuitHSState 14 | { 15 | /// 16 | /// No hidden service state was provided. 17 | /// 18 | [Description(null)] 19 | None, 20 | 21 | /// 22 | /// The client-side hidden service is connecting to the introductory point. 23 | /// 24 | [Description("HSCI_CONNECTING")] 25 | HSCIConnecting, 26 | 27 | /// 28 | /// The client-side hidden service has sent INTRODUCE1 and is awaiting a reply. 29 | /// 30 | [Description("HSCI_INTRO_SENT")] 31 | HSCIIntroSent, 32 | 33 | /// 34 | /// The client-side hidden service has received a reply and the circuit is closing. 35 | /// 36 | [Description("HSCI_DONE")] 37 | HSCIDone, 38 | 39 | /// 40 | /// The client-side hidden service is connecting to the rendezvous point. 41 | /// 42 | [Description("HSCR_CONNECTING")] 43 | HSCRConnecting, 44 | 45 | /// 46 | /// The client-side hidden servicce has established connection to the rendezvous point and is awaiting an introduction. 47 | /// 48 | [Description("HSCR_ESTABLISHED_IDLE")] 49 | HSCREstablishedIdle, 50 | 51 | /// 52 | /// The client-side hidden service has received an introduction and is awaiting a rend. 53 | /// 54 | [Description("HSCR_ESTABLISHED_WAITING")] 55 | HSCREstablishedWaiting, 56 | 57 | /// 58 | /// The client-side hidden service is connected to the hidden service. 59 | /// 60 | [Description("HSCR_JOINED")] 61 | HSCRJoined, 62 | 63 | /// 64 | /// The server-side hidden service is connecting to the introductory point. 65 | /// 66 | [Description("HSSI_CONNECTING")] 67 | HSSIConnecting, 68 | 69 | /// 70 | /// The server-side hidden service has established connection to the introductory point. 71 | /// 72 | [Description("HSSI_ESTABLISHED")] 73 | HSSIEstablished, 74 | 75 | /// 76 | /// The server-side hidden service is connecting to the rendezvous point. 77 | /// 78 | [Description("HSSR_CONNECTING")] 79 | HSSRConnecting, 80 | 81 | /// 82 | /// The server-side hidden service has established connection to the rendezvous point. 83 | /// 84 | [Description("HSSR_JOINED")] 85 | HSSRJoined, 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Circuits/Enumerators/CircuitPurpose.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | namespace Tor 8 | { 9 | /// 10 | /// An enumerator containing the possible values specified against the PURPOSE parameter. 11 | /// 12 | public enum CircuitPurpose 13 | { 14 | /// 15 | /// No purpose parameter was specified. 16 | /// 17 | [Description(null)] 18 | None, 19 | 20 | /// 21 | /// The circuit is intended for traffic or fetching directory information. 22 | /// 23 | [Description("GENERAL")] 24 | General, 25 | 26 | /// 27 | /// The circuit is a client-side introduction point for a hidden service circuit. 28 | /// 29 | [Description("HS_CLIENT_INTRO")] 30 | HSClientIntro, 31 | 32 | /// 33 | /// The circuit is a client-side hidden service rendezvous circuit. 34 | /// 35 | [Description("HS_CLIENT_REND")] 36 | HSClientRend, 37 | 38 | /// 39 | /// The circuit is a server-side introduction point for a hidden service circuit. 40 | /// 41 | [Description("HS_SERVICE_INTRO")] 42 | HSServiceIntro, 43 | 44 | /// 45 | /// The circuit is a server-side hidden service rendezvous circuit. 46 | /// 47 | [Description("HS_SERVICE_REND")] 48 | HSServiceRend, 49 | 50 | /// 51 | /// The circuit is a test circuit to verify that the service can be used as a relay. 52 | /// 53 | [Description("TESTING")] 54 | Testing, 55 | 56 | /// 57 | /// The circuit was built by a controller. 58 | /// 59 | [Description("CONTROLLER")] 60 | Controller, 61 | 62 | /// 63 | /// The circuit was built to measure the time taken. 64 | /// 65 | [Description("MEASURE_TIMEOUT")] 66 | MeasureTimeout, 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Circuits/Enumerators/CircuitReason.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | namespace Tor 8 | { 9 | /// 10 | /// An enumerator containing the possible values for a field which uses the REASON parameter. 11 | /// 12 | public enum CircuitReason 13 | { 14 | /// 15 | /// No reason was provided. 16 | /// 17 | [Description(null)] 18 | None, 19 | 20 | /// 21 | /// There was a violation in the Tor protocol. 22 | /// 23 | [Description("TORPROTOCOL")] 24 | TorProtocol, 25 | 26 | /// 27 | /// There was an internal error. 28 | /// 29 | [Description("INTERNAL")] 30 | Internal, 31 | 32 | /// 33 | /// Requested by the client via a TRUNCATE command. 34 | /// 35 | [Description("REQUESTED")] 36 | Requested, 37 | 38 | /// 39 | /// The relay is currently hibernating. 40 | /// 41 | [Description("HIBERNATING")] 42 | Hibernating, 43 | 44 | /// 45 | /// The relay is out of memory, sockets, or circuit IDs. 46 | /// 47 | [Description("RESOURCELIMIT")] 48 | ResourceLimit, 49 | 50 | /// 51 | /// Unable to contact the relay. 52 | /// 53 | [Description("CONNECTFAILED")] 54 | ConnectFailed, 55 | 56 | /// 57 | /// The relay had the wrong OR identification. 58 | /// 59 | [Description("OR_IDENTITY")] 60 | ORIdentity, 61 | 62 | /// 63 | /// The connection failed after being established. 64 | /// 65 | [Description("OR_CONN_CLOSED")] 66 | ORConnectionClosed, 67 | 68 | /// 69 | /// The circuit has expired. 70 | /// 71 | [Description("FINISHED")] 72 | Finished, 73 | 74 | /// 75 | /// The circuit construction timed out. 76 | /// 77 | [Description("TIMEOUT")] 78 | Timeout, 79 | 80 | /// 81 | /// The circuit was unexpectedly closed. 82 | /// 83 | [Description("DESTROYED")] 84 | Destroyed, 85 | 86 | /// 87 | /// There are not enough relays to make a circuit. 88 | /// 89 | [Description("NOPATH")] 90 | NoPath, 91 | 92 | /// 93 | /// The requested hidden service does not exist. 94 | /// 95 | [Description("NOSUCHSERVICE")] 96 | NoSuchService, 97 | 98 | /// 99 | /// The circuit construction timed out, except that the circuit was left open for measurement purposes. 100 | /// 101 | [Description("MEASUREMENT_EXPIRED")] 102 | MeasurementExpired, 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Circuits/Enumerators/CircuitStatus.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | namespace Tor 8 | { 9 | /// 10 | /// An enumerator containing the possible statuses of a circuit. 11 | /// 12 | public enum CircuitStatus 13 | { 14 | /// 15 | /// The circuit ID was assigned to a new circuit. 16 | /// 17 | [Description("LAUNCHED")] 18 | Launched, 19 | 20 | /// 21 | /// The circuit has completed all hops and can accept streams. 22 | /// 23 | [Description("BUILT")] 24 | Built, 25 | 26 | /// 27 | /// The circuit has been extended with an additional hop. 28 | /// 29 | [Description("EXTENDED")] 30 | Extended, 31 | 32 | /// 33 | /// The circuit is closed because it was not built. 34 | /// 35 | [Description("FAILED")] 36 | Failed, 37 | 38 | /// 39 | /// The circuit is closed. 40 | /// 41 | [Description("CLOSED")] 42 | Closed 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Tor4NET/Tor/ClientRemoteParams.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Diagnostics; 6 | 7 | namespace Tor 8 | { 9 | /// 10 | /// A class containing the configurations needed to connect to a remotely hosted tor application executable. 11 | /// 12 | [DebuggerStepThrough] 13 | [Serializable] 14 | public sealed class ClientRemoteParams 15 | { 16 | private string address; 17 | private string controlPassword; 18 | private int controlPort; 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | public ClientRemoteParams() : this(null, 9051, "") 24 | { 25 | } 26 | 27 | /// 28 | /// Initializes a new instance of the class. 29 | /// 30 | /// The address of the hosted tor application. 31 | public ClientRemoteParams(string address) : this(address, 9051, "") 32 | { 33 | } 34 | 35 | /// 36 | /// Initializes a new instance of the class. 37 | /// 38 | /// The address of the hosted tor application. 39 | /// The port number which the application will listening on for control connections. 40 | public ClientRemoteParams(string address, int controlPort) : this(address, controlPort, "") 41 | { 42 | } 43 | 44 | /// 45 | /// Initializes a new instance of the class. 46 | /// 47 | /// The address of the hosted tor application. 48 | /// The port number which the application will listening on for control connections. 49 | /// The password used when authenticating with the control connection. 50 | public ClientRemoteParams(string address, int controlPort, string controlPassword) 51 | { 52 | this.address = address; 53 | this.controlPassword = controlPassword; 54 | this.controlPort = controlPort; 55 | } 56 | 57 | #region Properties 58 | 59 | /// 60 | /// Gets or sets the address of the hosted tor application. 61 | /// 62 | public string Address 63 | { 64 | get { return address; } 65 | set { address = value; } 66 | } 67 | 68 | /// 69 | /// Gets or sets the password used when authenticating with the tor application on the control connection. A value of 70 | /// null or blank indicates that no password has been configured. 71 | /// 72 | public string ControlPassword 73 | { 74 | get { return controlPassword; } 75 | set { controlPassword = value; } 76 | } 77 | 78 | /// 79 | /// Gets or sets the port number which the application will be listening on for control connections. 80 | /// 81 | public int ControlPort 82 | { 83 | get { return controlPort; } 84 | set { controlPort = value; } 85 | } 86 | 87 | #endregion 88 | 89 | /// 90 | /// Validates the parameters assigned to the object, and throws relevant exceptions where necessary. 91 | /// 92 | internal void ValidateParameters() 93 | { 94 | if (string.IsNullOrWhiteSpace(address)) 95 | throw new TorException("The address cannot be null or white-space"); 96 | if (controlPort <= 0 || short.MaxValue < controlPort) 97 | throw new TorException("The control port number must be within a valid port range"); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Configuration/Attributes/ConfigurationAssocAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Config 7 | { 8 | /// 9 | /// Specifies the associated tor configuration name against an enumerator value. 10 | /// 11 | [AttributeUsage(AttributeTargets.Field)] 12 | internal sealed class ConfigurationAssocAttribute : Attribute 13 | { 14 | private readonly string name; 15 | 16 | private object defaultValue; 17 | private Type type; 18 | private ConfigurationValidation validation; 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The name of the configuration within the tor torrc configuration file. 24 | public ConfigurationAssocAttribute(string name) 25 | { 26 | this.defaultValue = null; 27 | this.name = name; 28 | this.type = null; 29 | this.validation = ConfigurationValidation.None; 30 | } 31 | 32 | #region Properties 33 | 34 | /// 35 | /// Gets or sets the default value of the configuration. 36 | /// 37 | public object Default 38 | { 39 | get { return defaultValue; } 40 | set { defaultValue = value; } 41 | } 42 | 43 | /// 44 | /// Gets the name of the configuration within the tor torrc configuration file. 45 | /// 46 | public string Name 47 | { 48 | get { return name; } 49 | } 50 | 51 | /// 52 | /// Gets or sets the type of value expected for the configuration. 53 | /// 54 | public Type Type 55 | { 56 | get { return type; } 57 | set { type = value; } 58 | } 59 | 60 | /// 61 | /// Gets or sets the validation to perform against the configuration value. 62 | /// 63 | public ConfigurationValidation Validation 64 | { 65 | get { return validation; } 66 | set { validation = value; } 67 | } 68 | 69 | #endregion 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Configuration/Enumerators/ConfigurationNames.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Config 7 | { 8 | /// 9 | /// An enumerator containing a list of configurations which can be assigned and retrieved. 10 | /// 11 | public enum ConfigurationNames 12 | { 13 | [ConfigurationAssoc("AllowDotExit", Default = false, Type = typeof(bool))] 14 | AllowDotExit, 15 | 16 | [ConfigurationAssoc("AllowNonRFC953HostNames", Default = false, Type = typeof(bool))] 17 | AllowNonRFC953HostNames, 18 | 19 | [ConfigurationAssoc("AvoidDiskWrites", Default = false, Type = typeof(bool))] 20 | AvoidDiskWrites, 21 | 22 | [ConfigurationAssoc("BandwidthRate", Default = 1099511627776.0, Type = typeof(Bytes), Validation = ConfigurationValidation.NonNull | ConfigurationValidation.SizeDivision)] 23 | BandwidthRate, 24 | 25 | [ConfigurationAssoc("CircuitBuildTimeout", Default = 60, Type = typeof(int), Validation = ConfigurationValidation.Positive)] 26 | CircuitBuildTimeout, 27 | 28 | [ConfigurationAssoc("CircuitIdleTimeout", Default = 3600, Type = typeof(int), Validation = ConfigurationValidation.Positive)] 29 | CircuitIdleTimeout, 30 | 31 | [ConfigurationAssoc("ClientPreferIPv6ORPort", Default = false, Type = typeof(bool))] 32 | ClientPreferIPv6ORPort, 33 | 34 | [ConfigurationAssoc("ClientUseIPv6", Default = false, Type = typeof(bool))] 35 | ClientUseIPv6, 36 | 37 | [ConfigurationAssoc("ControlPort", Default = 9051, Type = typeof(int), Validation = ConfigurationValidation.PortRange)] 38 | ControlPort, 39 | 40 | [ConfigurationAssoc("ConstrainedSockets", Default = false, Type = typeof(bool))] 41 | ConstrainedSockets, 42 | 43 | [ConfigurationAssoc("ConstrainedSockSize", Default = 8388608.0, Type = typeof(Bytes), Validation = ConfigurationValidation.NonNull | ConfigurationValidation.SizeDivision)] 44 | ConstrainedSockSize, 45 | 46 | [ConfigurationAssoc("DisableNetwork", Default = false, Type = typeof(bool))] 47 | DisableNetwork, 48 | 49 | [ConfigurationAssoc("EnforceDistinctSubnets", Default = true, Type = typeof(bool))] 50 | EnforceDistinctSubnets, 51 | 52 | [ConfigurationAssoc("ExcludeSingleHopRelays", Default = true, Type = typeof(bool))] 53 | ExcludeSingleHopRelays, 54 | 55 | [ConfigurationAssoc("FascistFirewall", Default = false, Type = typeof(bool))] 56 | FascistFirewall, 57 | 58 | [ConfigurationAssoc("FastFirstHopPK", Default = Auto.Auto, Type = typeof(Auto))] 59 | FastFirstHopPK, 60 | 61 | [ConfigurationAssoc("GeoIPFile", Default = null, Type = typeof(string))] 62 | GeoIPFile, 63 | 64 | [ConfigurationAssoc("GeoIPv6File", Default = null, Type = typeof(string))] 65 | GeoIPv6File, 66 | 67 | [ConfigurationAssoc("HardwareAccel", Default = false, Type = typeof(bool))] 68 | HardwareAcceleration, 69 | 70 | [ConfigurationAssoc("HashedControlPassword", Default = "", Type = typeof(string), Validation = ConfigurationValidation.NonNull)] 71 | HashedControlPassword, 72 | 73 | [ConfigurationAssoc("HTTPProxy", Type = typeof(Host))] 74 | HTTPProxy, 75 | 76 | [ConfigurationAssoc("HTTPProxyAuthenticator", Type = typeof(HostAuth))] 77 | HTTPProxyAuthenticator, 78 | 79 | [ConfigurationAssoc("HTTPSProxy", Type = typeof(Host))] 80 | HTTPSProxy, 81 | 82 | [ConfigurationAssoc("HTTPSProxyAuthenticator", Type = typeof(HostAuth))] 83 | HTTPSProxyAuthenticator, 84 | 85 | [ConfigurationAssoc("KeepalivePeriod", Default = 300, Type = typeof(int), Validation = ConfigurationValidation.Positive)] 86 | KeepAlivePeriod, 87 | 88 | [ConfigurationAssoc("LearnCircuitBuildTimeout", Default = true, Type = typeof(bool))] 89 | LearnCircuitBuildTimeout, 90 | 91 | [ConfigurationAssoc("MaxCircuitDirtiness", Default = 600, Type = typeof(int), Validation = ConfigurationValidation.Positive)] 92 | MaxCircuitDirtiness, 93 | 94 | [ConfigurationAssoc("MaxClientCircuitsPending", Default = 32, Type = typeof(int), Validation = ConfigurationValidation.Positive)] 95 | MaxClientCircuitsPending, 96 | 97 | [ConfigurationAssoc("NewCircuitPeriod", Default = 30, Type = typeof(int), Validation = ConfigurationValidation.Positive)] 98 | NewCircuitPeriod, 99 | 100 | [ConfigurationAssoc("OptimisticData", Default = Auto.Auto, Type = typeof(Auto))] 101 | OptimisticData, 102 | 103 | [ConfigurationAssoc("SafeSocks", Default = false, Type = typeof(bool))] 104 | SafeSocks, 105 | 106 | [ConfigurationAssoc("SocksPort", Default = 9051, Type = typeof(int), Validation = ConfigurationValidation.PortRange)] 107 | SocksPort, 108 | 109 | [ConfigurationAssoc("SocksTimeout", Default = 120, Type = typeof(int), Validation = ConfigurationValidation.Positive)] 110 | SocksTimeout, 111 | 112 | [ConfigurationAssoc("UseMicrodescriptors", Default = Auto.Auto, Type = typeof(Auto))] 113 | UseMicroDescriptors 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Configuration/Enumerators/ConfigurationValidation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Config 7 | { 8 | /// 9 | /// An enumerator containing the different validation methods to perform against a configuration value. 10 | /// 11 | [Flags] 12 | internal enum ConfigurationValidation : int 13 | { 14 | /// 15 | /// No validation should be performed. 16 | /// 17 | None = 0x000, 18 | 19 | /// 20 | /// Ensure that the value is not null. 21 | /// 22 | NonNull = 0x001, 23 | 24 | /// 25 | /// Ensure that the value is non-negative. 26 | /// 27 | NonNegative = 0x002, 28 | 29 | /// 30 | /// Ensure that the value is non-zero. 31 | /// 32 | NonZero = 0x004, 33 | 34 | /// 35 | /// Ensure that the value falls within the range of valid port numbers. 36 | /// 37 | PortRange = 0x008, 38 | 39 | /// 40 | /// Ensure that the value is divisible by 1024. 41 | /// 42 | SizeDivision = 0x010, 43 | 44 | /// 45 | /// Ensure that the value is positive and non-zero. 46 | /// 47 | Positive = NonNegative | NonZero 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Base/Command.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Diagnostics; 6 | 7 | namespace Tor.Controller 8 | { 9 | /// 10 | /// A class containing the base methods and properties for a command which will be executed across a control connection, 11 | /// and will return a response corresponding to the response of the tor application. 12 | /// 13 | internal abstract class Command where T : Response 14 | { 15 | /// 16 | /// Creates a new object instance and dispatches the command to the specified client. 17 | /// 18 | /// The type of the command. 19 | /// The type of the response generated from the command. 20 | /// The client hosting the control connection port. 21 | /// true if the command was created and dispatched successfully; otherwise, false. 22 | public static bool DispatchAndReturn(Client client) where TCommand : Command 23 | { 24 | try 25 | { 26 | TCommand command = Activator.CreateInstance(); 27 | 28 | if (command == null) 29 | return false; 30 | 31 | T response = command.Dispatch(client); 32 | return response.Success; 33 | } 34 | catch 35 | { 36 | return false; 37 | } 38 | } 39 | 40 | /// 41 | /// Dispatches the command to the client control port and produces a response result. 42 | /// 43 | /// The client hosting the control connection port. 44 | /// A object instance containing the response data. 45 | public T Dispatch(Client client) 46 | { 47 | if (client == null) 48 | throw new ArgumentNullException("client"); 49 | if (!client.IsRunning) 50 | throw new TorException("A command cannot be dispatched to a client which is no longer running"); 51 | 52 | try 53 | { 54 | using (Connection connection = new Connection(client)) 55 | { 56 | if (!connection.Connect()) 57 | throw new TorException("A command could not be dispatched to a client because the command failed to connect to the control port"); 58 | 59 | if (!connection.Authenticate(client.GetControlPassword())) 60 | throw new TorException("A command could not be dispatched to a client because the control could not be authenticated"); 61 | 62 | return Dispatch(connection); 63 | } 64 | } 65 | catch (Exception exception) 66 | { 67 | throw new TorException("A command could not be dispatched to a client because an error occurred", exception); 68 | } 69 | } 70 | 71 | /// 72 | /// Dispatches the command to the client control port and produces a response result. 73 | /// 74 | /// The control connection where the command should be dispatched. 75 | /// A object instance containing the response data. 76 | protected abstract T Dispatch(Connection connection); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Base/Response.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Controller 7 | { 8 | /// 9 | /// A class containing information regarding the response received back through the control connection after receiving a command from a client. 10 | /// 11 | internal class Response 12 | { 13 | private readonly bool success; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// A value indicating whether the command was received and processed successfully. 19 | public Response(bool success) 20 | { 21 | this.success = success; 22 | } 23 | 24 | #region Properties 25 | 26 | /// 27 | /// Gets a value indicating whether the command was received and processed successfully. 28 | /// 29 | public bool Success 30 | { 31 | get { return success; } 32 | } 33 | 34 | #endregion 35 | } 36 | 37 | /// 38 | /// A class containing a collection of mapped, to key-value pairs, as 39 | /// expected from certain commands dispatched to a control connection. 40 | /// 41 | internal sealed class ResponsePairs : Dictionary 42 | { 43 | /// 44 | /// Initializes a new instance of the class. 45 | /// 46 | public ResponsePairs() 47 | { 48 | } 49 | 50 | /// 51 | /// Initializes a new instance of the class. 52 | /// 53 | /// The initial number of elements that the can contain. 54 | public ResponsePairs(int capacity) : base(capacity) 55 | { 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Commands/CloseCircuitCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Controller 7 | { 8 | /// 9 | /// A class containing the command to close an existing circuit. 10 | /// 11 | internal sealed class CloseCircuitCommand : Command 12 | { 13 | private readonly Circuit circuit; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The circuit which should be closed. 19 | public CloseCircuitCommand(Circuit circuit) 20 | { 21 | this.circuit = circuit; 22 | } 23 | 24 | #region Tor.Controller.Command<> 25 | 26 | /// 27 | /// Dispatches the command to the client control port and produces a response result. 28 | /// 29 | /// The control connection where the command should be dispatched. 30 | /// 31 | /// A object instance containing the response data. 32 | /// 33 | protected override Response Dispatch(Connection connection) 34 | { 35 | if (circuit == null || circuit.Status == CircuitStatus.Closed) 36 | return new Response(false); 37 | 38 | if (connection.Write("closecircuit {0}", circuit.ID)) 39 | { 40 | ConnectionResponse response = connection.Read(); 41 | return new Response(response.Success); 42 | } 43 | 44 | return new Response(false); 45 | } 46 | 47 | #endregion 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Commands/CloseStreamCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Tor.Helpers; 6 | 7 | namespace Tor.Controller 8 | { 9 | /// 10 | /// A class containing the command to close an existing stream. 11 | /// 12 | internal sealed class CloseStreamCommand : Command 13 | { 14 | private readonly StreamReason reason; 15 | private readonly Stream stream; 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// The stream which should be closed. 21 | /// The reason for the stream being closed. 22 | public CloseStreamCommand(Stream stream, StreamReason reason) 23 | { 24 | this.reason = reason; 25 | this.stream = stream; 26 | } 27 | 28 | #region Tor.Controller.Command<> 29 | 30 | /// 31 | /// Dispatches the command to the client control port and produces a response result. 32 | /// 33 | /// The control connection where the command should be dispatched. 34 | /// 35 | /// A object instance containing the response data. 36 | /// 37 | protected override Response Dispatch(Connection connection) 38 | { 39 | if (stream == null || stream.ID <= 0) 40 | return new Response(false); 41 | if (stream.Status == StreamStatus.Failed || stream.Status == StreamStatus.Closed) 42 | return new Response(false); 43 | if (reason == StreamReason.None || reason == StreamReason.PrivateAddr || reason == StreamReason.End) 44 | return new Response(false); 45 | 46 | if (connection.Write("closestream {0} {1}", stream.ID, (int)reason)) 47 | { 48 | ConnectionResponse response = connection.Read(); 49 | return new Response(response.Success); 50 | } 51 | 52 | return new Response(false); 53 | } 54 | 55 | #endregion 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Commands/CreateCircuitCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Tor.Helpers; 6 | 7 | namespace Tor.Controller 8 | { 9 | /// 10 | /// A class containing the command to create a new circuit. 11 | /// 12 | internal sealed class CreateCircuitCommand : Command 13 | { 14 | private readonly List routers; 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | public CreateCircuitCommand() 20 | { 21 | this.routers = new List(); 22 | } 23 | 24 | /// 25 | /// Initializes a new instance of the class. 26 | /// 27 | /// The collection of routers which should be part of this circuit. 28 | public CreateCircuitCommand(IEnumerable routers) 29 | { 30 | this.routers = new List(routers); 31 | } 32 | 33 | #region Properties 34 | 35 | /// 36 | /// Gets a collection containing the list of routers which should be comprise this circuit. 37 | /// 38 | public List Routers 39 | { 40 | get { return routers; } 41 | } 42 | 43 | #endregion 44 | 45 | #region Tor.Controller.Command<> 46 | 47 | /// 48 | /// Dispatches the command to the client control port and produces a response result. 49 | /// 50 | /// The control connection where the command should be dispatched. 51 | /// 52 | /// A object instance containing the response data. 53 | /// 54 | protected override CreateCircuitResponse Dispatch(Connection connection) 55 | { 56 | StringBuilder builder = new StringBuilder("extendcircuit 0"); 57 | 58 | foreach (string router in routers) 59 | { 60 | builder.Append(' '); 61 | builder.Append(router); 62 | } 63 | 64 | if (connection.Write(builder.ToString())) 65 | { 66 | ConnectionResponse response = connection.Read(); 67 | 68 | if (!response.Success) 69 | return new CreateCircuitResponse(false, -1); 70 | 71 | string[] parts = StringHelper.GetAll(response.Responses[0], ' '); 72 | 73 | if (parts.Length < 2 || !"extended".Equals(parts[0], StringComparison.CurrentCultureIgnoreCase)) 74 | return new CreateCircuitResponse(false, -1); 75 | 76 | int circuitID; 77 | 78 | if (!int.TryParse(parts[1], out circuitID)) 79 | return new CreateCircuitResponse(false, -1); 80 | 81 | return new CreateCircuitResponse(true, circuitID); 82 | } 83 | 84 | return new CreateCircuitResponse(false, -1); 85 | } 86 | 87 | #endregion 88 | } 89 | 90 | /// 91 | /// A class containing the response information from a extendcircuit 0 command. 92 | /// 93 | internal sealed class CreateCircuitResponse : Response 94 | { 95 | private readonly int circuitID; 96 | 97 | /// 98 | /// Initializes a new instance of the class. 99 | /// 100 | /// A value indicating whether the command was received and processed successfully. 101 | /// The unique circuit identifier within the tor service. 102 | public CreateCircuitResponse(bool success, int circuitID) : base(success) 103 | { 104 | this.circuitID = circuitID; 105 | } 106 | 107 | #region Properties 108 | 109 | /// 110 | /// Gets the unique circuit identifier. 111 | /// 112 | public int CircuitID 113 | { 114 | get { return circuitID; } 115 | } 116 | 117 | #endregion 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Commands/ExtendCircuitCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Controller 7 | { 8 | /// 9 | /// A class containing the command responsible for extending a circuit. 10 | /// 11 | internal class ExtendCircuitCommand : Command 12 | { 13 | private readonly Circuit circuit; 14 | private readonly List routers; 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// The circuit which should be the target of extension. A null value indicates a new circuit. 20 | public ExtendCircuitCommand(Circuit circuit) 21 | { 22 | this.circuit = circuit; 23 | this.routers = new List(); 24 | } 25 | 26 | #region Properties 27 | 28 | /// 29 | /// Gets a collection containing the list of routers which should be extended onto this circuit. 30 | /// 31 | public List Routers 32 | { 33 | get { return routers; } 34 | } 35 | 36 | #endregion 37 | 38 | #region Tor.Controller.Command<> 39 | 40 | /// 41 | /// Dispatches the command to the client control port and produces a response result. 42 | /// 43 | /// The control connection where the command should be dispatched. 44 | /// 45 | /// A object instance containing the response data. 46 | /// 47 | protected override Response Dispatch(Connection connection) 48 | { 49 | if (routers.Count == 0) 50 | return new Response(false); 51 | 52 | int circuitID = 0; 53 | 54 | if (circuit != null) 55 | circuitID = circuit.ID; 56 | 57 | StringBuilder builder = new StringBuilder("extendcircuit"); 58 | builder.AppendFormat(" {0}", circuitID); 59 | 60 | foreach (string router in routers) 61 | builder.AppendFormat(" {0}", router); 62 | 63 | if (connection.Write(builder.ToString())) 64 | { 65 | ConnectionResponse response = connection.Read(); 66 | return new Response(response.Success); 67 | } 68 | 69 | return new Response(false); 70 | } 71 | 72 | #endregion 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Commands/GetAllRouterStatusCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Net; 6 | using Tor.Helpers; 7 | using System.ComponentModel; 8 | 9 | namespace Tor.Controller 10 | { 11 | /// 12 | /// A class containing the command to retrieve all relevant router statuses. 13 | /// 14 | internal sealed class GetAllRouterStatusCommand : Command 15 | { 16 | #region Tor.Controller.Command<> 17 | 18 | /// 19 | /// Dispatches the command to the client control port and produces a response result. 20 | /// 21 | /// The control connection where the command should be dispatched. 22 | /// 23 | /// A object instance containing the response data. 24 | /// 25 | protected override GetAllRouterStatusResponse Dispatch(Connection connection) 26 | { 27 | if (connection.Write("getinfo ns/all")) 28 | { 29 | ConnectionResponse response = connection.Read(); 30 | 31 | if (!response.Success || !response.Responses[0].StartsWith("ns/all", StringComparison.CurrentCultureIgnoreCase)) 32 | return new GetAllRouterStatusResponse(false); 33 | 34 | List routers = new List(); 35 | Router router = null; 36 | 37 | for (int i = 1, count = response.Responses.Count; i < count; i++) 38 | { 39 | string line = response.Responses[i].Trim(); 40 | 41 | if (string.IsNullOrWhiteSpace(line) || ".".Equals(line)) 42 | continue; 43 | 44 | if (line.StartsWith("r")) 45 | { 46 | if (router != null) 47 | { 48 | routers.Add(router); 49 | router = null; 50 | } 51 | 52 | string[] values = line.Split(' '); 53 | 54 | if (values.Length < 9) 55 | continue; 56 | 57 | DateTime publication = DateTime.MinValue; 58 | 59 | if (!DateTime.TryParse(string.Format("{0} {1}", values[4], values[5]), out publication)) 60 | publication = DateTime.MinValue; 61 | 62 | int orPort = 0; 63 | 64 | if (!int.TryParse(values[7], out orPort)) 65 | orPort = 0; 66 | 67 | int dirPort = 0; 68 | 69 | if (!int.TryParse(values[8], out dirPort)) 70 | dirPort = 0; 71 | 72 | IPAddress ipAddress = null; 73 | 74 | if (!IPAddress.TryParse(values[6], out ipAddress)) 75 | ipAddress = null; 76 | 77 | router = new Router(); 78 | router.Digest = values[3]; 79 | router.DIRPort = dirPort; 80 | router.Identity = values[2]; 81 | router.IPAddress = ipAddress; 82 | router.Nickname = values[1]; 83 | router.ORPort = orPort; 84 | router.Publication = publication; 85 | continue; 86 | } 87 | 88 | if (line.StartsWith("s") && router != null) 89 | { 90 | string[] values = line.Split(' '); 91 | 92 | for (int j = 1, length = values.Length; j < length; j++) 93 | { 94 | RouterFlags flag = ReflectionHelper.GetEnumerator(attr => values[j].Equals(attr.Description, StringComparison.CurrentCultureIgnoreCase)); 95 | 96 | if (flag != RouterFlags.None) 97 | router.Flags |= flag; 98 | } 99 | 100 | continue; 101 | } 102 | 103 | if (line.StartsWith("w") && router != null) 104 | { 105 | string[] values = line.Split(' '); 106 | 107 | if (values.Length < 2 || !values[1].StartsWith("bandwidth=", StringComparison.CurrentCultureIgnoreCase)) 108 | continue; 109 | 110 | string[] value = values[1].Split(new[] { '=' }, 2); 111 | 112 | if (value.Length < 2) 113 | continue; 114 | 115 | int bandwidth; 116 | 117 | if (int.TryParse(value[1].Trim(), out bandwidth)) 118 | router.Bandwidth = new Bytes((double)bandwidth, Bits.KB).Normalize(); 119 | } 120 | } 121 | 122 | if (router != null) 123 | { 124 | routers.Add(router); 125 | router = null; 126 | } 127 | 128 | return new GetAllRouterStatusResponse(true, routers); 129 | } 130 | 131 | return new GetAllRouterStatusResponse(false); 132 | } 133 | 134 | #endregion 135 | } 136 | 137 | /// 138 | /// A class containing the response information from a getinfo ns/all command. 139 | /// 140 | internal sealed class GetAllRouterStatusResponse : Response 141 | { 142 | private readonly RouterCollection routers; 143 | 144 | /// 145 | /// Initializes a new instance of the class. 146 | /// 147 | /// A value indicating whether the command was received and processed successfully. 148 | public GetAllRouterStatusResponse(bool success) : base(success) 149 | { 150 | this.routers = null; 151 | } 152 | 153 | /// 154 | /// Initializes a new instance of the class. 155 | /// 156 | /// A value indicating whether the command was received and processed successfully. 157 | /// The collection of routers. 158 | public GetAllRouterStatusResponse(bool success, IList routers) : base(success) 159 | { 160 | this.routers = new RouterCollection(routers); 161 | } 162 | 163 | #region Properties 164 | 165 | /// 166 | /// Gets a read-only collection containing the router status information. 167 | /// 168 | public RouterCollection Routers 169 | { 170 | get { return routers; } 171 | } 172 | 173 | #endregion 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Commands/GetConfCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Collections.ObjectModel; 6 | 7 | namespace Tor.Controller 8 | { 9 | /// 10 | /// A class containing the command to retrieve configuration values from a client. 11 | /// 12 | internal sealed class GetConfCommand : Command 13 | { 14 | private readonly ReadOnlyCollection configurations; 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// The configurations which should be retrieved from the tor application. 20 | public GetConfCommand(List configurations) 21 | { 22 | this.configurations = configurations.AsReadOnly(); 23 | } 24 | 25 | #region Tor.Controller.Command<> 26 | 27 | /// 28 | /// Dispatches the command to the client control port and produces a response result. 29 | /// 30 | /// The control connection where the command should be dispatched. 31 | /// 32 | /// A object instance containing the response data. 33 | /// 34 | protected override GetConfResponse Dispatch(Connection connection) 35 | { 36 | StringBuilder builder = new StringBuilder("getconf"); 37 | 38 | foreach (string name in configurations) 39 | { 40 | builder.Append(' '); 41 | builder.Append(name); 42 | } 43 | 44 | if (connection.Write(builder.ToString())) 45 | { 46 | ConnectionResponse response = connection.Read(); 47 | 48 | if (!response.Success) 49 | return new GetConfResponse(false, null); 50 | 51 | ResponsePairs values = new ResponsePairs(response.Responses.Count); 52 | 53 | foreach (string value in response.Responses) 54 | { 55 | string[] parts = value.Split(new[] { '=' }, 2); 56 | string name = parts[0].Trim(); 57 | 58 | if (parts.Length != 2) 59 | values[name] = null; 60 | else 61 | values[name] = parts[1].Trim(); 62 | } 63 | 64 | return new GetConfResponse(true, values); 65 | } 66 | 67 | return new GetConfResponse(false, null); 68 | } 69 | 70 | #endregion 71 | } 72 | 73 | /// 74 | /// A class containing a collection of configuration value responses. 75 | /// 76 | internal sealed class GetConfResponse : Response 77 | { 78 | private readonly ResponsePairs values; 79 | 80 | /// 81 | /// Initializes a new instance of the class. 82 | /// 83 | /// A value indicating whether the command was received and processed successfully. 84 | /// The values received from the tor control connection. 85 | public GetConfResponse(bool success, ResponsePairs values) : base(success) 86 | { 87 | this.values = values; 88 | } 89 | 90 | #region Properties 91 | 92 | /// 93 | /// Gets the values received from the control connection. 94 | /// 95 | public ResponsePairs Values 96 | { 97 | get { return values; } 98 | } 99 | 100 | #endregion 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Commands/GetInfoCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Collections.ObjectModel; 6 | 7 | namespace Tor.Controller 8 | { 9 | /// 10 | /// A class containing the command to get network information from the tor service. 11 | /// 12 | internal sealed class GetInfoCommand : Command 13 | { 14 | private string request; 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | public GetInfoCommand() 20 | { 21 | this.request = null; 22 | } 23 | 24 | /// 25 | /// Initializes a new instance of the class. 26 | /// 27 | /// The request to send with the getinfo command. 28 | public GetInfoCommand(string request) 29 | { 30 | this.request = request; 31 | } 32 | 33 | #region Tor.Controller.Command<> 34 | 35 | /// 36 | /// Dispatches the command to the client control port and produces a response result. 37 | /// 38 | /// The control connection where the command should be dispatched. 39 | /// 40 | /// A object instance containing the response data. 41 | /// 42 | protected override GetInfoResponse Dispatch(Connection connection) 43 | { 44 | if (request == null) 45 | return new GetInfoResponse(false); 46 | 47 | if (connection.Write("getinfo {0}", request)) 48 | { 49 | ConnectionResponse response = connection.Read(); 50 | 51 | if (!response.Success || !response.Responses[0].StartsWith(request, StringComparison.CurrentCultureIgnoreCase)) 52 | return new GetInfoResponse(false); 53 | 54 | List values = new List(response.Responses.Count); 55 | 56 | if (response.Responses.Count == 1) 57 | { 58 | string[] parts = response.Responses[0].Split(new[] { '=' }, 2); 59 | values.Add(parts.Length == 1 ? null : parts[1]); 60 | } 61 | else 62 | { 63 | for (int i = 1; i < response.Responses.Count; i++) 64 | { 65 | if (".".Equals(response.Responses[i])) 66 | break; 67 | 68 | values.Add(response.Responses[i]); 69 | } 70 | } 71 | 72 | return new GetInfoResponse(true, values.AsReadOnly()); 73 | } 74 | 75 | return new GetInfoResponse(false); 76 | } 77 | 78 | #endregion 79 | } 80 | 81 | /// 82 | /// A class containing the response values for a getinfo command. 83 | /// 84 | internal sealed class GetInfoResponse : Response 85 | { 86 | private readonly ReadOnlyCollection values; 87 | 88 | /// 89 | /// Initializes a new instance of the class. 90 | /// 91 | /// A value indicating whether the command was received and processed successfully. 92 | public GetInfoResponse(bool success) : base(success) 93 | { 94 | this.values = new List().AsReadOnly(); 95 | } 96 | 97 | /// 98 | /// Initializes a new instance of the class. 99 | /// 100 | /// A value indicating whether the command was received and processed successfully. 101 | /// The values returned from the control connection. 102 | public GetInfoResponse(bool success, ReadOnlyCollection values) : base(success) 103 | { 104 | this.values = values; 105 | } 106 | 107 | #region Properties 108 | 109 | /// 110 | /// Gets a read-only collection of the values returned from the control connection. 111 | /// 112 | public ReadOnlyCollection Values 113 | { 114 | get { return values; } 115 | } 116 | 117 | #endregion 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Commands/GetRouterStatusCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Net; 6 | using Tor.Helpers; 7 | using System.ComponentModel; 8 | 9 | namespace Tor.Controller 10 | { 11 | /// 12 | /// A class containing the command to retrieve router status information. 13 | /// 14 | internal sealed class GetRouterStatusCommand : Command 15 | { 16 | private string identity; 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | public GetRouterStatusCommand() : this(null) 22 | { 23 | } 24 | 25 | /// 26 | /// Initializes a new instance of the class. 27 | /// 28 | /// The router identity to retrieve status information for. 29 | public GetRouterStatusCommand(string identity) 30 | { 31 | this.identity = identity; 32 | } 33 | 34 | #region Properties 35 | 36 | /// 37 | /// Gets or sets the identity of the router. 38 | /// 39 | public string Identity 40 | { 41 | get { return identity; } 42 | } 43 | 44 | #endregion 45 | 46 | #region Tor.Controller.Command<> 47 | 48 | /// 49 | /// Dispatches the command to the client control port and produces a response result. 50 | /// 51 | /// 52 | /// 53 | /// A object instance containing the response data. 54 | /// 55 | protected override GetRouterStatusResponse Dispatch(Connection connection) 56 | { 57 | if (identity == null) 58 | return new GetRouterStatusResponse(false, null); 59 | 60 | string request = string.Format("ns/id/{0}", identity); 61 | 62 | if (connection.Write("getinfo {0}", request)) 63 | { 64 | ConnectionResponse response = connection.Read(); 65 | 66 | if (!response.Success || !response.Responses[0].StartsWith(request, StringComparison.CurrentCultureIgnoreCase)) 67 | return new GetRouterStatusResponse(false, null); 68 | 69 | Router router = null; 70 | 71 | foreach (string line in response.Responses) 72 | { 73 | string stripped = line.Trim(); 74 | 75 | if (string.IsNullOrWhiteSpace(stripped)) 76 | continue; 77 | 78 | if (stripped.StartsWith("r")) 79 | { 80 | string[] values = stripped.Split(' '); 81 | 82 | if (values.Length < 9) 83 | continue; 84 | 85 | DateTime publication = DateTime.MinValue; 86 | 87 | if (!DateTime.TryParse(string.Format("{0} {1}", values[4], values[5]), out publication)) 88 | publication = DateTime.MinValue; 89 | 90 | int orPort = 0; 91 | 92 | if (!int.TryParse(values[7], out orPort)) 93 | orPort = 0; 94 | 95 | int dirPort = 0; 96 | 97 | if (!int.TryParse(values[8], out dirPort)) 98 | dirPort = 0; 99 | 100 | IPAddress ipAddress = null; 101 | 102 | if (!IPAddress.TryParse(values[6], out ipAddress)) 103 | ipAddress = null; 104 | 105 | router = new Router(); 106 | router.Digest = values[3]; 107 | router.DIRPort = dirPort; 108 | router.Identity = values[2]; 109 | router.IPAddress = ipAddress; 110 | router.Nickname = values[1]; 111 | router.ORPort = orPort; 112 | router.Publication = publication; 113 | continue; 114 | } 115 | 116 | if (stripped.StartsWith("s") && router != null) 117 | { 118 | string[] values = stripped.Split(' '); 119 | 120 | for (int i = 1, length = values.Length; i < length; i++) 121 | { 122 | RouterFlags flag = ReflectionHelper.GetEnumerator(attr => values[i].Equals(attr.Description, StringComparison.CurrentCultureIgnoreCase)); 123 | 124 | if (flag != RouterFlags.None) 125 | router.Flags |= flag; 126 | } 127 | 128 | continue; 129 | } 130 | 131 | if (stripped.StartsWith("w") && router != null) 132 | { 133 | string[] values = stripped.Split(' '); 134 | 135 | if (values.Length < 2 || !values[1].StartsWith("bandwidth=", StringComparison.CurrentCultureIgnoreCase)) 136 | continue; 137 | 138 | string[] value = values[1].Split(new[] { '=' }, 2); 139 | 140 | if (value.Length < 2) 141 | continue; 142 | 143 | int bandwidth; 144 | 145 | if (int.TryParse(value[1].Trim(), out bandwidth)) 146 | router.Bandwidth = new Bytes((double)bandwidth, Bits.KB).Normalize(); 147 | } 148 | } 149 | 150 | return new GetRouterStatusResponse(true, router); 151 | } 152 | 153 | return new GetRouterStatusResponse(false, null); 154 | } 155 | 156 | #endregion 157 | } 158 | 159 | /// 160 | /// A class containing the response information from a getinfo ns/id/? command. 161 | /// 162 | internal sealed class GetRouterStatusResponse : Response 163 | { 164 | private readonly Router router; 165 | 166 | /// 167 | /// Initializes a new instance of the class. 168 | /// 169 | /// A value indicating whether the command was received and processed successfully. 170 | /// The router information retrieved from the command. 171 | public GetRouterStatusResponse(bool success, Router router) : base(success) 172 | { 173 | this.router = router; 174 | } 175 | 176 | #region Properties 177 | 178 | /// 179 | /// Gets the router information retrieved from the control connection. 180 | /// 181 | public Router Router 182 | { 183 | get { return router; } 184 | } 185 | 186 | #endregion 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Commands/SaveConfCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Controller 7 | { 8 | /// 9 | /// A class containing the command to save the configuration values in memory, to the torrc document. 10 | /// 11 | internal sealed class SaveConfCommand : Command 12 | { 13 | #region Tor.Controller.Command<> 14 | 15 | /// 16 | /// Dispatches the command to the client control port and produces a response result. 17 | /// 18 | /// The control connection where the command should be dispatched. 19 | /// 20 | /// A object instance containing the response data. 21 | /// 22 | protected override Response Dispatch(Connection connection) 23 | { 24 | if (connection.Write("saveconf")) 25 | { 26 | ConnectionResponse response = connection.Read(); 27 | return new Response(response.Success); 28 | } 29 | 30 | return new Response(false); 31 | } 32 | 33 | #endregion 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Commands/SetConfCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Controller 7 | { 8 | /// 9 | /// A class containing the command used to set the value of a configuration. 10 | /// 11 | internal sealed class SetConfCommand : Command 12 | { 13 | private readonly string name; 14 | private readonly string value; 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// The name of the configuration to set. 20 | /// The value of the configuration. 21 | public SetConfCommand(string name, string value) 22 | { 23 | this.name = name; 24 | this.value = value; 25 | } 26 | 27 | #region Tor.Controller.Command<> 28 | 29 | /// 30 | /// Dispatches the command to the client control port and produces a response result. 31 | /// 32 | /// The control connection where the command should be dispatched. 33 | /// 34 | /// A object instance containing the response data. 35 | /// 36 | protected override Response Dispatch(Connection connection) 37 | { 38 | if (name == null || value == null) 39 | return new Response(false); 40 | 41 | if (connection.Write("setconf {0}={1}", name, value.Contains(" ") ? string.Format("\"{0}\"", value) : value)) 42 | { 43 | ConnectionResponse response = connection.Read(); 44 | return new Response(response.Success); 45 | } 46 | 47 | return new Response(false); 48 | } 49 | 50 | #endregion 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Commands/SignalClearDNSCacheCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Controller 7 | { 8 | /// 9 | /// A class containing the command to clear client-side cached IP addresses for hostnames. 10 | /// 11 | internal sealed class SignalClearDNSCacheCommand : Command 12 | { 13 | #region Tor.Controller.Command<> 14 | 15 | /// 16 | /// Dispatches the command to the client control port and produces a response result. 17 | /// 18 | /// The control connection where the command should be dispatched. 19 | /// 20 | /// A object instance containing the response data. 21 | /// 22 | protected override Response Dispatch(Connection connection) 23 | { 24 | if (connection.Write("signal cleardnscache")) 25 | { 26 | ConnectionResponse response = connection.Read(); 27 | return new Response(response.Success); 28 | } 29 | 30 | return new Response(false); 31 | } 32 | 33 | #endregion 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Commands/SignalHaltCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Controller 7 | { 8 | /// 9 | /// A class containing the command to signal an immediate halt in the tor process. 10 | /// 11 | internal sealed class SignalHaltCommand : Command 12 | { 13 | #region Tor.Controller.Command<> 14 | 15 | /// 16 | /// Dispatches the command to the client control port and produces a response result. 17 | /// 18 | /// The control connection where the command should be dispatched. 19 | /// 20 | /// A object instance containing the response data. 21 | /// 22 | protected override Response Dispatch(Connection connection) 23 | { 24 | if (connection.Write("signal halt")) 25 | { 26 | ConnectionResponse response = connection.Read(); 27 | return new Response(response.Success); 28 | } 29 | 30 | return new Response(false); 31 | } 32 | 33 | #endregion 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Commands/SignalNewCircuitCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Controller 7 | { 8 | /// 9 | /// A class containing the command to generate a new circuit. 10 | /// 11 | internal sealed class SignalNewCircuitCommand : Command 12 | { 13 | #region Tor.Controller.Command<> 14 | 15 | /// 16 | /// Dispatches the command to the client control port and produces a response result. 17 | /// 18 | /// The control connection where the command should be dispatched. 19 | /// 20 | /// A object instance containing the response data. 21 | /// 22 | protected override Response Dispatch(Connection connection) 23 | { 24 | if (connection.Write("signal newnym")) 25 | { 26 | ConnectionResponse response = connection.Read(); 27 | return new Response(response.Success); 28 | } 29 | 30 | return new Response(false); 31 | } 32 | 33 | #endregion 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Connection/ConnectionResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Collections.ObjectModel; 6 | 7 | namespace Tor.Controller 8 | { 9 | /// 10 | /// A class containing information regarding a response received back from a control connection. 11 | /// 12 | internal sealed class ConnectionResponse 13 | { 14 | private readonly StatusCode code; 15 | private readonly ReadOnlyCollection responses; 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// The status code returned by the control connection. 21 | public ConnectionResponse(StatusCode code) 22 | { 23 | this.code = code; 24 | this.responses = new List().AsReadOnly(); 25 | } 26 | 27 | /// 28 | /// Initializes a new instance of the class. 29 | /// 30 | /// The status code returned by the control connection. 31 | /// The responses received back from the control connection. 32 | public ConnectionResponse(StatusCode code, IList responses) 33 | { 34 | this.code = code; 35 | this.responses = new ReadOnlyCollection(responses); 36 | } 37 | 38 | #region Properties 39 | 40 | /// 41 | /// Gets a read-only collection of responses received from the control connection. 42 | /// 43 | public ReadOnlyCollection Responses 44 | { 45 | get { return responses; } 46 | } 47 | 48 | /// 49 | /// Gets the status code returned with the response. 50 | /// 51 | public StatusCode StatusCode 52 | { 53 | get { return code; } 54 | } 55 | 56 | /// 57 | /// Gets a value indicating whether the response was successful feedback. 58 | /// 59 | public bool Success 60 | { 61 | get { return code == StatusCode.OK; } 62 | } 63 | 64 | #endregion 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Control.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Controller 7 | { 8 | /// 9 | /// A class containing methods for performing control operations against the tor application. 10 | /// 11 | public sealed class Control : MarshalByRefObject 12 | { 13 | private readonly Client client; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The client for which this object instance belongs. 19 | internal Control(Client client) 20 | { 21 | this.client = client; 22 | } 23 | 24 | /// 25 | /// Cleans the current circuits in the tor application by requesting new circuits be generated. 26 | /// 27 | public bool CleanCircuits() 28 | { 29 | return Command.DispatchAndReturn(client); 30 | } 31 | 32 | /// 33 | /// Clears the client-side cache of IP addresses for hostnames. 34 | /// 35 | /// 36 | public bool ClearDNSCache() 37 | { 38 | return Command.DispatchAndReturn(client); 39 | } 40 | 41 | /// 42 | /// Closes an existing circuit within the tor service. 43 | /// 44 | /// The circuit which should be closed. 45 | /// true if the circuit was closed successfully; otherwise, false. 46 | public bool CloseCircuit(Circuit circuit) 47 | { 48 | if (circuit == null) 49 | throw new ArgumentNullException("circuit"); 50 | if (circuit.ID == 0) 51 | throw new ArgumentException("The circuit has an invalid ID", "circuit"); 52 | 53 | CloseCircuitCommand command = new CloseCircuitCommand(circuit); 54 | Response response = command.Dispatch(client); 55 | return response.Success; 56 | } 57 | 58 | /// 59 | /// Closes an existing stream within the tor service. 60 | /// 61 | /// The stream which should be closed. 62 | /// The reason for the stream being closed. 63 | /// true if the stream was closed successfully; otherwise, false. 64 | public bool CloseStream(Stream stream, StreamReason reason) 65 | { 66 | if (stream == null) 67 | throw new ArgumentNullException("stream"); 68 | if (stream.ID == 0) 69 | throw new ArgumentException("The stream has an invalid ID", "stream"); 70 | if (reason == StreamReason.None || reason == StreamReason.End || reason == StreamReason.PrivateAddr) 71 | throw new ArgumentOutOfRangeException("reason", "The reason for closure cannot be None, End or PrivateAddr"); 72 | 73 | CloseStreamCommand command = new CloseStreamCommand(stream, reason); 74 | Response response = command.Dispatch(client); 75 | return response.Success; 76 | } 77 | 78 | /// 79 | /// Creates a new circuit within the tor service, and allow tor to select the routers. 80 | /// 81 | /// true if the circuit is created successfully; otherwise, false. 82 | public bool CreateCircuit() 83 | { 84 | CreateCircuitCommand command = new CreateCircuitCommand(); 85 | CreateCircuitResponse response = command.Dispatch(client); 86 | return response.Success && response.CircuitID >= 0; 87 | } 88 | 89 | /// 90 | /// Creates a new circuit within the tor service comprised of a series of specified routers. 91 | /// 92 | /// true if the circuit is created successfully; otherwise, false. 93 | public bool CreateCircuit(params string[] routers) 94 | { 95 | CreateCircuitCommand command = new CreateCircuitCommand(routers); 96 | CreateCircuitResponse response = command.Dispatch(client); 97 | return response.Success && response.CircuitID >= 0; 98 | } 99 | 100 | /// 101 | /// Extends an existing circuit by attaching a new router onto the path. 102 | /// 103 | /// The circuit which should be extended. 104 | /// The list of router identities or nicknames to extend onto the circuit. 105 | /// true if the circuit was extended successfully; otherwise, false. 106 | public bool ExtendCircuit(Circuit circuit, params string[] routers) 107 | { 108 | if (circuit == null) 109 | throw new ArgumentNullException("circuit"); 110 | if (circuit.ID == 0) 111 | throw new ArgumentException("The circuit has an invalid ID", "circuit"); 112 | if (routers.Length == 0) 113 | throw new ArgumentOutOfRangeException("routers", "At least one router should be supplied with the extend"); 114 | 115 | ExtendCircuitCommand command = new ExtendCircuitCommand(circuit); 116 | command.Routers.AddRange(routers); 117 | 118 | Response response = command.Dispatch(client); 119 | return response.Success; 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Controller/Enumerators/StatusCode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Controller 7 | { 8 | /// 9 | /// An enumerator containing the status codes sent in response to commands. 10 | /// 11 | internal enum StatusCode : int 12 | { 13 | /// 14 | /// This should never occur ideally, unless a response was malformed or incomplete. 15 | /// 16 | Unknown = 0, 17 | 18 | /// 19 | /// The command was processed. 20 | /// 21 | OK = 250, 22 | 23 | /// 24 | /// The operation was unnecessary. 25 | /// 26 | OperationUnnecessary = 251, 27 | 28 | /// 29 | /// The resources were exhausted. 30 | /// 31 | ResourceExhausted = 451, 32 | 33 | /// 34 | /// There was a syntax error in the protocol. 35 | /// 36 | SyntaxErrorProtocol = 500, 37 | 38 | /// 39 | /// The command was unrecognized. 40 | /// 41 | UnrecognizedCommand = 501, 42 | 43 | /// 44 | /// The command is unimplemented. 45 | /// 46 | UnimplementedCommand = 511, 47 | 48 | /// 49 | /// There was a syntax error in a command argument. 50 | /// 51 | SyntaxErrorArgument = 512, 52 | 53 | /// 54 | /// The command argument was unrecognized. 55 | /// 56 | UnrecognizedCommandArgument = 513, 57 | 58 | /// 59 | /// The command could not execute because authentication is required. 60 | /// 61 | AuthenticationRequired = 514, 62 | 63 | /// 64 | /// The command to authenticate returned an invalid authentication response. 65 | /// 66 | BadAuthentication = 515, 67 | 68 | /// 69 | /// The command generated a non-specific error response. 70 | /// 71 | Unspecified = 550, 72 | 73 | /// 74 | /// An error occurred within Tor leading to the command failing to execute. 75 | /// 76 | InternalError = 551, 77 | 78 | /// 79 | /// The command contained a configuration key, stream ID, circuit ID, or event which did not exist. 80 | /// 81 | UnrecognizedEntity = 552, 82 | 83 | /// 84 | /// The command sent a configuration value incompatible with the configuration. 85 | /// 86 | InvalidConfigurationValue = 553, 87 | 88 | /// 89 | /// The command contained an invalid descriptor. 90 | /// 91 | InvalidDescriptor = 554, 92 | 93 | /// 94 | /// The command contained a reference to an unmanaged entity. 95 | /// 96 | UnmanagedEntity = 555, 97 | 98 | /// 99 | /// A notification sent following an asynchronous operation. 100 | /// 101 | AsynchronousEventNotify = 650, 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Core/Bytes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Tor.Helpers; 6 | using System.ComponentModel; 7 | using Tor.Converters; 8 | 9 | namespace Tor 10 | { 11 | /// 12 | /// A structure containing byte information, in a specified magnitude. 13 | /// 14 | [Serializable] 15 | [TypeConverter(typeof(BytesTypeConverter))] 16 | public struct Bytes 17 | { 18 | /// 19 | /// Gets an empty structure. 20 | /// 21 | public static readonly Bytes Empty = new Bytes(); 22 | 23 | private Bits units; 24 | private double value; 25 | 26 | /// 27 | /// Initializes a new instance of the struct. 28 | /// 29 | /// The value in bytes. 30 | public Bytes(double value) 31 | { 32 | this.units = Bits.B; 33 | this.value = value; 34 | } 35 | 36 | /// 37 | /// Initializes a new instance of the struct. 38 | /// 39 | /// The value relative to the specified units. 40 | /// The units of the bytes. 41 | public Bytes(double value, Bits units) 42 | { 43 | this.units = units; 44 | this.value = value; 45 | } 46 | 47 | #region Properties 48 | 49 | /// 50 | /// Gets or sets the units of the bytes. 51 | /// 52 | public Bits Units 53 | { 54 | get { return units; } 55 | set { units = value; } 56 | } 57 | 58 | /// 59 | /// Gets or sets the value of bytes, relative to the units. 60 | /// 61 | public double Value 62 | { 63 | get { return value; } 64 | set { this.value = value; } 65 | } 66 | 67 | #endregion 68 | 69 | #region System.Object 70 | 71 | /// 72 | /// Determines whether the specified , is equal to this instance. 73 | /// 74 | /// The to compare with this instance. 75 | /// 76 | /// true if the specified is equal to this instance; otherwise, false. 77 | /// 78 | public override bool Equals(object obj) 79 | { 80 | return obj != null && obj is Bytes && ((Bytes)obj).units == units && ((Bytes)obj).value == value; 81 | } 82 | 83 | /// 84 | /// Returns a hash code for this instance. 85 | /// 86 | /// 87 | /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 88 | /// 89 | public override int GetHashCode() 90 | { 91 | unchecked 92 | { 93 | int hash = 17; 94 | hash = hash * 23 + Convert.ToInt32(units); 95 | hash = hash * 23 + Convert.ToInt32(value); 96 | return hash; 97 | } 98 | } 99 | 100 | /// 101 | /// Returns a that represents this instance. 102 | /// 103 | /// 104 | /// A that represents this instance. 105 | /// 106 | public override string ToString() 107 | { 108 | string unit = "bytes"; 109 | 110 | switch (units) 111 | { 112 | case Bits.KB: 113 | unit = "KBytes"; 114 | break; 115 | case Bits.MB: 116 | unit = "MBytes"; 117 | break; 118 | case Bits.GB: 119 | unit = "GBytes"; 120 | break; 121 | case Bits.TB: 122 | unit = "TBytes"; 123 | break; 124 | } 125 | 126 | return string.Format("{0} {1}", Convert.ToInt32(value), unit); 127 | } 128 | 129 | #endregion 130 | 131 | /// 132 | /// Normalizes the bytes by dividing the value into the nearest acceptable unit. 133 | /// 134 | /// A struct containing the normalized values. 135 | public Bytes Normalize() 136 | { 137 | if (units == Bits.TB) 138 | return this; 139 | if (value == 0.00) 140 | return this; 141 | 142 | int max = (int)Bits.TB; 143 | int unit = (int)units; 144 | double absolute = Math.Abs(value); 145 | 146 | while (1024 <= absolute && unit < max) 147 | { 148 | absolute = Math.Round(absolute / 1024.00, 4); 149 | unit++; 150 | } 151 | 152 | if (value < 0.00) 153 | absolute *= -1.0; 154 | 155 | return new Bytes(absolute, (Bits)unit); 156 | } 157 | 158 | /// 159 | /// Converts the units of the bytes into another unit. 160 | /// 161 | /// The units to convert the bytes to. 162 | /// A structure containing the converted value. 163 | public Bytes ToUnit(Bits unit) 164 | { 165 | if (units == unit) 166 | return this; 167 | if (value == 0.00) 168 | return new Bytes(0.00, unit); 169 | 170 | int from = 10 - (int)units; 171 | int to = 10 - (int)unit; 172 | double absolute = Math.Abs(value); 173 | 174 | if (from < to) 175 | { 176 | while (from < to) 177 | { 178 | absolute = Math.Round(absolute * 1024.00, 4); 179 | from++; 180 | } 181 | } 182 | else 183 | { 184 | while (to < from) 185 | { 186 | absolute = Math.Round(absolute / 1024.00, 4); 187 | from--; 188 | } 189 | } 190 | 191 | if (value < 0.00) 192 | absolute *= -1.0; 193 | 194 | return new Bytes(absolute, unit); 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Core/Converters/BytesTypeConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | using System.Globalization; 7 | 8 | namespace Tor.Converters 9 | { 10 | /// 11 | /// A class providing the methods necessary to convert between a object and object. 12 | /// 13 | public sealed class BytesTypeConverter : TypeConverter 14 | { 15 | #region System.ComponentModel.TypeConverter 16 | 17 | /// 18 | /// Returns whether this converter can convert an object of the given type to the type of this converter, using the specified context. 19 | /// 20 | /// An that provides a format context. 21 | /// A that represents the type you want to convert from. 22 | /// 23 | /// true if this converter can perform the conversion; otherwise, false. 24 | /// 25 | public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 26 | { 27 | if (sourceType.Equals(typeof(double))) 28 | return true; 29 | if (sourceType.Equals(typeof(string))) 30 | return true; 31 | 32 | return base.CanConvertFrom(context, sourceType); 33 | } 34 | 35 | /// 36 | /// Converts the given object to the type of this converter, using the specified context and culture information. 37 | /// 38 | /// An that provides a format context. 39 | /// The to use as the current culture. 40 | /// The to convert. 41 | /// 42 | /// An that represents the converted value. 43 | /// 44 | public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) 45 | { 46 | if (value is double) 47 | return new Bytes((double)value); 48 | if (value is string) 49 | return new Bytes(Convert.ToDouble(value)); 50 | 51 | return base.ConvertFrom(context, culture, value); 52 | } 53 | 54 | /// 55 | /// Converts the given value object to the specified type, using the specified context and culture information. 56 | /// 57 | /// An that provides a format context. 58 | /// A . If null is passed, the current culture is assumed. 59 | /// The to convert. 60 | /// The to convert the parameter to. 61 | /// 62 | /// An that represents the converted value. 63 | /// 64 | public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 65 | { 66 | if (destinationType.Equals(typeof(double))) 67 | return ((Bytes)value).ToUnit(Bits.B).Value; 68 | if (destinationType.Equals(typeof(string))) 69 | return ((Bytes)value).ToString(); 70 | 71 | return base.ConvertTo(context, culture, value, destinationType); 72 | } 73 | 74 | #endregion 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Core/Converters/HostAuthTypeConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | using System.Globalization; 7 | 8 | namespace Tor.Converters 9 | { 10 | /// 11 | /// A class providing the methods necessary to convert between a object and object. 12 | /// 13 | public sealed class HostAuthTypeConverter : TypeConverter 14 | { 15 | #region System.ComponentModel.TypeConverter 16 | 17 | /// 18 | /// Returns whether this converter can convert an object of the given type to the type of this converter, using the specified context. 19 | /// 20 | /// An that provides a format context. 21 | /// A that represents the type you want to convert from. 22 | /// 23 | /// true if this converter can perform the conversion; otherwise, false. 24 | /// 25 | public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 26 | { 27 | if (sourceType.Equals(typeof(string))) 28 | return true; 29 | 30 | return base.CanConvertFrom(context, sourceType); 31 | } 32 | 33 | /// 34 | /// Converts the given object to the type of this converter, using the specified context and culture information. 35 | /// 36 | /// An that provides a format context. 37 | /// The to use as the current culture. 38 | /// The to convert. 39 | /// 40 | /// An that represents the converted value. 41 | /// 42 | /// A string must contain a username, or a username and password, format 43 | public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) 44 | { 45 | if (value == null) 46 | return HostAuth.Null; 47 | 48 | if (value is string) 49 | { 50 | string actual = value as string; 51 | 52 | if (actual.Contains(":")) 53 | { 54 | string[] parts = actual.Split(':'); 55 | 56 | if (parts.Length != 2) 57 | throw new InvalidCastException("A string must contain a username, or a username and password, format"); 58 | 59 | return new HostAuth(parts[0], parts[1]); 60 | } 61 | 62 | return new HostAuth(actual, null); 63 | } 64 | 65 | return base.ConvertFrom(context, culture, value); 66 | } 67 | 68 | /// 69 | /// Converts the given value object to the specified type, using the specified context and culture information. 70 | /// 71 | /// An that provides a format context. 72 | /// A . If null is passed, the current culture is assumed. 73 | /// The to convert. 74 | /// The to convert the parameter to. 75 | /// 76 | /// An that represents the converted value. 77 | /// 78 | public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 79 | { 80 | if (destinationType.Equals(typeof(string))) 81 | { 82 | HostAuth hostAuth = (HostAuth)value; 83 | 84 | if (hostAuth.IsNull) 85 | return ""; 86 | 87 | if (hostAuth.Password == null) 88 | return hostAuth.Username; 89 | 90 | return string.Format("{0}:{1}", hostAuth.Username, hostAuth.Password); 91 | } 92 | 93 | return base.ConvertTo(context, culture, value, destinationType); 94 | } 95 | 96 | #endregion 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Core/Converters/HostTypeConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | using System.Globalization; 7 | 8 | namespace Tor.Converters 9 | { 10 | /// 11 | /// A class providing the methods necessary to convert between a object and object. 12 | /// 13 | public sealed class HostTypeConverter : TypeConverter 14 | { 15 | #region System.ComponentModel.TypeConverter 16 | 17 | /// 18 | /// Returns whether this converter can convert an object of the given type to the type of this converter, using the specified context. 19 | /// 20 | /// An that provides a format context. 21 | /// A that represents the type you want to convert from. 22 | /// 23 | /// true if this converter can perform the conversion; otherwise, false. 24 | /// 25 | public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 26 | { 27 | if (sourceType.Equals(typeof(string))) 28 | return true; 29 | 30 | return base.CanConvertFrom(context, sourceType); 31 | } 32 | 33 | /// 34 | /// Converts the given object to the type of this converter, using the specified context and culture information. 35 | /// 36 | /// An that provides a format context. 37 | /// The to use as the current culture. 38 | /// The to convert. 39 | /// 40 | /// An that represents the converted value. 41 | /// 42 | /// 43 | /// A string must contain an IP address, or an IP address and port number, format 44 | /// or 45 | /// A string containing an IP address and port must contain a valid port number 46 | /// 47 | public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) 48 | { 49 | if (value == null) 50 | return Host.Null; 51 | 52 | if (value is string) 53 | { 54 | string actual = value as string; 55 | 56 | if (actual.Contains(":")) 57 | { 58 | int port; 59 | string[] parts = actual.Split(':'); 60 | 61 | if (parts.Length != 2) 62 | throw new InvalidCastException("A string must contain an IP address, or an IP address and port number, format"); 63 | 64 | if (!int.TryParse(parts[1], out port)) 65 | throw new InvalidCastException("A string containing an IP address and port must contain a valid port number"); 66 | 67 | return new Host(parts[0], port); 68 | } 69 | 70 | return new Host(actual); 71 | } 72 | 73 | return base.ConvertFrom(context, culture, value); 74 | } 75 | 76 | /// 77 | /// Converts the given value object to the specified type, using the specified context and culture information. 78 | /// 79 | /// An that provides a format context. 80 | /// A . If null is passed, the current culture is assumed. 81 | /// The to convert. 82 | /// The to convert the parameter to. 83 | /// 84 | /// An that represents the converted value. 85 | /// 86 | public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 87 | { 88 | if (destinationType.Equals(typeof(string))) 89 | { 90 | Host host = (Host)value; 91 | 92 | if (host.IsNull) 93 | return ""; 94 | 95 | if (host.Port == -1) 96 | return host.Address; 97 | 98 | return string.Format("{0}:{1}", host.Address, host.Port); 99 | } 100 | 101 | return base.ConvertTo(context, culture, value, destinationType); 102 | } 103 | 104 | #endregion 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Core/Enumerators/Auto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | namespace Tor 8 | { 9 | /// 10 | /// An enumerator which extends the primitive type to accept an automatic state. 11 | /// 12 | public enum Auto : int 13 | { 14 | /// 15 | /// The value should be determined automatically. 16 | /// 17 | [Description("auto")] 18 | Auto = -1, 19 | 20 | /// 21 | /// The value is false. 22 | /// 23 | [Description("0")] 24 | False = 0, 25 | 26 | /// 27 | /// The value is true. 28 | /// 29 | [Description("1")] 30 | True = 1 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Core/Enumerators/Bits.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | namespace Tor 8 | { 9 | /// 10 | /// An enumerator containing the different units of bytes. 11 | /// 12 | public enum Bits : int 13 | { 14 | /// 15 | /// The unit is bytes. 16 | /// 17 | [Description("bytes")] 18 | B = 0, 19 | 20 | /// 21 | /// The unit is kilo-bytes. 22 | /// 23 | [Description("KBytes")] 24 | KB = 1, 25 | 26 | /// 27 | /// The unit is mega-bytes. 28 | /// 29 | [Description("MBytes")] 30 | MB = 2, 31 | 32 | /// 33 | /// The unit is giga-bytes. 34 | /// 35 | [Description("GBytes")] 36 | GB = 3, 37 | 38 | /// 39 | /// The unit is tera-bytes. 40 | /// 41 | [Description("TBytes")] 42 | TB = 4 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Core/Exceptions/TorException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor 7 | { 8 | /// 9 | /// A class containing the details of an exception which occurred when processing a tor operation. 10 | /// 11 | public class TorException : Exception 12 | { 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | /// The message that describes the error. 17 | public TorException(string message) : base(message) 18 | { 19 | } 20 | 21 | /// 22 | /// Initializes a new instance of the class. 23 | /// 24 | /// The error message that explains the reason for the exception. 25 | /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. 26 | public TorException(string message, Exception innerException) : base(message, innerException) 27 | { 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Core/Helpers/StringHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Helpers 7 | { 8 | /// 9 | /// A class containing methods to assist with string-based parsing. 10 | /// 11 | internal static class StringHelper 12 | { 13 | /// 14 | /// Gets all blocks from a where the delimiter is not included within quotations. 15 | /// 16 | /// The to retrieve the blocks from. 17 | /// The delimiter to search for. 18 | /// A array containing the blocks. 19 | public static string[] GetAll(string data, char delimiter) 20 | { 21 | if (data == null) 22 | return null; 23 | 24 | int index = 0; 25 | string part = null; 26 | List blocks = new List(); 27 | 28 | while ((part = GetNext(data, index, delimiter)) != null) 29 | { 30 | blocks.Add(part); 31 | index += part.Length + 1; 32 | } 33 | 34 | return blocks.ToArray(); 35 | } 36 | 37 | /// 38 | /// Gets the next block from a where the delimiter is not included within quotations. 39 | /// 40 | /// The to retrieve the block from. 41 | /// The start index within the string. 42 | /// The delimiter to search for. 43 | /// A containing the block data. 44 | public static string GetNext(string data, int start, char delimiter) 45 | { 46 | if (data == null) 47 | return null; 48 | if (data.Length <= start) 49 | return null; 50 | 51 | int index = start; 52 | int length = data.Length; 53 | bool escaped = false; 54 | 55 | while (index < length) 56 | { 57 | char c = data[index++]; 58 | 59 | if (c == '"') 60 | { 61 | escaped = !escaped; 62 | continue; 63 | } 64 | 65 | if (c == delimiter && !escaped) 66 | { 67 | index--; 68 | break; 69 | } 70 | } 71 | 72 | return data.Substring(start, index - start); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Core/Host.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | using Tor.Converters; 7 | 8 | namespace Tor 9 | { 10 | /// 11 | /// A structure containing information on a host, such as an address and/or port number. 12 | /// 13 | [Serializable] 14 | [TypeConverter(typeof(HostTypeConverter))] 15 | public struct Host 16 | { 17 | private string address; 18 | private int port; 19 | 20 | /// 21 | /// Initializes a new instance of the struct. 22 | /// 23 | /// The address of the host. 24 | public Host(string address) 25 | { 26 | if (string.IsNullOrWhiteSpace(address)) 27 | throw new ArgumentException("A host address cannot be null or white-space", "address"); 28 | 29 | this.address = address; 30 | this.port = -1; 31 | } 32 | 33 | /// 34 | /// Initializes a new instance of the struct. 35 | /// 36 | /// The address of the host. 37 | /// The port number open on the host. A value of -1 indicates an unspecified port number. 38 | public Host(string address, int port) 39 | { 40 | if (string.IsNullOrWhiteSpace(address)) 41 | throw new ArgumentException("A host address cannot be null or white-space", "address"); 42 | if (port != -1 && (port <= 0 || short.MaxValue < port)) 43 | throw new ArgumentOutOfRangeException("port", "A port number must fall within an acceptable range"); 44 | 45 | this.address = address; 46 | this.port = port; 47 | } 48 | 49 | #region Properties 50 | 51 | /// 52 | /// Gets or sets the address of the host. 53 | /// 54 | public string Address 55 | { 56 | get { return address; } 57 | set 58 | { 59 | if (string.IsNullOrWhiteSpace(value)) 60 | throw new ArgumentException("A host address cannot be null or white-space"); 61 | 62 | address = value; 63 | } 64 | } 65 | 66 | /// 67 | /// Gets a value indicating whether the host is actually a null reference. 68 | /// 69 | public bool IsNull 70 | { 71 | get { return address == null; } 72 | } 73 | 74 | /// 75 | /// Gets or sets the port number open on the host. A value of -1 indicates an unspecified port number. 76 | /// 77 | public int Port 78 | { 79 | get { return port; } 80 | set 81 | { 82 | if (port != -1 && (port <= 0 || short.MaxValue < port)) 83 | throw new ArgumentOutOfRangeException("value", "A port number must fall within an acceptable range"); 84 | 85 | port = value; 86 | } 87 | } 88 | 89 | /// 90 | /// Gets a object instance representing a null value. 91 | /// 92 | public static Host Null 93 | { 94 | get { return new Host() { address = null, port = -1 }; } 95 | } 96 | 97 | #endregion 98 | 99 | #region System.Object 100 | 101 | /// 102 | /// Determines whether the specified , is equal to this instance. 103 | /// 104 | /// The to compare with this instance. 105 | /// 106 | /// true if the specified is equal to this instance; otherwise, false. 107 | /// 108 | public override bool Equals(object obj) 109 | { 110 | return obj != null && obj is Host && ((Host)obj).address == address && ((Host)obj).port == port; 111 | } 112 | 113 | /// 114 | /// Returns a hash code for this instance. 115 | /// 116 | /// 117 | /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 118 | /// 119 | public override int GetHashCode() 120 | { 121 | unchecked 122 | { 123 | int hash = 17; 124 | hash = hash * 23 + address.GetHashCode(); 125 | hash = hash * 23 + port; 126 | return hash; 127 | } 128 | } 129 | 130 | /// 131 | /// Returns a that represents this instance. 132 | /// 133 | /// 134 | /// A that represents this instance. 135 | /// 136 | public override string ToString() 137 | { 138 | if (port == -1) 139 | return address; 140 | else 141 | return string.Format("{0}:{1}", address, port); 142 | } 143 | 144 | #endregion 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Core/HostAuth.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | using Tor.Converters; 7 | 8 | namespace Tor 9 | { 10 | /// 11 | /// A structure containing credential information for a host connection. 12 | /// 13 | [Serializable] 14 | [TypeConverter(typeof(HostAuthTypeConverter))] 15 | public struct HostAuth 16 | { 17 | private string password; 18 | private string username; 19 | 20 | /// 21 | /// Initializes a new instance of the struct. 22 | /// 23 | /// The username of the credentials. 24 | /// The password of the credentials. A value of null indicates no password. 25 | public HostAuth(string username, string password) 26 | { 27 | this.password = password; 28 | this.username = username; 29 | } 30 | 31 | #region Properties 32 | 33 | /// 34 | /// Gets a value indicating whether the host authentication is actually a null reference. 35 | /// 36 | public bool IsNull 37 | { 38 | get { return username == null && password == null; } 39 | } 40 | 41 | /// 42 | /// Gets or sets the password used when authenticating. A value of null indicates no password. 43 | /// 44 | public string Password 45 | { 46 | get { return password; } 47 | set { password = value; } 48 | } 49 | 50 | /// 51 | /// Gets or sets the username used when authenticating. 52 | /// 53 | public string Username 54 | { 55 | get { return username; } 56 | set { username = value; } 57 | } 58 | 59 | /// 60 | /// Gets a object instance representing a null value. 61 | /// 62 | public static HostAuth Null 63 | { 64 | get { return new HostAuth() { username = null, password = null }; } 65 | } 66 | 67 | #endregion 68 | 69 | #region System.Object 70 | 71 | /// 72 | /// Determines whether the specified , is equal to this instance. 73 | /// 74 | /// The to compare with this instance. 75 | /// 76 | /// true if the specified is equal to this instance; otherwise, false. 77 | /// 78 | public override bool Equals(object obj) 79 | { 80 | return obj != null && obj is HostAuth && ((HostAuth)obj).password == password && ((HostAuth)obj).username == username; 81 | } 82 | 83 | /// 84 | /// Returns a hash code for this instance. 85 | /// 86 | /// 87 | /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 88 | /// 89 | public override int GetHashCode() 90 | { 91 | unchecked 92 | { 93 | int hash = 17; 94 | hash = hash * 23 + (username != null ? username.GetHashCode() : 0); 95 | hash = hash * 23 + (password != null ? password.GetHashCode() : 0); 96 | return hash; 97 | } 98 | } 99 | 100 | /// 101 | /// Returns a that represents this instance. 102 | /// 103 | /// 104 | /// A that represents this instance. 105 | /// 106 | public override string ToString() 107 | { 108 | if (username == null && password == null) 109 | return ""; 110 | if (password == null) 111 | return username; 112 | 113 | return string.Format("{0}:{1}", username, password); 114 | } 115 | 116 | #endregion 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Events/Attributes/EventAssocAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Events 7 | { 8 | /// 9 | /// Specifies that a dispatcher class is associated with an event. 10 | /// 11 | [AttributeUsage(AttributeTargets.Class)] 12 | internal sealed class EventAssocAttribute : Attribute 13 | { 14 | private readonly Enumerators.Event evt; 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// The event the class is associated with. 20 | public EventAssocAttribute(Enumerators.Event evt) 21 | { 22 | this.evt = evt; 23 | } 24 | 25 | #region Properties 26 | 27 | /// 28 | /// Gets the event the class is associated with. 29 | /// 30 | public Enumerators.Event Event 31 | { 32 | get { return evt; } 33 | } 34 | 35 | #endregion 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Events/Base/Dispatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Events 7 | { 8 | /// 9 | /// A class containing the skeleton structure for processing an event response received from a control connection. 10 | /// 11 | internal abstract class Dispatcher 12 | { 13 | private Client client; 14 | private Enumerators.Event currentEvent; 15 | private Events events; 16 | 17 | #region Properties 18 | 19 | /// 20 | /// Gets or sets the client which owns the dispatcher. 21 | /// 22 | public Client Client 23 | { 24 | get { return client; } 25 | set { client = value; } 26 | } 27 | 28 | /// 29 | /// Gets or sets the event being processed by this dispatcher. 30 | /// 31 | public Enumerators.Event CurrentEvent 32 | { 33 | get { return currentEvent; } 34 | set { currentEvent = value; } 35 | } 36 | 37 | /// 38 | /// Gets or sets the event handler object instance. 39 | /// 40 | public Events Events 41 | { 42 | get { return events; } 43 | set { events = value; } 44 | } 45 | 46 | #endregion 47 | 48 | /// 49 | /// Dispatches the event, parsing the content of the line and raising the relevant event. 50 | /// 51 | /// The line which was received from the control connection. 52 | /// true if the event is parsed and dispatched successfully; otherwise, false. 53 | public abstract bool Dispatch(string line); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Events/Dispatchers/BandwidthDispatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Tor.Helpers; 6 | 7 | namespace Tor.Events 8 | { 9 | /// 10 | /// A class containing the logic for parsing a bandwidth event. 11 | /// 12 | [EventAssoc(Enumerators.Event.Bandwidth)] 13 | internal sealed class BandwidthDispatcher : Dispatcher 14 | { 15 | #region Tor.Events.Dispatcher 16 | 17 | /// 18 | /// Dispatches the event, parsing the content of the line and raising the relevant event. 19 | /// 20 | /// The line which was received from the control connection. 21 | /// 22 | /// true if the event is parsed and dispatched successfully; otherwise, false. 23 | /// 24 | public override bool Dispatch(string line) 25 | { 26 | string[] parts = StringHelper.GetAll(line, ' '); 27 | 28 | if (parts.Length < 2) 29 | return false; 30 | 31 | double downloaded; 32 | double uploaded; 33 | 34 | if (!double.TryParse(parts[0], out downloaded)) 35 | return false; 36 | 37 | if (!double.TryParse(parts[1], out uploaded)) 38 | return false; 39 | 40 | Events.OnBandwidthChanged(new BandwidthEventArgs(new Bytes(downloaded).Normalize(), new Bytes(uploaded).Normalize())); 41 | return true; 42 | } 43 | 44 | #endregion 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Events/Dispatchers/CircuitDispatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Tor.Helpers; 6 | using System.ComponentModel; 7 | 8 | namespace Tor.Events 9 | { 10 | /// 11 | /// A class containing the logic for parsing a circuit-status event. 12 | /// 13 | [EventAssoc(Enumerators.Event.Circuits)] 14 | internal sealed class CircuitDispatcher : Dispatcher 15 | { 16 | #region Tor.Events.Dispatcher 17 | 18 | /// 19 | /// Dispatches the event, parsing the content of the line and raising the relevant event. 20 | /// 21 | /// The line which was received from the control connection. 22 | /// 23 | /// true if the event is parsed and dispatched successfully; otherwise, false. 24 | /// 25 | public override bool Dispatch(string line) 26 | { 27 | int index = 0; 28 | int circuitID = 0; 29 | string[] parts = StringHelper.GetAll(line, ' '); 30 | Circuit circuit = null; 31 | List routers = new List(); 32 | 33 | if (parts == null || parts.Length < 2) 34 | return false; 35 | 36 | if (!int.TryParse(parts[0], out circuitID)) 37 | return false; 38 | 39 | circuit = new Circuit(Client, circuitID); 40 | circuit.Status = ReflectionHelper.GetEnumerator(attr => parts[1].Equals(attr.Description, StringComparison.CurrentCultureIgnoreCase)); 41 | 42 | for (int i = 2, length = parts.Length; i < length; i++) 43 | { 44 | string data = parts[i]; 45 | 46 | index += data.Length + 1; 47 | data = data.Trim(); 48 | 49 | if (!data.Contains("=")) 50 | { 51 | routers.AddRange(data.Split(',')); 52 | continue; 53 | } 54 | 55 | string[] values = data.Split(new[] { '=' }, 2); 56 | string name = values[0].Trim(); 57 | string value = values[1].Trim(); 58 | 59 | if (name.Equals("BUILD_FLAGS")) 60 | { 61 | string[] flags = value.Split(','); 62 | 63 | foreach (string flag in flags) 64 | circuit.BuildFlags |= ReflectionHelper.GetEnumerator(attr => flag.Equals(attr.Description, StringComparison.CurrentCultureIgnoreCase)); 65 | } 66 | else 67 | { 68 | switch (name) 69 | { 70 | case "HS_STATE": 71 | circuit.HSState = ReflectionHelper.GetEnumerator(attr => value.Equals(attr.Description, StringComparison.CurrentCultureIgnoreCase)); 72 | break; 73 | case "PURPOSE": 74 | circuit.Purpose = ReflectionHelper.GetEnumerator(attr => value.Equals(attr.Description, StringComparison.CurrentCultureIgnoreCase)); 75 | break; 76 | case "REASON": 77 | circuit.Reason = ReflectionHelper.GetEnumerator(attr => value.Equals(attr.Description, StringComparison.CurrentCultureIgnoreCase)); 78 | break; 79 | case "TIME_CREATED": 80 | DateTime timeCreated; 81 | if (DateTime.TryParse(value, out timeCreated)) 82 | circuit.TimeCreated = timeCreated; 83 | else 84 | circuit.TimeCreated = DateTime.MinValue; 85 | break; 86 | } 87 | } 88 | } 89 | 90 | circuit.Paths = routers; 91 | 92 | Events.OnCircuitChanged(new CircuitEventArgs(circuit)); 93 | 94 | return true; 95 | } 96 | 97 | #endregion 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Events/Dispatchers/ConfigChangedDispatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Events 7 | { 8 | /// 9 | /// A class containing the logic for parsing a config-changed event. 10 | /// 11 | [EventAssoc(Enumerators.Event.ConfigChanged)] 12 | internal sealed class ConfigChangedDispatcher : Dispatcher 13 | { 14 | #region Tor.Events.Dispatcher 15 | 16 | /// 17 | /// Dispatches the event, parsing the content of the line and raising the relevant event. 18 | /// 19 | /// The line which was received from the control connection. 20 | /// 21 | /// true if the event is parsed and dispatched successfully; otherwise, false. 22 | /// 23 | public override bool Dispatch(string line) 24 | { 25 | string[] lines = line.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); 26 | 27 | if (lines.Length == 0) 28 | return false; 29 | 30 | Dictionary configurations = new Dictionary(lines.Length); 31 | 32 | foreach (string part in lines) 33 | { 34 | string trimmed = part.Trim(); 35 | 36 | if (trimmed.Length == 0) 37 | continue; 38 | 39 | if (trimmed.StartsWith("650")) 40 | trimmed = trimmed.Substring(3); 41 | if (trimmed.Length > 0 && trimmed[0] == '-') 42 | trimmed = trimmed.Substring(1); 43 | 44 | if (trimmed.Length == 0) 45 | continue; 46 | 47 | string[] values = trimmed.Split(new[] { '=' }, 2); 48 | 49 | if (values.Length == 1) 50 | configurations[values[0].Trim()] = null; 51 | else 52 | configurations[values[0].Trim()] = values[1].Trim(); 53 | } 54 | 55 | Client.Events.OnConfigurationChanged(new ConfigurationChangedEventArgs(configurations)); 56 | 57 | return false; 58 | } 59 | 60 | #endregion 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Events/Dispatchers/LogDispatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Events 7 | { 8 | /// 9 | /// A class containing the logic for parsing a log message event. 10 | /// 11 | [EventAssoc(Enumerators.Event.LogDebug | Enumerators.Event.LogError | Enumerators.Event.LogInfo | Enumerators.Event.LogNotice | Enumerators.Event.LogWarn)] 12 | internal sealed class LogDispatcher : Dispatcher 13 | { 14 | #region Tor.Events.Dispatcher 15 | 16 | /// 17 | /// Dispatches the event, parsing the content of the line and raising the relevant event. 18 | /// 19 | /// The line which was received from the control connection. 20 | /// 21 | /// true if the event is parsed and dispatched successfully; otherwise, false. 22 | /// 23 | public override bool Dispatch(string line) 24 | { 25 | string[] lines = line.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); 26 | 27 | if (lines.Length == 0) 28 | return false; 29 | 30 | foreach (string value in lines) 31 | { 32 | string trimmed = value.Trim(); 33 | 34 | if (trimmed.Length == 0 || trimmed.Equals(".")) 35 | continue; 36 | if (trimmed.StartsWith("250")) 37 | continue; 38 | 39 | Client.Events.OnLogReceived(new LogEventArgs(trimmed), CurrentEvent); 40 | } 41 | 42 | return true; 43 | } 44 | 45 | #endregion 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Events/Dispatchers/ORConnectionDispatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Tor.Helpers; 6 | using System.ComponentModel; 7 | 8 | namespace Tor.Events 9 | { 10 | /// 11 | /// A class containing the logic for dispatching an OR connection changed event. 12 | /// 13 | [EventAssoc(Enumerators.Event.ORConnections)] 14 | internal sealed class ORConnectionDispatcher : Dispatcher 15 | { 16 | #region Tor.Events.Dispatcher 17 | 18 | /// 19 | /// Dispatches the event, parsing the content of the line and raising the relevant event. 20 | /// 21 | /// The line which was received from the control connection. 22 | /// 23 | /// true if the event is parsed and dispatched successfully; otherwise, false. 24 | /// 25 | public override bool Dispatch(string line) 26 | { 27 | string target; 28 | ORStatus status; 29 | string[] parts = StringHelper.GetAll(line, ' '); 30 | 31 | if (parts.Length < 2) 32 | return false; 33 | 34 | target = parts[0]; 35 | status = ReflectionHelper.GetEnumerator(attr => parts[1].Equals(attr.Description, StringComparison.CurrentCultureIgnoreCase)); 36 | 37 | ORConnection connection = new ORConnection(); 38 | connection.Status = status; 39 | connection.Target = target; 40 | 41 | for (int i = 2; i < parts.Length; i++) 42 | { 43 | string data = parts[i].Trim(); 44 | 45 | if (!data.Contains("=")) 46 | continue; 47 | 48 | string[] values = data.Split(new[] { '=' }, 2); 49 | 50 | if (values.Length < 2) 51 | continue; 52 | 53 | string name = values[0].Trim(); 54 | string value = values[1].Trim(); 55 | 56 | if ("REASON".Equals(name, StringComparison.CurrentCultureIgnoreCase)) 57 | { 58 | connection.Reason = ReflectionHelper.GetEnumerator(attr => value.Equals(attr.Description, StringComparison.CurrentCultureIgnoreCase)); 59 | continue; 60 | } 61 | 62 | if ("NCIRCS".Equals(name, StringComparison.CurrentCultureIgnoreCase)) 63 | { 64 | int circuits; 65 | 66 | if (int.TryParse(value, out circuits)) 67 | connection.CircuitCount = circuits; 68 | 69 | continue; 70 | } 71 | 72 | if ("ID".Equals(name, StringComparison.CurrentCultureIgnoreCase)) 73 | { 74 | int id; 75 | 76 | if (int.TryParse(value, out id)) 77 | connection.ID = id; 78 | 79 | continue; 80 | } 81 | } 82 | 83 | Client.Events.OnORConnectionChanged(new ORConnectionEventArgs(connection)); 84 | return true; 85 | } 86 | 87 | #endregion 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Events/Dispatchers/StreamDispatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Tor.Helpers; 6 | using System.ComponentModel; 7 | 8 | namespace Tor.Events 9 | { 10 | /// 11 | /// A class containing the logic for processing a stream-status event. 12 | /// 13 | [EventAssoc(Enumerators.Event.Streams)] 14 | internal sealed class StreamDispatcher : Dispatcher 15 | { 16 | #region Tor.Events.Dispatcher 17 | 18 | /// 19 | /// Dispatches the event, parsing the content of the line and raising the relevant event. 20 | /// 21 | /// The line which was received from the control connection. 22 | /// 23 | /// true if the event is parsed and dispatched successfully; otherwise, false. 24 | /// 25 | public override bool Dispatch(string line) 26 | { 27 | int streamID; 28 | int circuitID; 29 | int port; 30 | StreamStatus status; 31 | Host target; 32 | string[] parts = StringHelper.GetAll(line, ' '); 33 | 34 | if (parts.Length < 4) 35 | return false; 36 | 37 | if ("Tor_internal".Equals(parts[3], StringComparison.CurrentCultureIgnoreCase)) 38 | return false; 39 | 40 | if (!int.TryParse(parts[0], out streamID)) 41 | return false; 42 | 43 | if (!int.TryParse(parts[2], out circuitID)) 44 | return false; 45 | 46 | string[] targetParts = parts[3].Split(new[] { ':' }, 2); 47 | 48 | if (targetParts.Length < 2) 49 | return false; 50 | 51 | if (!int.TryParse(targetParts[1], out port)) 52 | return false; 53 | 54 | status = ReflectionHelper.GetEnumerator(attr => parts[1].Equals(attr.Description, StringComparison.CurrentCultureIgnoreCase)); 55 | target = new Host(targetParts[0], port); 56 | 57 | Stream stream = new Stream(Client, streamID, target); 58 | stream.CircuitID = circuitID; 59 | stream.Status = status; 60 | 61 | for (int i = 4; i < parts.Length; i++) 62 | { 63 | string data = parts[i].Trim(); 64 | 65 | if (!data.Contains("=")) 66 | continue; 67 | 68 | string[] values = data.Split(new[] { '=' }, 2); 69 | 70 | if (values.Length < 2) 71 | continue; 72 | 73 | string name = values[0].Trim(); 74 | string value = values[1].Trim(); 75 | 76 | if ("REASON".Equals(name, StringComparison.CurrentCultureIgnoreCase)) 77 | { 78 | stream.Reason = ReflectionHelper.GetEnumerator(attr => value.Equals(attr.Description, StringComparison.CurrentCultureIgnoreCase)); 79 | continue; 80 | } 81 | 82 | if ("PURPOSE".Equals(name, StringComparison.CurrentCultureIgnoreCase)) 83 | { 84 | stream.Purpose = ReflectionHelper.GetEnumerator(attr => value.Equals(attr.Description, StringComparison.CurrentCultureIgnoreCase)); 85 | continue; 86 | } 87 | } 88 | 89 | Events.OnStreamChanged(new StreamEventArgs(stream)); 90 | return true; 91 | } 92 | 93 | #endregion 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Events/Enumerators/Event.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | namespace Tor.Events.Enumerators 8 | { 9 | /// 10 | /// An enumerator containing the list of events which can be monitored in the tor service. 11 | /// 12 | [Flags] 13 | public enum Event : int 14 | { 15 | /// 16 | /// The event was unrecognised. 17 | /// 18 | [Description(null)] 19 | Unknown = 0x000, 20 | 21 | /// 22 | /// An event raised when the circuit status is changed. 23 | /// 24 | [Description("CIRC")] 25 | Circuits = 0x001, 26 | 27 | /// 28 | /// An event raised when a stream status is changed. 29 | /// 30 | [Description("STREAM")] 31 | Streams = 0x002, 32 | 33 | /// 34 | /// An event raised when an OR connection status is changed. 35 | /// 36 | [Description("ORCONN")] 37 | ORConnections = 0x004, 38 | 39 | /// 40 | /// An event raised when the bandwidth used within the last second has changed. 41 | /// 42 | [Description("BW")] 43 | Bandwidth = 0x008, 44 | 45 | /// 46 | /// An event raised when the value of a configuration has changed. 47 | /// 48 | [Description("CONF_CHANGED")] 49 | ConfigChanged = 0x010, 50 | 51 | /// 52 | /// An event raised when a debug message is produced. 53 | /// 54 | [Description("DEBUG")] 55 | LogDebug = 0x020, 56 | 57 | /// 58 | /// An event raised when an information message is produced. 59 | /// 60 | [Description("INFO")] 61 | LogInfo = 0x040, 62 | 63 | /// 64 | /// An event raised when a notice message is produced. 65 | /// 66 | [Description("NOTICE")] 67 | LogNotice = 0x080, 68 | 69 | /// 70 | /// An event raised when a warning message is produced. 71 | /// 72 | [Description("WARN")] 73 | LogWarn = 0x100, 74 | 75 | /// 76 | /// An event raised when an error message is produced. 77 | /// 78 | [Description("ERR")] 79 | LogError = 0x200, 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Events/Event.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | namespace Tor.Events 8 | { 9 | /// 10 | /// An enumerator containing the list of events which can be monitored in the tor service. 11 | /// 12 | public enum Event 13 | { 14 | /// 15 | /// An event raised when the circuit status is changed. 16 | /// 17 | [Description("CIRC")] 18 | Circuits, 19 | 20 | /// 21 | /// An event raised when a stream status is changed. 22 | /// 23 | [Description("STREAM")] 24 | Streams, 25 | 26 | /// 27 | /// An event raised when an OR connection status is changed. 28 | /// 29 | [Description("ORCONN")] 30 | ORConnections, 31 | 32 | /// 33 | /// An event raised when the bandwidth used within the last second has changed. 34 | /// 35 | [Description("BW")] 36 | Bandwidth, 37 | 38 | /// 39 | /// An event raised when new descriptors are available. 40 | /// 41 | [Description("NEWDESC")] 42 | NewDescriptors, 43 | 44 | /// 45 | /// An event raised when a new address mapping is registered in the tor address map cache. 46 | /// 47 | [Description("ADDRMAP")] 48 | AddressMapping, 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Events/Events/BandwidthEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor 7 | { 8 | /// 9 | /// A class containing information regarding bandwidth values changing. 10 | /// 11 | [Serializable] 12 | public sealed class BandwidthEventArgs : EventArgs 13 | { 14 | private readonly Bytes downloaded; 15 | private readonly Bytes uploaded; 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// The bytes downloaded. 21 | /// The bytes uploaded. 22 | public BandwidthEventArgs(Bytes downloaded, Bytes uploaded) 23 | { 24 | this.downloaded = downloaded; 25 | this.uploaded = uploaded; 26 | } 27 | 28 | #region Properties 29 | 30 | /// 31 | /// Gets the bytes downloaded. 32 | /// 33 | public Bytes Downloaded 34 | { 35 | get { return downloaded; } 36 | } 37 | 38 | /// 39 | /// Gets the bytes uploaded. 40 | /// 41 | public Bytes Uploaded 42 | { 43 | get { return uploaded; } 44 | } 45 | 46 | #endregion 47 | } 48 | 49 | /// 50 | /// Represents the method that will handle a bandwidth changed event. 51 | /// 52 | /// The sender. 53 | /// The instance containing the event data. 54 | public delegate void BandwidthEventHandler(object sender, BandwidthEventArgs e); 55 | } 56 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Events/Events/CircuitEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor 7 | { 8 | /// 9 | /// A class containing information regarding a circuit status changing. 10 | /// 11 | public sealed class CircuitEventArgs : EventArgs 12 | { 13 | private readonly Circuit circuit; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The circuit which was changed. 19 | public CircuitEventArgs(Circuit circuit) 20 | { 21 | this.circuit = circuit; 22 | } 23 | 24 | #region Properties 25 | 26 | /// 27 | /// Gets the circuit which was changed. 28 | /// 29 | public Circuit Circuit 30 | { 31 | get { return circuit; } 32 | } 33 | 34 | #endregion 35 | } 36 | 37 | /// 38 | /// Represents the method that will handle a circuit changed event. 39 | /// 40 | /// The sender. 41 | /// The instance containing the event data. 42 | public delegate void CircuitEventHandler(object sender, CircuitEventArgs e); 43 | } 44 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Events/Events/ConfigurationChangedEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Events 7 | { 8 | /// 9 | /// A class containing information regarding configuration values changing. 10 | /// 11 | public sealed class ConfigurationChangedEventArgs : EventArgs 12 | { 13 | private readonly Dictionary configurations; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The configurations which were changed. 19 | internal ConfigurationChangedEventArgs(Dictionary configurations) 20 | { 21 | this.configurations = configurations; 22 | } 23 | 24 | #region Properties 25 | 26 | /// 27 | /// Gets the configurations which were changed. 28 | /// 29 | public Dictionary Configurations 30 | { 31 | get { return configurations; } 32 | } 33 | 34 | #endregion 35 | } 36 | 37 | /// 38 | /// Represents the method that will handle a configuration changed event. 39 | /// 40 | /// The sender. 41 | /// The instance containing the event data. 42 | public delegate void ConfigurationChangedEventHandler(object sender, ConfigurationChangedEventArgs e); 43 | } 44 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Events/Events/LogEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor 7 | { 8 | /// 9 | /// A class containing information regarding a log message received from a client. 10 | /// 11 | public sealed class LogEventArgs : EventArgs 12 | { 13 | private readonly string message; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The message which was received. 19 | public LogEventArgs(string message) 20 | { 21 | this.message = message; 22 | } 23 | 24 | #region Properties 25 | 26 | /// 27 | /// Gets the message which was received. 28 | /// 29 | public string Message 30 | { 31 | get { return message; } 32 | } 33 | 34 | #endregion 35 | } 36 | 37 | /// 38 | /// Represents the method that will handle a log message event. 39 | /// 40 | /// The sender. 41 | /// The instance containing the event data. 42 | public delegate void LogEventHandler(object sender, LogEventArgs e); 43 | } 44 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Events/Events/ORConnectionEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor 7 | { 8 | /// 9 | /// A class containing information regarding an OR connection event. 10 | /// 11 | [Serializable] 12 | public sealed class ORConnectionEventArgs : EventArgs 13 | { 14 | private readonly ORConnection connection; 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// The connection which was changed. 20 | public ORConnectionEventArgs(ORConnection connection) 21 | { 22 | this.connection = connection; 23 | } 24 | 25 | #region Properties 26 | 27 | /// 28 | /// Gets the connection which was changed. 29 | /// 30 | public ORConnection Connection 31 | { 32 | get { return connection; } 33 | } 34 | 35 | #endregion 36 | } 37 | 38 | /// 39 | /// Represents the method that will handle an OR connection changed event. 40 | /// 41 | /// The sender. 42 | /// The instance containing the event data. 43 | public delegate void ORConnectionEventHandler(object sender, ORConnectionEventArgs e); 44 | } 45 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Events/Events/StreamEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor 7 | { 8 | /// 9 | /// A class containing information regarding a stream status changing. 10 | /// 11 | public sealed class StreamEventArgs : EventArgs 12 | { 13 | private readonly Stream stream; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The stream which was changed. 19 | public StreamEventArgs(Stream stream) 20 | { 21 | this.stream = stream; 22 | } 23 | 24 | #region Properties 25 | 26 | /// 27 | /// Gets the stream which was changed. 28 | /// 29 | public Stream Stream 30 | { 31 | get { return stream; } 32 | } 33 | 34 | #endregion 35 | } 36 | 37 | /// 38 | /// Represents the method that will handle a stream changed event. 39 | /// 40 | /// The sender. 41 | /// The instance containing the event data. 42 | public delegate void StreamEventHandler(object sender, StreamEventArgs e); 43 | } 44 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Logging/Logging.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Tor.Logging 7 | { 8 | /// 9 | /// A class containing the methods and events for interacting with the logging engine within the client. 10 | /// 11 | public sealed class Logging : MarshalByRefObject 12 | { 13 | private readonly Client client; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The client for which this object instance belongs. 19 | internal Logging(Client client) 20 | { 21 | this.client = client; 22 | } 23 | 24 | #region Events 25 | 26 | /// 27 | /// Occurs when a debug message is received. 28 | /// 29 | public event LogEventHandler DebugReceived 30 | { 31 | add { client.Events.DebugReceived += value; } 32 | remove { client.Events.DebugReceived -= value; } 33 | } 34 | 35 | /// 36 | /// Occurs when an error message is received. 37 | /// 38 | public event LogEventHandler ErrorReceived 39 | { 40 | add { client.Events.ErrorReceived += value; } 41 | remove { client.Events.ErrorReceived -= value; } 42 | } 43 | 44 | /// 45 | /// Occurs when an information message is received. 46 | /// 47 | public event LogEventHandler InfoReceived 48 | { 49 | add { client.Events.InfoReceived += value; } 50 | remove { client.Events.InfoReceived -= value; } 51 | } 52 | 53 | /// 54 | /// Occurs when a notice message is received. 55 | /// 56 | public event LogEventHandler NoticeReceived 57 | { 58 | add { client.Events.NoticeReceived += value; } 59 | remove { client.Events.NoticeReceived -= value; } 60 | } 61 | 62 | /// 63 | /// Occurs when a warning message is received. 64 | /// 65 | public event LogEventHandler WarnReceived 66 | { 67 | add { client.Events.WarnReceived += value; } 68 | remove { client.Events.WarnReceived -= value; } 69 | } 70 | 71 | #endregion 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Tor4NET/Tor/ORConnections/Enumerators/ORReason.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | namespace Tor 8 | { 9 | /// 10 | /// An enumerator containing the different reasons for a ORStatus.Closed or ORStatus.Failed state. 11 | /// 12 | public enum ORReason 13 | { 14 | /// 15 | /// The reason was not provided or could not be determined. 16 | /// 17 | [Description(null)] 18 | None, 19 | 20 | /// 21 | /// The OR connection has shut down cleanly. 22 | /// 23 | [Description("DONE")] 24 | Done, 25 | 26 | /// 27 | /// The OR connection received an ECONNREFUSED when connecting to the target OR. 28 | /// 29 | [Description("CONNECTREFUSED")] 30 | ConnectRefused, 31 | 32 | /// 33 | /// The OR connection connected to the OR, but the identity was not what was expected. 34 | /// 35 | [Description("IDENTITY")] 36 | Identity, 37 | 38 | /// 39 | /// The OR connection received an ECONNRESET or similar IO error from OR. 40 | /// 41 | [Description("CONNECTRESET")] 42 | ConnectReset, 43 | 44 | /// 45 | /// The OR connection received an ETIMEOUT or similar IO eerror from the OR, or the connection 46 | /// has been terminated for being open for too long. 47 | /// 48 | [Description("TIMEOUT")] 49 | Timeout, 50 | 51 | /// 52 | /// The OR connection received an ENOTCONN, ENETUNREACH, ENETDOWN, EHOSTUNREACH or 53 | /// similar error while connecting to the OR. 54 | /// 55 | [Description("NOROUTE")] 56 | NoRoute, 57 | 58 | /// 59 | /// The OR connection received a different IO error. 60 | /// 61 | [Description("IOERROR")] 62 | IOError, 63 | 64 | /// 65 | /// The OR connection does not have enough system resources to connect to the OR. 66 | /// 67 | [Description("RESOURCELIMIT")] 68 | ResourceLimit, 69 | 70 | /// 71 | /// No pluggable transport was available. 72 | /// 73 | [Description("PT_MISSING")] 74 | PTMissing, 75 | 76 | /// 77 | /// The OR connection closed for some other reason. 78 | /// 79 | [Description("MISC")] 80 | Misc 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Tor4NET/Tor/ORConnections/Enumerators/ORStatus.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | namespace Tor 8 | { 9 | /// 10 | /// An enumerator containing the different states of an OR connection. 11 | /// 12 | public enum ORStatus 13 | { 14 | /// 15 | /// No status was not provided or the status could not be determined. 16 | /// 17 | [Description(null)] 18 | None, 19 | 20 | /// 21 | /// The OR connection has been received and is beginning the handshake process. 22 | /// 23 | [Description("NEW")] 24 | New, 25 | 26 | /// 27 | /// The OR connection has been launched and is beginning the client-side handshake process. 28 | /// 29 | [Description("LAUNCHED")] 30 | Launched, 31 | 32 | /// 33 | /// The OR connection has been connected and the handshake is complete. 34 | /// 35 | [Description("CONNECTED")] 36 | Connected, 37 | 38 | /// 39 | /// The OR connection failed. 40 | /// 41 | [Description("FAILED")] 42 | Failed, 43 | 44 | /// 45 | /// The OR connection closed. 46 | /// 47 | [Description("CLOSED")] 48 | Closed 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Tor4NET/Tor/ORConnections/ORConnection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Collections.ObjectModel; 6 | 7 | namespace Tor 8 | { 9 | /// 10 | /// A class containing information regarding an OR connection within the tor service. 11 | /// 12 | [Serializable] 13 | public sealed class ORConnection 14 | { 15 | private int circuitCount; 16 | private int id; 17 | private ORReason reason; 18 | private ORStatus status; 19 | private string target; 20 | 21 | /// 22 | /// Initializes a new instance of the class. 23 | /// 24 | internal ORConnection() 25 | { 26 | this.circuitCount = 0; 27 | this.id = 0; 28 | this.reason = ORReason.None; 29 | this.status = ORStatus.None; 30 | this.target = ""; 31 | } 32 | 33 | #region Properties 34 | 35 | /// 36 | /// Gets the number of established and pending circuits. 37 | /// 38 | public int CircuitCount 39 | { 40 | get { return circuitCount; } 41 | internal set { circuitCount = value; } 42 | } 43 | 44 | /// 45 | /// Gets the unique identifier of the connection. This value is only provided in version 0.2.5.2-alpha. 46 | /// 47 | public int ID 48 | { 49 | get { return id; } 50 | internal set { id = value; } 51 | } 52 | 53 | /// 54 | /// Gets the reason for an ORStatus.Closed or ORStatus.Failed state. 55 | /// 56 | public ORReason Reason 57 | { 58 | get { return reason; } 59 | internal set { reason = value; } 60 | } 61 | 62 | /// 63 | /// Gets the status of the connection. 64 | /// 65 | public ORStatus Status 66 | { 67 | get { return status; } 68 | internal set { status = value; } 69 | } 70 | 71 | /// 72 | /// Gets the target of the connection. 73 | /// 74 | public string Target 75 | { 76 | get { return target; } 77 | internal set { target = value; } 78 | } 79 | 80 | #endregion 81 | } 82 | 83 | /// 84 | /// A class containing a read-only collection of objects. 85 | /// 86 | public sealed class ORConnectionCollection : ReadOnlyCollection 87 | { 88 | /// 89 | /// Initializes a new instance of the class. 90 | /// 91 | /// The list of OR connections. 92 | internal ORConnectionCollection(IList list) : base(list) 93 | { 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Proxy/Socks5Proxy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Net; 6 | 7 | namespace Tor.Proxy 8 | { 9 | /// 10 | /// A class which implements the interface to provide routing of HTTP requests. 11 | /// 12 | public sealed class Socks5Proxy : IWebProxy 13 | { 14 | private readonly Client client; 15 | 16 | private ICredentials credentials; 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | /// The client for which this object instance belongs. 22 | internal Socks5Proxy(Client client) 23 | { 24 | this.client = client; 25 | } 26 | 27 | #region Properties 28 | 29 | /// 30 | /// The credentials to submit to the proxy server for authentication. 31 | /// 32 | public ICredentials Credentials 33 | { 34 | get { return credentials; } 35 | set { credentials = value; } 36 | } 37 | 38 | #endregion 39 | 40 | /// 41 | /// Returns the URI of a proxy. 42 | /// 43 | /// A that specifies the requested Internet resource. 44 | /// 45 | /// A instance that contains the URI of the proxy used to contact . 46 | /// 47 | public Uri GetProxy(Uri destination) 48 | { 49 | return new Uri(string.Format("http://127.0.0.1:{0}", client.Proxy.Port)); 50 | } 51 | 52 | /// 53 | /// Indicates that the proxy should not be used for the specified host. 54 | /// 55 | /// The of the host to check for proxy use. 56 | /// 57 | /// true if the proxy server should not be used for ; otherwise, false. 58 | /// 59 | public bool IsBypassed(Uri host) 60 | { 61 | return !client.Proxy.IsRunning; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Routers/Enumerators/RouterFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | namespace Tor 8 | { 9 | /// 10 | /// An enumerator containing different flags which may be associated with a router. 11 | /// 12 | [Flags] 13 | public enum RouterFlags : int 14 | { 15 | /// 16 | /// No flags were associated with the router. 17 | /// 18 | [Description(null)] 19 | None = 0x0000, 20 | 21 | /// 22 | /// The router is a directory authority. 23 | /// 24 | [Description("Authority")] 25 | Authority = 0x0001, 26 | 27 | /// 28 | /// The router is considered useless as an exit node. 29 | /// 30 | [Description("BadExit")] 31 | BadExit = 0x0002, 32 | 33 | /// 34 | /// The router is more useful for building general-purpose exit circuits, rather than router circuits. 35 | /// 36 | [Description("Exit")] 37 | Exit = 0x0004, 38 | 39 | /// 40 | /// The router is suitable for high-bandwidth circuits. 41 | /// 42 | [Description("Fast")] 43 | Fast = 0x0008, 44 | 45 | /// 46 | /// The router is suitable for use as an entry guard. 47 | /// 48 | [Description("Guard")] 49 | Guard = 0x0010, 50 | 51 | /// 52 | /// The router is considered a v2 hidden-service directory. 53 | /// 54 | [Description("HSDir")] 55 | HSDir = 0x0020, 56 | 57 | /// 58 | /// The router's identity-nickname mapping is canonical, and this authority binds names. 59 | /// 60 | [Description("Named")] 61 | Named = 0x0040, 62 | 63 | /// 64 | /// The router is suitable for long-lived circuits. 65 | /// 66 | [Description("Stable")] 67 | Stable = 0x0080, 68 | 69 | /// 70 | /// The router is currently usable. 71 | /// 72 | [Description("Running")] 73 | Running = 0x0100, 74 | 75 | /// 76 | /// The router's name has been bound by another router, and this authority binds names. 77 | /// 78 | [Description("Unnamed")] 79 | Unnamed = 0x0200, 80 | 81 | /// 82 | /// The router has been validated. 83 | /// 84 | [Description("Valid")] 85 | Valid = 0x0400, 86 | 87 | /// 88 | /// The router implements the v2 directory protocol, or higher. 89 | /// 90 | [Description("V2Dir")] 91 | V2Dir = 0x0800, 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Routers/Router.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Collections.ObjectModel; 6 | using System.Net; 7 | 8 | namespace Tor 9 | { 10 | /// 11 | /// A class containing information regarding a router within a circuit. 12 | /// 13 | [Serializable] 14 | public sealed class Router 15 | { 16 | private Bytes bandwidth; 17 | private string digest; 18 | private int dirPort; 19 | private RouterFlags flags; 20 | private string identity; 21 | private IPAddress ipAddress; 22 | private string nickname; 23 | private int orPort; 24 | private DateTime publication; 25 | 26 | /// 27 | /// Initializes a new instance of the class. 28 | /// 29 | /// The circuit containing the router. 30 | internal Router() 31 | { 32 | this.bandwidth = Bytes.Empty; 33 | this.digest = null; 34 | this.dirPort = -1; 35 | this.flags = RouterFlags.None; 36 | this.identity = null; 37 | this.ipAddress = null; 38 | this.nickname = null; 39 | this.orPort = -1; 40 | this.publication = DateTime.MinValue; 41 | } 42 | 43 | #region Properties 44 | 45 | /// 46 | /// Gets the bandwidth of the router. 47 | /// 48 | public Bytes Bandwidth 49 | { 50 | get { return bandwidth; } 51 | internal set { bandwidth = value; } 52 | } 53 | 54 | /// 55 | /// Gets the digest of the router. This is the hash of the most recent descriptor, encoded in base64. 56 | /// 57 | public string Digest 58 | { 59 | get { return digest; } 60 | internal set { digest = value; } 61 | } 62 | 63 | /// 64 | /// Gets the current directory port of the router. 65 | /// 66 | public int DIRPort 67 | { 68 | get { return dirPort; } 69 | internal set { dirPort = value; } 70 | } 71 | 72 | /// 73 | /// Gets the flags assigned against the router. 74 | /// 75 | public RouterFlags Flags 76 | { 77 | get { return flags; } 78 | internal set { flags = value; } 79 | } 80 | 81 | /// 82 | /// Gets the encoded hash identity of the router, encoded in base 64 with trailing equal symbols removed. 83 | /// 84 | public string Identity 85 | { 86 | get { return identity; } 87 | internal set { identity = value; } 88 | } 89 | 90 | /// 91 | /// Gets the IP address of the router. 92 | /// 93 | public IPAddress IPAddress 94 | { 95 | get { return ipAddress; } 96 | internal set { ipAddress = value; } 97 | } 98 | 99 | /// 100 | /// Gets the nickname of the router. 101 | /// 102 | public string Nickname 103 | { 104 | get { return nickname; } 105 | internal set { nickname = value; } 106 | } 107 | 108 | /// 109 | /// Gets the current OR port of the router. 110 | /// 111 | public int ORPort 112 | { 113 | get { return orPort; } 114 | internal set { orPort = value; } 115 | } 116 | 117 | /// 118 | /// Gets the publication time of the most recent descriptor. 119 | /// 120 | public DateTime Publication 121 | { 122 | get { return publication; } 123 | internal set { publication = value; } 124 | } 125 | 126 | #endregion 127 | } 128 | 129 | /// 130 | /// A class containing a read-only collection of objects. 131 | /// 132 | public sealed class RouterCollection : ReadOnlyCollection 133 | { 134 | /// 135 | /// Initializes a new instance of the class. 136 | /// 137 | /// The list of routers. 138 | internal RouterCollection(IList list) : base(list) 139 | { 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Streams/Enumerators/StreamPurpose.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | namespace Tor 8 | { 9 | /// 10 | /// An enumerator containing the different purposes for a stream, which is provided when extended events are enabled. 11 | /// 12 | public enum StreamPurpose 13 | { 14 | /// 15 | /// A purpose was not provided. 16 | /// 17 | [Description(null)] 18 | None, 19 | 20 | /// 21 | /// The stream was generated internally for fetching directory information. 22 | /// 23 | [Description("DIR_FETCH")] 24 | DirectoryFetch, 25 | 26 | /// 27 | /// The stream was generated internally for uploading information to a directory authority. 28 | /// 29 | [Description("DIR_READ")] 30 | DirectoryRead, 31 | 32 | /// 33 | /// The stream is a user-initiated DNS request. 34 | /// 35 | [Description("DNS_REQUEST")] 36 | DNSRequest, 37 | 38 | /// 39 | /// The stream is used explicitly for testing whether our hosted directory port is accessible. 40 | /// 41 | [Description("DIRPORT_TEST")] 42 | DirectoryPortTest, 43 | 44 | /// 45 | /// The stream is likely handling a user request. This could also be an internal stream, and none of the other 46 | /// purposes match the real purpose of the stream. 47 | /// 48 | [Description("USER")] 49 | User, 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Streams/Enumerators/StreamReason.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | namespace Tor 8 | { 9 | /// 10 | /// An enumerator containing the reasons for a stream's failed, closed or detached events. 11 | /// 12 | public enum StreamReason : int 13 | { 14 | /// 15 | /// No reason was provided. 16 | /// 17 | [Description(null)] 18 | None = 0, 19 | 20 | /// 21 | /// A miscellaneous error occurred. 22 | /// 23 | [Description("MISC")] 24 | Misc = 1, 25 | 26 | /// 27 | /// The stream failed to resolve an address. 28 | /// 29 | [Description("RESOLVEFAILED")] 30 | ResolveFailed = 2, 31 | 32 | /// 33 | /// The stream connect attempt was refused. 34 | /// 35 | [Description("CONNECTREFUSED")] 36 | ConnectRefused = 3, 37 | 38 | /// 39 | /// The exit policy failed. 40 | /// 41 | [Description("EXITPOLICY")] 42 | ExitPolicy = 4, 43 | 44 | /// 45 | /// The stream was destroyed. 46 | /// 47 | [Description("DESTROY")] 48 | Destroy = 5, 49 | 50 | /// 51 | /// The stream closed normally. 52 | /// 53 | [Description("DONE")] 54 | Done = 6, 55 | 56 | /// 57 | /// The stream timed out. 58 | /// 59 | [Description("TIMEOUT")] 60 | Timeout = 7, 61 | 62 | /// 63 | /// There is no route to the host. 64 | /// 65 | [Description("NOROUTE")] 66 | NoRoute = 8, 67 | 68 | /// 69 | /// The server is hibernating. 70 | /// 71 | [Description("HIBERNATING")] 72 | Hibernating = 9, 73 | 74 | /// 75 | /// An internal error occurred. 76 | /// 77 | [Description("INTERNAL")] 78 | Internal = 10, 79 | 80 | /// 81 | /// The server ran out of resources. 82 | /// 83 | [Description("RESOURCELIMIT")] 84 | ResourceLimit = 11, 85 | 86 | /// 87 | /// The connection was reset. 88 | /// 89 | [Description("CONNRESET")] 90 | ConnReset = 12, 91 | 92 | /// 93 | /// There was a tor protocol error. 94 | /// 95 | [Description("TORPROTOCOL")] 96 | TorProtocol = 13, 97 | 98 | /// 99 | /// The stream was not accessing a directory. 100 | /// 101 | [Description("NOTDIRECTORY")] 102 | NotDirectory = 14, 103 | 104 | /// 105 | /// A relay-end cell was received. 106 | /// 107 | [Description("END")] 108 | End = -1, 109 | 110 | /// 111 | /// The client tried to connect to a private address. 112 | /// 113 | [Description("PRIVATE_ADDR")] 114 | PrivateAddr = -1, 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Streams/Enumerators/StreamStatus.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | namespace Tor 8 | { 9 | /// 10 | /// An enumerator containing the different possible statuses for a stream. 11 | /// 12 | public enum StreamStatus 13 | { 14 | /// 15 | /// The stream status was not provided. 16 | /// 17 | [Description(null)] 18 | None, 19 | 20 | /// 21 | /// A new request to connect. 22 | /// 23 | [Description("NEW")] 24 | New, 25 | 26 | /// 27 | /// A new request to resolve an address. 28 | /// 29 | [Description("NEWRESOLVE")] 30 | NewResolve, 31 | 32 | /// 33 | /// An address was re-mapped to another. 34 | /// 35 | [Description("REMAP")] 36 | Remap, 37 | 38 | /// 39 | /// A connect cell was sent along a circuit. 40 | /// 41 | [Description("SENTCONNECT")] 42 | SentConnect, 43 | 44 | /// 45 | /// A resolve cell was sent along the circuit. 46 | /// 47 | [Description("SENTRESOLVE")] 48 | SentResolve, 49 | 50 | /// 51 | /// A reply was received and the stream was established. 52 | /// 53 | [Description("SUCCEEDED")] 54 | Succeeded, 55 | 56 | /// 57 | /// The stream failed and cannot be retried. 58 | /// 59 | [Description("FAILED")] 60 | Failed, 61 | 62 | /// 63 | /// The stream is closed. 64 | /// 65 | [Description("CLOSED")] 66 | Closed, 67 | 68 | /// 69 | /// The stream was detached from a circuit, but can be retried. 70 | /// 71 | [Description("DETACHED")] 72 | Detached, 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Tor4NET/Tor/Streams/Stream.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Collections.ObjectModel; 6 | 7 | namespace Tor 8 | { 9 | /// 10 | /// A class containing information about an active or inactive stream within the tor network service. 11 | /// 12 | public sealed class Stream : MarshalByRefObject 13 | { 14 | private readonly Client client; 15 | private readonly int id; 16 | private readonly Host target; 17 | 18 | private int circuitID; 19 | private StreamPurpose purpose; 20 | private StreamReason reason; 21 | private StreamStatus status; 22 | 23 | /// 24 | /// Initializes a new instance of the class. 25 | /// 26 | /// The client for which the stream belongs. 27 | /// The unique identifier of the stream within the tor session. 28 | /// The target of the stream. 29 | internal Stream(Client client, int id, Host target) 30 | { 31 | this.circuitID = 0; 32 | this.client = client; 33 | this.id = id; 34 | this.purpose = StreamPurpose.None; 35 | this.reason = StreamReason.None; 36 | this.status = StreamStatus.None; 37 | this.target = target; 38 | } 39 | 40 | #region Properties 41 | 42 | /// 43 | /// Gets the unique identifier of the circuit which owns this stream. This will be zero if the stream has been detached. 44 | /// 45 | public int CircuitID 46 | { 47 | get { return circuitID; } 48 | internal set { circuitID = value; } 49 | } 50 | 51 | /// 52 | /// Gets the unique identifier of the stream in the tor session. 53 | /// 54 | public int ID 55 | { 56 | get { return id; } 57 | } 58 | 59 | /// 60 | /// Gets the purpose for the stream. This will be StreamPurpose.None unless extended events are enabled. 61 | /// 62 | public StreamPurpose Purpose 63 | { 64 | get { return purpose; } 65 | internal set { purpose = value; } 66 | } 67 | 68 | /// 69 | /// Gets the reason for the stream being closed, failed or detached. This will be StreamReason.None until the stream 70 | /// has reached either of the aforementioned states. 71 | /// 72 | public StreamReason Reason 73 | { 74 | get { return reason; } 75 | internal set { reason = value; } 76 | } 77 | 78 | /// 79 | /// Gets the status of the stream. 80 | /// 81 | public StreamStatus Status 82 | { 83 | get { return status; } 84 | internal set { status = value; } 85 | } 86 | 87 | /// 88 | /// Gets the target of the stream. 89 | /// 90 | public Host Target 91 | { 92 | get { return target; } 93 | } 94 | 95 | #endregion 96 | 97 | /// 98 | /// Closes the stream. 99 | /// 100 | /// true if the stream is closed successfully; otherwise, false. 101 | public bool Close() 102 | { 103 | return client.Controller.CloseStream(this, StreamReason.Misc); 104 | } 105 | } 106 | 107 | /// 108 | /// A class containing a read-only collection of objects. 109 | /// 110 | public sealed class StreamCollection : ReadOnlyCollection 111 | { 112 | /// 113 | /// Initializes a new instance of the class. 114 | /// 115 | /// The list of streams. 116 | internal StreamCollection(IList list) : base(list) 117 | { 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /Tor4NET/Tor4NET.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | false 6 | false 7 | Zaczero (Kamil Monicz) 8 | https://github.com/Zaczero/Tor4NET 9 | 10 | 1.3.1 11 | Copyright © Kamil Monicz 2020 12 | 13 | tor, proxy, socks5, http, https, onion, dark, web, hidden, onion service, 14 | An all-in-one solution to fulfill your .NET dark web needs 15 | 1.3.1.0 16 | https://github.com/Zaczero/Tor4NET 17 | 18 | 1.3.1.0 19 | MIT 20 | Tor4NET_small.png 21 | true 22 | true 23 | snupkg 24 | 25 | 26 | 27 | AnyCPU 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | True 37 | 38 | 39 | 40 | 41 | 42 | 43 | all 44 | runtime; build; native; contentfiles; analyzers; buildtransitive 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Tor4NET/TorUpdater.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net.Http; 4 | using System.Text.RegularExpressions; 5 | using System.Threading.Tasks; 6 | 7 | namespace Tor4NET 8 | { 9 | internal class TorUpdater 10 | { 11 | private readonly struct TorVersion 12 | { 13 | private readonly string source; 14 | 15 | public readonly int Major; 16 | public readonly int Minor; 17 | public readonly int Patch; 18 | public readonly string Suffix; 19 | 20 | public TorVersion(string version) 21 | { 22 | source = version; 23 | 24 | var match = ReleaseVersioningRegex.Match(version); 25 | if (!match.Success) 26 | { 27 | Major = 0; 28 | Minor = 0; 29 | Patch = 0; 30 | Suffix = string.Empty; 31 | return; 32 | } 33 | 34 | var matchMajor = match.Groups["major"].Value; 35 | if (matchMajor.Length == 0) 36 | matchMajor = "0"; 37 | 38 | var matchMinor = match.Groups["minor"].Value; 39 | if (matchMinor.Length == 0) 40 | matchMinor = "0"; 41 | 42 | var matchPatch = match.Groups["patch"].Value; 43 | if (matchPatch.Length == 0) 44 | matchPatch = "0"; 45 | 46 | var matchSuffix = match.Groups["suffix"].Value; 47 | if (matchSuffix.Length == 0) 48 | matchSuffix = string.Empty; 49 | 50 | Major = int.TryParse(matchMajor, out var matchMajorInt) ? matchMajorInt : 0; 51 | Minor = int.TryParse(matchMinor, out var matchMinorInt) ? matchMinorInt : 0; 52 | Patch = int.TryParse(matchPatch, out var matchPatchInt) ? matchPatchInt : 0; 53 | Suffix = matchSuffix; 54 | } 55 | 56 | public override string ToString() 57 | { 58 | return source; 59 | } 60 | } 61 | 62 | private const string BaseUrl = "https://dist.torproject.org/torbrowser/"; 63 | 64 | private static readonly Regex ReleaseHtmlRegex = new Regex(@"alt=""\[DIR\]""> \d+(?:\.\S+)*?)\/"">(?:\d+(?:\.\S+)*?)\/<\/a>\s*(?\d{4})-(?\d{2})-(?\d{2})"); 65 | private static readonly Regex ReleaseVersioningRegex = new Regex(@"(?\d+)(?:\.(?\d+)(?:\.(?\d+))?)?(?\S+)?"); 66 | 67 | private readonly Regex versionRegex; 68 | private readonly HttpClient httpClient; 69 | private readonly bool x86; 70 | 71 | public TorUpdater(HttpClient httpClient, bool x86 = true) 72 | { 73 | versionRegex = x86 ? 74 | new Regex(@"tor-win32-(?\S+?)\.zip") : 75 | new Regex(@"tor-win64-(?\S+?)\.zip"); 76 | 77 | this.httpClient = httpClient; 78 | this.x86 = x86; 79 | } 80 | 81 | private async Task GetReleaseList() 82 | { 83 | var html = await httpClient.GetStringAsync(BaseUrl); 84 | 85 | var releaseMatches = ReleaseHtmlRegex.Matches(html); 86 | var releases = new TorVersion[releaseMatches.Count]; 87 | var releaseIndex = 0; 88 | 89 | foreach (Match match in releaseMatches) 90 | releases[releaseIndex++] = new TorVersion(match.Groups["release"].Value); 91 | 92 | Array.Sort(releases, (left, right) => 93 | { 94 | if (left.Major > right.Major) 95 | return -1; 96 | if (left.Major < right.Major) 97 | return 1; 98 | 99 | if (left.Minor > right.Minor) 100 | return -1; 101 | if (left.Minor < right.Minor) 102 | return 1; 103 | 104 | if (left.Patch > right.Patch) 105 | return -1; 106 | if (left.Patch < right.Patch) 107 | return 1; 108 | 109 | return string.Compare(right.Suffix, left.Suffix, StringComparison.Ordinal); 110 | }); 111 | 112 | var result = new string[releases.Length]; 113 | 114 | for (var i = 0; i < releases.Length; i++) 115 | result[i] = releases[i].ToString(); 116 | 117 | return result; 118 | } 119 | 120 | public async Task<(string, string)> GetLatestVersion() 121 | { 122 | var releases = await GetReleaseList(); 123 | if (releases.Length == 0) 124 | return (string.Empty, string.Empty); 125 | 126 | foreach (var release in releases) 127 | { 128 | var (_, version) = await GetLatestVersion(release); 129 | if (version.Length > 0) 130 | return (release, version); 131 | } 132 | 133 | return (string.Empty, string.Empty); 134 | } 135 | 136 | private async Task<(string, string)> GetLatestVersion(string release) 137 | { 138 | // backwards compatibility when `release` parameter is null 139 | if (release == null) 140 | return await GetLatestVersion(); 141 | 142 | var url = $"{BaseUrl}{release}/"; 143 | var html = await httpClient.GetStringAsync(url); 144 | 145 | return (release, versionRegex.Match(html).Groups["version"].Value); 146 | } 147 | 148 | public async Task DownloadUpdate(string release = null, string version = null) 149 | { 150 | if (version == null) 151 | (release, version) = await GetLatestVersion(release); 152 | 153 | return await httpClient.GetStreamAsync($"{BaseUrl}{release}/tor-win{(x86 ? "32" : "64")}-{version}.zip"); 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /Tor4NET/publish.bat: -------------------------------------------------------------------------------- 1 | @echo OFF 2 | dotnet publish -c Release 3 | dotnet pack -c Release 4 | pause -------------------------------------------------------------------------------- /icons/Tor4NET.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zaczero/Tor4NET/4dfd9ef3a95ca3d2d961946cc1abdf9f85941055/icons/Tor4NET.png -------------------------------------------------------------------------------- /icons/Tor4NET.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zaczero/Tor4NET/4dfd9ef3a95ca3d2d961946cc1abdf9f85941055/icons/Tor4NET.xcf -------------------------------------------------------------------------------- /icons/Tor4NET_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zaczero/Tor4NET/4dfd9ef3a95ca3d2d961946cc1abdf9f85941055/icons/Tor4NET_icon.png -------------------------------------------------------------------------------- /icons/Tor4NET_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zaczero/Tor4NET/4dfd9ef3a95ca3d2d961946cc1abdf9f85941055/icons/Tor4NET_small.png --------------------------------------------------------------------------------