├── torflow.csproj.user
├── Program.cs
├── torflow.sln
├── README.md
├── UNLICENSE
├── Properties
└── AssemblyInfo.cs
├── torflow.csproj
├── Tests
└── Test1.cs
└── Lib
└── TorFlow.cs
/torflow.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ShowAllFiles
5 |
6 |
--------------------------------------------------------------------------------
/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Windows.Forms;
6 |
7 | namespace torflow
8 | {
9 | class Program
10 | {
11 | static void Main(string[] args)
12 | {
13 | new Tests1.TorFlow(args);
14 | Application.Run();
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/torflow.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31702.278
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "torflow", "torflow.csproj", "{1ACAF9A5-7254-4F0F-B346-55F435D1A64C}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {1ACAF9A5-7254-4F0F-B346-55F435D1A64C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {1ACAF9A5-7254-4F0F-B346-55F435D1A64C}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {1ACAF9A5-7254-4F0F-B346-55F435D1A64C}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {1ACAF9A5-7254-4F0F-B346-55F435D1A64C}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {A7AAA913-0E2E-4FAF-9CD7-9CF757889A99}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TorFlow (Updated: 13-Jan-2022)
2 |
3 | ## License
4 | Unlicense
5 |
6 | ### Requirements
7 | - Binary files of [TOR (Use official instead!)](https://github.com/SlowsieNT/TorFlow/releases/tag/resources)
8 | - .NET 3.5+
9 |
10 | __Example__:
11 | ```cs
12 | TorProcess vTorProcess = new TorProcess {
13 | // (Both paths are full filenames)
14 | ExecutablePath = "etc/tor/tor.exe",
15 | TorrcFilePath = "etc/Config"
16 | };
17 | // Once you call AddHiddenService, it will return HiddenService
18 | // HiddenService.AddPort will return HiddenService
19 | // Meaning you can call AddPort over and over again
20 | vTorProcess.Torrc.AddHiddenService("etc/website01").AddPort(11, 81).AddPort(24, 181);
21 | vTorProcess.Torrc.AddHiddenService("etc/website02").AddPort(80, 8080);
22 | // Handle events (optional, yes)
23 | vTorProcess.OnLine += TorProcess1_OnLine;
24 | vTorProcess.OnReady += TorProcess1_OnReady;
25 | vTorProcess.OnState += TorProcess1_OnState;
26 | // To get hostname of onion, best to use this:
27 | vTorProcess.OnHiddenServiceCreated += TorProcess1_OnHiddenServiceCreated;
28 | // Set data directory where the tor is supposed to write files
29 | vTorProcess.Torrc.DataDirectory = "etc/TorData";
30 | // Run the Thread
31 | vTorProcess.Run();
32 | ```
33 |
--------------------------------------------------------------------------------
/UNLICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("torflow")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("torflow")]
13 | [assembly: AssemblyCopyright("Copyright © 2021")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("1acaf9a5-7254-4f0f-b346-55f435d1a64c")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/torflow.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {1ACAF9A5-7254-4F0F-B346-55F435D1A64C}
8 | Exe
9 | torflow
10 | torflow
11 | v3.5
12 | 512
13 | true
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/Tests/Test1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Text.RegularExpressions;
6 | using System.Linq;
7 | using System.Threading;
8 | using System.Windows.Forms;
9 | using TorFlow;
10 |
11 | namespace Tests1 {
12 | public class TorFlow {
13 | public TorFlow(string[] aArgs) {
14 | // NOTE: You don't need to kill tor,
15 | // is usually independent tor instance.
16 | // Feel free to remove this line:
17 | Process.Start("tskill", "tor /a").WaitForExit();
18 | SampleRun1();
19 | }
20 | void SampleRun1() {
21 | // Very simple instancing
22 | TorProcess vTorProcess = new TorProcess {
23 | // (Both paths are full filenames)
24 | ExecutablePath = "etc/tor/tor.exe",
25 | TorrcFilePath = "etc/Config"
26 | };
27 | // Once you call AddHiddenService, it will return HiddenService
28 | // HiddenService.AddPort will return HiddenService
29 | // Meaning you can call AddPort over and over again
30 | vTorProcess.Torrc.AddHiddenService("etc/website01").AddPort(11, 81).AddPort(24, 181);
31 | vTorProcess.Torrc.AddHiddenService("etc/website02").AddPort(80, 8080);
32 | // Handle events
33 | vTorProcess.OnLine += TorProcess1_OnLine;
34 | vTorProcess.OnReady += TorProcess1_OnReady;
35 | vTorProcess.OnState += TorProcess1_OnState;
36 | vTorProcess.OnHiddenServiceCreated += VTorProcess_OnHiddenServiceCreated;
37 | // Set data directory where the tor is supposed to write files
38 | vTorProcess.Torrc.DataDirectory = "etc/TorData";
39 | // Run the Thread
40 | vTorProcess.Run();
41 | }
42 |
43 | private void VTorProcess_OnHiddenServiceCreated(TorProcess aTorProc, TorProcess.HiddenService aValue) {
44 | Console.WriteLine(aValue.Hostname.Trim() + ":" + aValue.ToString(1));
45 | }
46 |
47 | private void TorProcess1_OnState(TorProcess aTorProc, int aValue) {
48 | Console.Title = TorProcess.GetStateAsText(aValue);
49 | }
50 |
51 | private void TorProcess1_OnReady(TorProcess aTorProc) {
52 | //Console.Clear();
53 | Console.Title = "ONIONs served!!!";
54 | // KILL THE TOR ASAP
55 | aTorProc.Kill();
56 | }
57 |
58 | private void TorProcess1_OnLine(TorProcess aTorProc, string aValue) {
59 | Console.WriteLine(aValue);
60 | }
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/Lib/TorFlow.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Text.RegularExpressions;
8 | using System.Threading;
9 |
10 | namespace TorFlow {
11 |
12 | /// Most events are background threads, remember: use try-catch.
13 | public class TorProcess {
14 | static string[] m_psStates = "Error,Starting,Running,Ready,Exited,Restarting".Split(',');
15 | public static string GetStateAsText(int aState) {
16 | return m_psStates[aState];
17 | }
18 | /// Return state, use int/null to avoid errors.
19 | ///
null returns current state as text.
20 | public string this[object aState] {
21 | get {
22 | if (null == aState)
23 | return m_psStates[State];
24 | // Disable out of bounds
25 | if (m_psStates.Length > (ushort)aState)
26 | return m_psStates[(int)aState];
27 | return this[null];
28 | }
29 | }
30 | public delegate void TorDelegateDef(TorProcess aTorProc);
31 | public delegate void TorDelegateInt(TorProcess aTorProc, int aValue);
32 | public delegate void TorDelegateString(TorProcess aTorProc, string aValue);
33 | public delegate void TorDelegateEx(TorProcess aTorProc, object aValue, int aDataType);
34 | public delegate void TorDelegateHS(TorProcess aTorProc, HiddenService aValue);
35 | public delegate void TorDelegateIntArray(TorProcess aTorProc, int[] aValue);
36 | /// Called when tor finishes bootstrapping.
37 | public event TorDelegateDef OnReady;
38 | public event TorDelegateDef OnClose;
39 | public event TorDelegateDef OnRestarting;
40 | public event TorDelegateInt OnState;
41 | public event TorDelegateHS OnHiddenServiceCreated;
42 | /// Silence is golden.
43 | public event TorDelegateEx OnError;
44 | /// This event is not background thread.
45 | ///
Useful when more ports are needed.
46 | public event TorDelegateIntArray OnTorrcPreparedPorts;
47 | /// Called every ReadLine of tor output
48 | public event TorDelegateString OnLine;
49 | /// On Bootstrapping
50 | public event TorDelegateInt OnRapping;
51 | /// Process ID
52 | public int Id;
53 | /// Used if tor is not intended to be terminated at all
54 | public bool Persist = true;
55 | /// Doesn't work for hidden service class
56 | public bool MakeDirs = true;
57 | /// Full File path to tor executable
58 | public string ExecutablePath = "dir/tor.exe";
59 | /// Full File path to torrc
60 | public string TorrcFilePath = "dir/torrc";
61 | /// States:
62 | /// 0 Error, 1 BeforeStart, 2 Running,
63 | /// 3 Ready, 4 Exited, 5 Restarting
64 | ///
65 | public int State;
66 | /// Time to wait [ms] before reinitiating tor process.
67 | public int RestartDelay = 1025;
68 | public TorConfig Torrc;
69 | public Process m_Process;
70 | public TorProcess() {
71 | Torrc = new TorConfig(this);
72 | }
73 | /// Run the background Thread.
74 | public void Run() {
75 | ThreadPool.QueueUserWorkItem(UserWorkItemRun);
76 | }
77 | /// Terminate Process, will reinitiate if abPersist is false.
78 | public void Kill(bool abPersist=false) {
79 | Persist = abPersist;
80 | m_Process.Kill();
81 | }
82 | void FakeAsync(WaitCallback aAction) {
83 | ThreadPool.QueueUserWorkItem(aAction);
84 | }
85 | void InvokeOnHiddenServiceCreated(HiddenService aHiddenService) {
86 | FakeAsync(delegate (object aState) {
87 | OnHiddenServiceCreated?.Invoke(this, aHiddenService);
88 | });
89 | }
90 | void InvokeOnError(object aValue, int aDataType) {
91 | FakeAsync(delegate (object aState) {
92 | OnError?.Invoke(this, aValue, aDataType);
93 | });
94 | }
95 | void InvokeOnState(int aValue) {
96 | FakeAsync(delegate (object aState) {
97 | OnState?.Invoke(this, aValue);
98 | });
99 | }
100 | void InvokeOnRapping(int aValue) {
101 | FakeAsync(delegate (object aState) {
102 | OnRapping?.Invoke(this, aValue);
103 | });
104 | }
105 | void InvokeOnReady() {
106 | FakeAsync(delegate (object aState) {
107 | OnReady?.Invoke(this);
108 | });
109 | }
110 | void InvokeOnLine(string aValue) {
111 | FakeAsync(delegate (object aState) {
112 | OnLine?.Invoke(this, aValue);
113 | });
114 | }
115 | private void InvokeOnClose() {
116 | FakeAsync(delegate (object aState) {
117 | OnClose?.Invoke(this);
118 | });
119 | }
120 | private void InvokeOnRestarting() {
121 | FakeAsync(delegate (object aState) {
122 | OnRestarting?.Invoke(this);
123 | });
124 | }
125 | void UserWorkItemRun(object aState) {
126 | // Make sure all possible dirs are made
127 | if (MakeDirs) {
128 | IOUtils.MakeDirAll(IOUtils.ToDirs(TorrcFilePath));
129 | IOUtils.MakeDirAll(Torrc.DataDirectory);
130 | }
131 | // Attempt to write torrc file
132 | IOUtils.WriteAllText(TorrcFilePath, "" + Torrc);
133 | // Check if all paths exist
134 | if (!File.Exists(TorrcFilePath))
135 | InvokeOnError(TorrcFilePath + "\r\n", 0);
136 | if (!File.Exists(ExecutablePath))
137 | InvokeOnError(ExecutablePath + "\r\n", 0);
138 | if (!Directory.Exists(Torrc.DataDirectory))
139 | InvokeOnError(Torrc.DataDirectory + "\r\n", 0);
140 | m_Process = new Process {
141 | StartInfo = new ProcessStartInfo {
142 | FileName = ExecutablePath,
143 | Arguments = "-f " + '"' + TorrcFilePath + '"',
144 | UseShellExecute = false,
145 | RedirectStandardOutput = true,
146 | CreateNoWindow = true
147 | }
148 | };
149 | InvokeOnState(State = 1);
150 | try {
151 | m_Process.Start();
152 | Id = m_Process.Id;
153 | } catch (Exception vEx) {
154 | InvokeOnState(State = 0);
155 | InvokeOnError(vEx, 1);
156 | return;
157 | }
158 | // Report that TOR is alive and running
159 | InvokeOnState(State = 2);
160 | // While running, and console output incoming...
161 | while (!m_Process.StandardOutput.EndOfStream) {
162 | // Read console output line by line
163 | string vLine = m_Process.StandardOutput.ReadLine();
164 | // Report each line to OnLine event
165 | InvokeOnLine(vLine);
166 | // TOR enjoys rap
167 | if (vLine.Contains("rapped ")) {
168 | // Get % of how much it rapped
169 | string vStrInt = Regex.Split(vLine, "rapped ")[1].Split('%')[0];
170 | // Parse % and pass to event OnRapping
171 | InvokeOnRapping(int.Parse(vStrInt));
172 | // If TOR rapped enough, report READY
173 | if ("100" == vStrInt) {
174 | InvokeOnState(State = 3);
175 | InvokeOnReady();
176 | }
177 | }
178 | }
179 | // Report its refusal to rap
180 | InvokeOnState(State = 4);
181 | InvokeOnClose();
182 | // Run tor again if escalated
183 | if (Persist) {
184 | Thread.Sleep(RestartDelay);
185 | InvokeOnState(State = 5);
186 | InvokeOnRestarting();
187 | UserWorkItemRun(aState);
188 | }
189 | }
190 |
191 | public class TorConfig {
192 | TorProcess m_TProc;
193 | public TorConfig(TorProcess aTorProc) {
194 | m_TProc = aTorProc;
195 | ThreadPool.QueueUserWorkItem(UserWorkItemListenHostnames);
196 | }
197 | public int PreparePortCount = 0;
198 | public int[] PreparedPorts;
199 | void UserWorkItemListenHostnames(object state) {
200 | while (true) {
201 | for (int vI = 0; vI < TorHiddenServices.Count; vI++) {
202 | var vHS = TorHiddenServices[vI];
203 | if (vHS != null && default == vHS.Hostname) {
204 | var vFileName = vHS.Directory + "/hostname";
205 | // Attempt to read hostname.
206 | vHS.Hostname = IOUtils.ReadAllText(vFileName);
207 | if (default != vHS.Hostname)
208 | m_TProc.InvokeOnHiddenServiceCreated(vHS);
209 | }
210 | }
211 | Thread.Sleep(1000/50); // 50 Op/s
212 | }
213 | }
214 | public void PreparePorts() {
215 | List vPorts = new List(new int[] { TcpUtils.GetOpenPort() });
216 | for (int vI = 0; vI < PreparePortCount; vI++)
217 | vPorts.Add(TcpUtils.GetOpenPort(1 + vPorts[vI]));
218 | PreparedPorts = vPorts.ToArray();
219 | }
220 | public override string ToString() {
221 | if (null == PreparedPorts) {
222 | PreparePorts();
223 | m_TProc.OnTorrcPreparedPorts?.Invoke(m_TProc, PreparedPorts);
224 | }
225 | if (0 == PreparedPorts.Length) {
226 | PreparePorts();
227 | m_TProc.OnTorrcPreparedPorts?.Invoke(m_TProc, PreparedPorts);
228 | }
229 | string vOutput = "";
230 | if ("auto" == SocksPort)
231 | SocksPort = "" + PreparedPorts[0];
232 | if (AvoidDiskWrites) vOutput += "AvoidDiskWrites 1" + "\r\n";
233 | // GeoIP checks before alloc
234 | if (File.Exists(GeoIPFile)) vOutput += "GeoIPFile " + GeoIPFile + "\r\n";
235 | if (File.Exists(GeoIPv6File)) vOutput += "GeoIPv6File " + GeoIPv6File + "\r\n";
236 | // DataDirectory before alloc
237 | if (m_TProc.MakeDirs)
238 | IOUtils.MakeDirAll(DataDirectory);
239 | if (Directory.Exists(DataDirectory))
240 | vOutput += "DataDirectory " + DataDirectory + "\r\n";
241 | vOutput += "ControlPort " + ControlPort + " " + ControlPortFlags + "\r\n";
242 | vOutput += "SocksPort " + SocksPort + " " + SocksPortFlags + "\r\n";
243 | foreach (HiddenService vHS in TorHiddenServices) {
244 | vOutput += "HiddenServiceDir " + vHS.Directory + "\r\n";
245 | foreach (HiddenServicePort vPort in vHS.Ports)
246 | vOutput += "HiddenServicePort " + vPort.OnionPort + " " + vPort.ServerPort + "\r\n";
247 | }
248 | return vOutput;
249 | }
250 | public bool AvoidDiskWrites = true; // default=0
251 | /// If not found, will attempt to create automatically.
252 | public string DataDirectory;
253 | public string ControlPort = "auto";
254 | public string ControlPortFlags = "";
255 | public string SocksPort = "auto";
256 | public string SocksPortFlags = "IPv6Traffic PreferIPv6";
257 | public string GeoIPFile, GeoIPv6File;
258 | public List CustomLines = new List();
259 | public List TorHiddenServices = new List();
260 | public bool RemoveCustomAt(int aIndex) {
261 | if (CustomLines.Count > aIndex) {
262 | CustomLines.RemoveAt(aIndex);
263 | return true;
264 | }
265 | return false;
266 | }
267 | public int AddCustom(string aValue, string aValue2) {
268 | return AddCustom(aValue + " " + aValue2);
269 | }
270 | public int AddCustom(string aValue) {
271 | CustomLines.Add(aValue);
272 | return CustomLines.Count - 1;
273 | }
274 | ///
275 | /// Used if hosting onion service, no port forwarding required.
276 | ///
277 | /// If not found, will attempt to create automatically.
278 | /// HiddenService always.
279 | public HiddenService AddHiddenService(string aDirectory) {
280 | HiddenService vHS = new HiddenService(aDirectory);
281 | TorHiddenServices.Add(vHS);
282 | return vHS;
283 | }
284 | }
285 | /// No port forwarding required.
286 | public class HiddenServicePort {
287 | public int OnionPort = 80, ServerPort = 8080;
288 | public string ServerHost = "";
289 | public HiddenServicePort(int aOnionPort, int aServerPort, string aServerHost) { OnionPort = aOnionPort; ServerPort = aServerPort; ServerHost = aServerHost; }
290 | public HiddenServicePort(int aOnionPort, int aServerPort) { OnionPort = aOnionPort; ServerPort = aServerPort; }
291 | public HiddenServicePort(int aServerPort) { ServerPort = aServerPort; }
292 | public HiddenServicePort() { }
293 | public override string ToString() {
294 | string vStr = ServerHost;
295 | if (0 < vStr.Length)
296 | vStr += ":";
297 | return OnionPort + " " + vStr + ServerPort;
298 | }
299 | }
300 | public class HiddenService {
301 | public string Directory;
302 | /// Hostname is readonly
303 | public string Hostname;
304 | public List Ports = new List();
305 | public HiddenService(string aDir) {
306 | Directory = aDir;
307 | IOUtils.MakeDirAll(aDir);
308 | }
309 | public HiddenService AddPort(int vOnionPort, int vServerPort) {
310 | Ports.Add(new HiddenServicePort(vOnionPort, vServerPort));
311 | return this;
312 | }
313 | /// ToString(1) will return onion ports separated by comma
314 | public string ToString(int aWhat) {
315 | if (1 == aWhat) {
316 | string vOut = "";
317 | for (int vI = 0; vI < Ports.Count; vI++)
318 | vOut += Ports[vI].OnionPort + ", ";
319 | // Remove trailing comma
320 | if (vOut.Length > 3)
321 | return vOut.Substring(0, vOut.Length - 2);
322 | }
323 | return ToString();
324 | }
325 | public override string ToString() {
326 | string vOutput = "HiddenServiceDir " + Directory + "\r\n";
327 | for (int vI = 0, vL = Ports.Count; vI < vL; vI++) {
328 | vOutput += "HiddenServicePort " + Ports[vI];
329 | if (vI + 1 < vL) vOutput += "\r\n";
330 | }
331 | return vOutput;
332 | }
333 | }
334 |
335 | }
336 | public class IOUtils {
337 | public static string ToDirs(string aString) {
338 | string vOutput = "", vTemp = "";
339 | for (int vI = 0, vL = aString.Length; vI < vL; vI++) {
340 | if ('\\' == aString[vI] || '/' == aString[vI]) {
341 | vOutput += vTemp + "/";
342 | vTemp = "";
343 | } else vTemp += aString[vI];
344 | }
345 | return vOutput;
346 | }
347 | public static bool MakeDirAll(string aDirname) {
348 | try {
349 | if (!Directory.Exists(aDirname))
350 | Directory.CreateDirectory(aDirname);
351 | return true;
352 | } catch { return false; }
353 | }
354 | public static bool DeleteFile(string aPath) {
355 | try {
356 | if (File.Exists(aPath))
357 | File.Delete(aPath);
358 | return true;
359 | } catch { return false; }
360 | }
361 | public static bool DeleteDir(string aPath) {
362 | try {
363 | if (Directory.Exists(aPath))
364 | Directory.Delete(aPath, true);
365 | return true;
366 | } catch { return false; }
367 | }
368 | public static bool WriteAllText(string aFilename, string aContent) {
369 | try {
370 | File.WriteAllText(aFilename, aContent);
371 | return true;
372 | } catch { return false; }
373 | }
374 | public static string ReadAllText(string aFilename) {
375 | try {
376 | if (!File.Exists(aFilename)) return default;
377 | return File.ReadAllText(aFilename);
378 | } catch { return default; }
379 | }
380 | }
381 | public class TcpUtils {
382 | public static int GetOpenPort(int aPStart = 9000, int aPEnd = 60000) {
383 | int vUUPort = 0;
384 | System.Net.NetworkInformation.IPGlobalProperties vProps = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties();
385 | var vTEP = vProps.GetActiveTcpListeners();
386 | var vUPorts = (from vP in vTEP select vP.Port).ToList();
387 | for (int vPort = aPStart; vPort < aPEnd; vPort++)
388 | if (!vUPorts.Contains(vPort)) {
389 | vUUPort = vPort;
390 | break;
391 | }
392 | return vUUPort;
393 | }
394 | }
395 | }
396 |
--------------------------------------------------------------------------------