Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
Socks5Server.cs
1using System;
2using System.Collections.Generic;
3using System.Net;
4using System.Net.NetworkInformation;
5using System.Net.Sockets;
6using System.Threading.Tasks;
7using Waher.Events;
11
13{
17 public class Socks5Server : CommunicationLayer, IDisposable
18 {
22 public const int DefaultPort = 1080;
23
27 public const int DefaultConnectionBacklog = 10;
28
29 private LinkedList<TcpListener> listeners = new LinkedList<TcpListener>();
30 private Cache<CaseInsensitiveString, Pair> connections;
31 private bool disposed = false;
32
38 : this(DefaultPort, Sniffers)
39 {
40 }
41
47 public Socks5Server(int Port, params ISniffer[] Sniffers)
48 : this(new int[] { Port }, Sniffers)
49 {
50 }
51
57 public Socks5Server(int[] Ports, params ISniffer[] Sniffers)
58 : base(false, Sniffers)
59 {
60 this.connections = new Cache<CaseInsensitiveString, Pair>(int.MaxValue, TimeSpan.MaxValue, TimeSpan.FromMinutes(1), true);
61 this.connections.Removed += this.ClientConnections_Removed;
62
63 this.Initialize(Ports);
64 }
65
66 private async void Initialize(int[] Ports)
67 {
68 try
69 {
70 TcpListener Listener;
71
72 foreach (NetworkInterface Interface in NetworkInterface.GetAllNetworkInterfaces())
73 {
74 if (Interface.OperationalStatus != OperationalStatus.Up)
75 continue;
76
77 IPInterfaceProperties Properties = Interface.GetIPProperties();
78
79 foreach (UnicastIPAddressInformation UnicastAddress in Properties.UnicastAddresses)
80 {
81 if ((UnicastAddress.Address.AddressFamily == AddressFamily.InterNetwork && Socket.OSSupportsIPv4) ||
82 (UnicastAddress.Address.AddressFamily == AddressFamily.InterNetworkV6 && Socket.OSSupportsIPv6))
83 {
84 if (!(Ports is null))
85 {
86 foreach (int C2sPort in Ports)
87 {
88 try
89 {
90 await this.Information("Opening port " + C2sPort.ToString() + " on " + UnicastAddress.Address.ToString() + ".");
91
92 Listener = new TcpListener(UnicastAddress.Address, C2sPort);
93 Listener.Start(DefaultConnectionBacklog);
94 Listener.BeginAcceptTcpClient(this.AcceptTcpClientCallback, Listener);
95 this.listeners.AddLast(Listener);
96
97 await this.Information("Port " + C2sPort.ToString() + " on " + UnicastAddress.Address.ToString() + " opened.");
98 }
99 catch (Exception ex)
100 {
101 Log.Exception(ex, UnicastAddress.Address.ToString() + ":" + C2sPort);
102 }
103 }
104 }
105 }
106 }
107 }
108 }
109 catch (Exception ex)
110 {
111 Log.Exception(ex);
112 }
113 }
114
115 internal bool RegisterConnection(string StreamId, Socks5Connection Connection)
116 {
117 if (this.connections.TryGetValue(StreamId, out Pair P))
118 {
119 if (P.Connection2 is null)
120 P.Connection2 = Connection;
121 else
122 return false;
123 }
124 else
125 {
126 this.connections[StreamId] = new Pair()
127 {
128 Connection1 = Connection
129 };
130 }
131
132 return true;
133 }
134
135 internal void UnregisterStream(string StreamId, Socks5Connection Connection)
136 {
137 if (this.connections.TryGetValue(StreamId, out Pair P))
138 {
139 if (P.Connection1 == Connection)
140 {
141 P.Closed1 = true;
142 if (P.Closed2)
143 this.connections.Remove(StreamId);
144 else
145 P.Connection2?.CloseWhenDone();
146 }
147 else if (P.Connection2 == Connection)
148 {
149 P.Closed2 = true;
150 if (P.Closed1)
151 this.connections.Remove(StreamId);
152 else
153 P.Connection1?.CloseWhenDone();
154 }
155 }
156 }
157
158 internal bool TryGetRemoteEndpoint(string StreamId, Socks5Connection Sender, out Socks5Connection Receiver)
159 {
160 if (this.connections.TryGetValue(StreamId, out Pair P))
161 {
162 if (P.Connection1 == Sender)
163 Receiver = P.Connection2;
164 else if (P.Connection2 == Sender)
165 Receiver = P.Connection1;
166 else
167 Receiver = null;
168 }
169 else
170 Receiver = null;
171
172 return !(Receiver is null);
173 }
174
175 internal bool Activate(string StreamId)
176 {
177 if (!this.connections.TryGetValue(StreamId, out Pair P))
178 return false;
179
180 if (P.Connection1 is null ||
181 P.Connection2 is null ||
182 !P.Connection1.WaitingForActivation ||
183 !P.Connection2.WaitingForActivation)
184 {
185 return false;
186 }
187
188 P.Connection1.Activate();
189 P.Connection2.Activate();
190
191 return true;
192 }
193
194 private class Pair
195 {
196 public Socks5Connection Connection1 = null;
197 public Socks5Connection Connection2 = null;
198 public bool Closed1 = false;
199 public bool Closed2 = false;
200 }
201
202 private Task ClientConnections_Removed(object Sender, CacheItemEventArgs<CaseInsensitiveString, Pair> e)
203 {
204 e.Value.Connection1?.Dispose();
205 e.Value.Connection2?.Dispose();
206
207 return Task.CompletedTask;
208 }
209
213 public void Dispose()
214 {
215 this.disposed = true;
216
217 this.connections?.Clear();
218 this.connections?.Dispose();
219 this.connections = null;
220
221 if (!(this.listeners is null))
222 {
223 LinkedList<TcpListener> Listeners = this.listeners;
224 this.listeners = null;
225
226 foreach (TcpListener Listener in Listeners)
227 Listener.Stop();
228 }
229 }
230
234 public int[] OpenC2SPorts
235 {
236 get
237 {
238 SortedDictionary<int, bool> Open = new SortedDictionary<int, bool>();
239
240 if (!(this.listeners is null))
241 {
242 IPEndPoint IPEndPoint;
243
244 foreach (TcpListener Listener in this.listeners)
245 {
246 IPEndPoint = Listener.LocalEndpoint as IPEndPoint;
247 if (!(IPEndPoint is null))
248 Open[IPEndPoint.Port] = true;
249 }
250 }
251
252 int[] Result = new int[Open.Count];
253 Open.Keys.CopyTo(Result, 0);
254
255 return Result;
256 }
257 }
258
262 public bool IsOpen
263 {
264 get
265 {
266 return !(this.listeners?.First is null);
267 }
268 }
269
270 private async void AcceptTcpClientCallback(IAsyncResult ar)
271 {
272 try
273 {
274 if (this.disposed || NetworkingModule.Stopping)
275 return;
276
277 TcpListener Listener = (TcpListener)ar.AsyncState;
278
279 if (!this.disposed)
280 {
281 try
282 {
283 TcpClient Client = Listener.EndAcceptTcpClient(ar);
284 await this.Information("Connection accepted from " + Client.Client.RemoteEndPoint.ToString() + ".");
285
287 BinaryTcpClient.Bind(true);
288
290
292 }
293 finally
294 {
295 if (!this.disposed)
296 Listener.BeginAcceptTcpClient(this.AcceptTcpClientCallback, Listener);
297 }
298 }
299 }
300 catch (SocketException)
301 {
302 // Ignore
303 }
304 catch (ObjectDisposedException)
305 {
306 // Ignore
307 }
308 catch (NullReferenceException)
309 {
310 // Ignore
311 }
312 catch (Exception ex)
313 {
314 if (this.listeners is null)
315 return;
316
317 Log.Exception(ex);
318 }
319 }
320
321 }
322}
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Definition: Log.cs:1647
Implements a binary TCP Client, by encapsulating a TcpClient. It also makes the use of TcpClient safe...
void Bind()
Binds to a TcpClient that was already connected when provided to the constructor.
void Continue()
Continues reading from the socket, if paused in an event handler.
Simple base class for classes implementing communication protocols.
ISniffer[] Sniffers
Registered sniffers.
Task Information(string Comment)
Called to inform the viewer of something.
Module that controls the life cycle of communication.
static bool Stopping
If the system is stopping.
Socks5Server(int[] Ports, params ISniffer[] Sniffers)
SOCKS5 server.
Definition: Socks5Server.cs:57
int[] OpenC2SPorts
C2S Ports successfully opened.
Socks5Server(params ISniffer[] Sniffers)
SOCKS5 server. Default port will be used.
Definition: Socks5Server.cs:37
Socks5Server(int Port, params ISniffer[] Sniffers)
SOCKS5 server.
Definition: Socks5Server.cs:47
const int DefaultPort
Default SOCKS5 Port (1080).
Definition: Socks5Server.cs:22
bool IsOpen
If the server is open and accepts incoming connections.
const int DefaultConnectionBacklog
Default Connection backlog (10).
Definition: Socks5Server.cs:27
Implements an in-memory cache.
Definition: Cache.cs:15
void Dispose()
IDisposable.Dispose
Definition: Cache.cs:74
bool Remove(KeyType Key)
Removes an item from the cache.
Definition: Cache.cs:451
bool TryGetValue(KeyType Key, out ValueType Value)
Tries to get a value from the cache.
Definition: Cache.cs:203
void Clear()
Clears the cache.
Definition: Cache.cs:484
Event arguments for cache item removal events.
ValueType Value
Value of item that was removed.
Interface for sniffers. Sniffers can be added to ICommunicationLayer classes to eavesdrop on communic...
Definition: ISniffer.cs:11