6using System.Threading.Tasks;
64 private readonly
object synchObj =
new object();
65 private readonly
string host;
66 private readonly
int port;
67 private readonly
string jid;
68 private bool closeWhenDone =
false;
69 private bool disposed =
false;
70 private object callbackState;
71 private object tag =
null;
72 private bool isWriting =
false;
93 this.
Information(
"Connecting to " + this.host +
":" + this.port.ToString());
105 private async
void Connect()
109 this.client.OnReceived += this.Client_OnReceived;
110 this.client.OnSent += this.Client_OnSent;
111 this.client.OnError += this.Client_OnError;
112 this.client.OnDisconnected += this.Client_OnDisconnected;
113 this.client.OnWriteQueueEmpty += this.Client_OnWriteQueueEmpty;
119 this.
Information(
"Connected to " + this.host +
":" + this.port.ToString());
122 await this.SendPacket(
true,
new byte[] { 5, 1, 0 });
131 private async Task Client_OnWriteQueueEmpty(
object Sender, EventArgs e)
137 this.isWriting =
false;
138 DoDispose = this.closeWhenDone;
147 private Task Client_OnDisconnected(
object Sender, EventArgs e)
152 private Task Client_OnError(
object Sender, Exception Exception)
157 private Task Client_OnSent(
object Sender,
bool ConstantBuffer,
byte[] Buffer,
int Offset,
int Count)
162 return Task.CompletedTask;
165 private async Task<bool> Client_OnReceived(
object Sender,
bool ConstantBuffer,
byte[] Buffer,
int Offset,
int Count)
172 await this.ParseIncoming(Buffer, Offset, Count);
189 if (this.state != NewState)
191 this.state = NewState;
192 this.
Information(
"State changed to " + this.state.ToString());
198 internal object CallbackState
200 get => this.callbackState;
201 set => this.callbackState = value;
210 set => this.tag = value;
221 public string Host => this.host;
231 public string JID => this.jid;
236 [Obsolete(
"Use DisposeAsync()")]
249 this.disposed =
true;
252 if (!(this.client is
null))
265 [Obsolete(
"Use an overload with a ConstantBuffer argument. This increases performance, as the buffer will not be unnecessarily cloned if queued.")]
266 public Task<bool>
Send(
byte[] Data)
268 return this.
Send(
false, Data);
278 public Task<bool>
Send(
bool ConstantBuffer,
byte[] Data)
281 throw new IOException(
"SOCKS5 connection not open.");
283 return this.SendPacket(ConstantBuffer, Data);
286 private Task<bool> SendPacket(
bool ConstantBuffer,
byte[] Data)
290 this.isWriting =
true;
293 return this.client.
SendAsync(ConstantBuffer, Data);
310 this.closeWhenDone =
true;
311 return Task.CompletedTask;
318 private async Task ParseIncoming(
byte[] Buffer,
int Offset,
int Count)
324 if (Count < 2 || Buffer[Offset++] < 5)
326 await this.ToError();
330 byte Method = Buffer[Offset++];
339 await this.ToError();
345 int c = Offset + Count;
347 if (Count < 5 || Buffer[Offset++] < 5)
349 await this.ToError();
353 byte REP = Buffer[Offset++];
362 this.
Error(
"General SOCKS server failure.");
363 await this.ToError();
367 this.
Error(
"Connection not allowed by ruleset.");
368 await this.ToError();
372 this.
Error(
"Network unreachable.");
373 await this.ToError();
377 this.
Error(
"Host unreachable.");
378 await this.ToError();
382 this.
Error(
"Connection refused.");
383 await this.ToError();
387 this.
Error(
"TTL expired.");
388 await this.ToError();
392 this.
Error(
"Command not supported.");
393 await this.ToError();
397 this.
Error(
"Address type not supported.");
398 await this.ToError();
402 this.
Error(
"Unrecognized error code returned: " + REP.ToString());
403 await this.ToError();
409 byte ATYP = Buffer[Offset++];
410 IPAddress Addr =
null;
411 string DomainName =
null;
418 this.
Error(
"Expected more bytes.");
419 await this.ToError();
423 byte[] A =
new byte[4];
424 System.Buffer.BlockCopy(Buffer, Offset, A, 0, 4);
426 Addr =
new IPAddress(A);
430 byte NrBytes = Buffer[Offset++];
431 if (Offset + NrBytes > c)
433 this.
Error(
"Expected more bytes.");
434 await this.ToError();
438 DomainName = Encoding.ASCII.GetString(Buffer, Offset, NrBytes);
445 this.
Error(
"Expected more bytes.");
446 await this.ToError();
451 System.Buffer.BlockCopy(Buffer, Offset, A, 0, 16);
453 Addr =
new IPAddress(A);
457 await this.ToError();
463 this.
Error(
"Invalid number of bytes received.");
464 await this.ToError();
468 int Port = Buffer[Offset++];
470 Port |= Buffer[Offset++];
472 await this.
OnResponse.Raise(
this,
new ResponseEventArgs(REP, Addr, DomainName,
Port),
false);
479 public event EventHandlerAsync<ResponseEventArgs>
OnResponse =
null;
486 private async Task ToError()
494 using MemoryStream Req =
new MemoryStream();
500 if (DestinationAddress.AddressFamily == AddressFamily.InterNetwork)
502 else if (DestinationAddress.AddressFamily == AddressFamily.InterNetworkV6)
505 throw new ArgumentException(
"Invalid address family.", nameof(DestinationAddress));
507 byte[] Addr = DestinationAddress.GetAddressBytes();
508 Req.Write(Addr, 0, Addr.Length);
509 Req.WriteByte((
byte)(
Port >> 8));
510 Req.WriteByte((
byte)
Port);
512 return this.SendPacket(
true, Req.ToArray());
517 using MemoryStream Req =
new MemoryStream();
524 byte[] Bytes = Encoding.ASCII.GetBytes(DestinationDomainName);
525 int c = Bytes.Length;
527 throw new IOException(
"Domain name too long.");
529 Req.WriteByte((
byte)c);
530 Req.Write(Bytes, 0, Bytes.Length);
531 Req.WriteByte((
byte)(
Port >> 8));
532 Req.WriteByte((
byte)
Port);
534 return this.SendPacket(
true, Req.ToArray());
545 return this.Request(
Command.CONNECT, DestinationAddress,
Port);
556 return this.Request(
Command.CONNECT, DestinationDomainName,
Port);
566 public Task
CONNECT(
string StreamID,
string RequesterJID,
string TargetJID)
568 string s = StreamID + RequesterJID + TargetJID;
570 StringBuilder sb =
new StringBuilder();
572 foreach (
byte b
in Hash)
573 sb.Append(b.ToString(
"x2"));
575 return this.
CONNECT(sb.ToString(), 0);
584 public Task
BIND(IPAddress DestinationAddress,
int Port)
586 return this.Request(
Command.BIND, DestinationAddress,
Port);
595 public Task
BIND(
string DestinationDomainName,
int Port)
597 return this.Request(
Command.BIND, DestinationDomainName,
Port);
608 return this.Request(
Command.UDP_ASSOCIATE, DestinationAddress,
Port);
619 return this.Request(
Command.UDP_ASSOCIATE, DestinationDomainName,
Port);
Static class managing the application event log. Applications and services log events on this static ...
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.
Implements a binary TCP Client, by encapsulating a TcpClient. It also makes the use of TcpClient safe...
Task< bool > SendAsync(byte[] Packet)
Sends a binary packet.
virtual Task DisposeAsync()
Disposes of the object asynchronously. The underlying TcpClient is either disposed directly,...
Task< bool > ConnectAsync(string Host, int Port)
Connects to a host using TCP.
Simple base class for classes implementing communication protocols.
void Exception(Exception Exception)
Called to inform the viewer of an exception state.
ISniffer[] Sniffers
Registered sniffers.
bool HasSniffers
If there are sniffers registered on the object.
void Error(string Error)
Called to inform the viewer of an error state.
void TransmitBinary(int Count)
Called when binary data has been transmitted.
void ReceiveBinary(int Count)
Called when binary data has been received.
void Information(string Comment)
Called to inform the viewer of something.
Event arguments for data reception events.
Client used for SOCKS5 communication.
Task CONNECT(string StreamID, string RequesterJID, string TargetJID)
XMPP-specific SOCKS5 connection, as described in XEP-0065: https://xmpp.org/extensions/xep-0065....
Task CONNECT(string DestinationDomainName, int Port)
Connects to the target.
EventHandlerAsync< ResponseEventArgs > OnResponse
Event raised when a response has been returned.
Task UDP_ASSOCIATE(string DestinationDomainName, int Port)
Establish an association within the UDP relay process.
EventHandlerAsync OnWriteQueueEmpty
Event raised when the write queue is empty.
Task CloseWhenDone()
Closes the stream when all bytes have been sent.
EventHandlerAsync OnStateChange
Event raised whenever the state changes.
string Host
Host of SOCKS5 stream host.
Socks5State State
Current state.
Task BIND(IPAddress DestinationAddress, int Port)
Binds to the target.
Task< bool > Send(byte[] Data)
Send binary data.
EventHandlerAsync< DataReceivedEventArgs > OnDataReceived
Event raised when binary data has been received over an established connection.
Socks5Client(string Host, int Port, string JID, params ISniffer[] Sniffers)
Client used for SOCKS5 communication.
int Port
Port of SOCKS5 stream host.
Task BIND(string DestinationDomainName, int Port)
Binds to the target.
async Task DisposeAsync()
IDisposable.Dispose
Task CONNECT(IPAddress DestinationAddress, int Port)
Connects to the target.
Task UDP_ASSOCIATE(IPAddress DestinationAddress, int Port)
Establish an association within the UDP relay process.
void Dispose()
IDisposable.Dispose
Task< bool > Send(bool ConstantBuffer, byte[] Data)
Send binary data.
string JID
JID of SOCKS5 stream host.
Contains methods for simple hash calculations.
static byte[] ComputeSHA1Hash(byte[] Data)
Computes the SHA-1 hash of a block of binary data.
Interface for objects that contain a reference to a host.
Interface for asynchronously disposable objects.
Interface for sniffers. Sniffers can be added to ICommunicationLayer classes to eavesdrop on communic...
delegate Task EventHandlerAsync(object Sender, EventArgs e)
Asynchronous version of EventArgs.
Socks5State
SOCKS5 connection state.