4using System.Net.Sockets;
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 await 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 await this.
Information(
"Connected to " + this.host +
":" + this.port.ToString());
122 await this.SendPacket(
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,
byte[] Buffer,
int Offset,
int Count)
162 return Task.CompletedTask;
165 private async Task<bool> Client_OnReceived(
object Sender,
byte[] Buffer,
int Offset,
int Count)
172 await this.ParseIncoming(Buffer, Offset, Count);
189 if (this.state != NewState)
191 this.state = NewState;
192 await 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;
240 this.disposed =
true;
253 public Task<bool>
Send(
byte[] Data)
256 throw new IOException(
"SOCKS5 connection not open.");
258 return this.SendPacket(Data);
261 private Task<bool> SendPacket(
byte[] Data)
265 this.isWriting =
true;
285 this.closeWhenDone =
true;
293 private async Task ParseIncoming(
byte[] Buffer,
int Offset,
int Count)
299 if (Count < 2 || Buffer[Offset++] < 5)
301 await this.ToError();
305 byte Method = Buffer[Offset++];
314 await this.ToError();
320 int c = Offset + Count;
322 if (Count < 5 || Buffer[Offset++] < 5)
324 await this.ToError();
328 byte REP = Buffer[Offset++];
337 await this.
Error(
"General SOCKS server failure.");
338 await this.ToError();
342 await this.
Error(
"Connection not allowed by ruleset.");
343 await this.ToError();
347 await this.
Error(
"Network unreachable.");
348 await this.ToError();
352 await this.
Error(
"Host unreachable.");
353 await this.ToError();
357 await this.
Error(
"Connection refused.");
358 await this.ToError();
362 await this.
Error(
"TTL expired.");
363 await this.ToError();
367 await this.
Error(
"Command not supported.");
368 await this.ToError();
372 await this.
Error(
"Address type not supported.");
373 await this.ToError();
377 await this.
Error(
"Unrecognized error code returned: " + REP.ToString());
378 await this.ToError();
384 byte ATYP = Buffer[Offset++];
385 IPAddress Addr =
null;
386 string DomainName =
null;
393 await this.
Error(
"Expected more bytes.");
394 await this.ToError();
398 byte[] A =
new byte[4];
399 Array.Copy(Buffer, Offset, A, 0, 4);
401 Addr =
new IPAddress(A);
405 byte NrBytes = Buffer[Offset++];
406 if (Offset + NrBytes > c)
408 await this.
Error(
"Expected more bytes.");
409 await this.ToError();
413 DomainName = Encoding.ASCII.GetString(Buffer, Offset, NrBytes);
420 await this.
Error(
"Expected more bytes.");
421 await this.ToError();
426 Array.Copy(Buffer, Offset, A, 0, 16);
428 Addr =
new IPAddress(A);
432 await this.ToError();
438 await this.
Error(
"Invalid number of bytes received.");
439 await this.ToError();
443 int Port = Buffer[Offset++];
445 Port |= Buffer[Offset++];
447 await this.
OnResponse.Raise(
this,
new ResponseEventArgs(REP, Addr, DomainName,
Port),
false);
454 public event EventHandlerAsync<ResponseEventArgs>
OnResponse =
null;
461 private async Task ToError()
469 using (MemoryStream Req =
new MemoryStream())
475 if (DestinationAddress.AddressFamily == AddressFamily.InterNetwork)
477 else if (DestinationAddress.AddressFamily == AddressFamily.InterNetworkV6)
480 throw new ArgumentException(
"Invalid address family.", nameof(DestinationAddress));
482 byte[] Addr = DestinationAddress.GetAddressBytes();
483 Req.Write(Addr, 0, Addr.Length);
484 Req.WriteByte((
byte)(
Port >> 8));
485 Req.WriteByte((
byte)
Port);
487 return this.SendPacket(Req.ToArray());
493 using (MemoryStream Req =
new MemoryStream())
500 byte[] Bytes = Encoding.ASCII.GetBytes(DestinationDomainName);
501 int c = Bytes.Length;
503 throw new IOException(
"Domain name too long.");
505 Req.WriteByte((
byte)c);
506 Req.Write(Bytes, 0, Bytes.Length);
507 Req.WriteByte((
byte)(
Port >> 8));
508 Req.WriteByte((
byte)
Port);
510 return this.SendPacket(Req.ToArray());
522 return this.Request(
Command.CONNECT, DestinationAddress,
Port);
533 return this.Request(
Command.CONNECT, DestinationDomainName,
Port);
543 public Task
CONNECT(
string StreamID,
string RequesterJID,
string TargetJID)
545 string s = StreamID + RequesterJID + TargetJID;
547 StringBuilder sb =
new StringBuilder();
549 foreach (
byte b
in Hash)
550 sb.Append(b.ToString(
"x2"));
552 return this.
CONNECT(sb.ToString(), 0);
561 public Task
BIND(IPAddress DestinationAddress,
int Port)
563 return this.Request(
Command.BIND, DestinationAddress,
Port);
572 public Task
BIND(
string DestinationDomainName,
int Port)
574 return this.Request(
Command.BIND, DestinationDomainName,
Port);
585 return this.Request(
Command.UDP_ASSOCIATE, DestinationAddress,
Port);
596 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.
static byte[] ToArray(byte[] Buffer, int Offset, int Count)
Converts a binary subset of a buffer into an array.
Task< bool > ConnectAsync(string Host, int Port)
Connects to a host using TCP.
virtual void Dispose()
Disposes of the object. The underlying TcpClient is either disposed directly, or when asynchronous op...
Simple base class for classes implementing communication protocols.
Task TransmitBinary(byte[] Data)
Called when binary data has been transmitted.
Task Error(string Error)
Called to inform the viewer of an error state.
Task Exception(Exception Exception)
Called to inform the viewer of an exception state.
ISniffer[] Sniffers
Registered sniffers.
Task Information(string Comment)
Called to inform the viewer of something.
bool HasSniffers
If there are sniffers registered on the object.
Task ReceiveBinary(byte[] Data)
Called when binary data has been received.
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.
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.
void CloseWhenDone()
Closes the stream when all bytes have been sent.
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.
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
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 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.