├── .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 | # 
2 |
3 | [](https://travis-ci.com/Zaczero/Tor4NET)
4 | [](https://github.com/Zaczero/Tor4NET/releases/latest)
5 | [](https://www.nuget.org/packages/Tor4NET/)
6 | [](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
--------------------------------------------------------------------------------