Skip to content

Commit 3dffa0b

Browse files
committed
implement Socks5 pipeline
1 parent 879e8ac commit 3dffa0b

File tree

10 files changed

+238
-25
lines changed

10 files changed

+238
-25
lines changed

Socksy.Core.Test/Dtos/SetMethodDTOTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ public void Send_SendsDtoOverSocket()
77
{
88
// Arrange
99
byte ver = 5;
10-
byte method = 0;
10+
AuthenticationMETHOD method = AuthenticationMETHOD.NO_ACCEPTABLE_METHODS;
1111
var dto = SetMethodDTO.Create(ver, method);
1212
var socket = new SocketMock();
1313

1414
// Act
1515
dto.Send(socket);
1616

1717
// Assert
18-
Assert.Equal(new byte[] { ver, method }, socket.SentData);
18+
Assert.Equal(new byte[] { ver, (byte)method }, socket.SentData);
1919
}
2020
}

Socksy.Core.Test/Dtos/SocketMock.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@ internal class SocketMock : ISocket
1010
public List<byte> SentData => _sentData;
1111
public bool Disposed => _disposed;
1212

13+
public bool Connected => throw new NotImplementedException();
14+
15+
public int Available => throw new NotImplementedException();
16+
17+
public int ReceiveTimeout { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
18+
public int SendTimeout { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
19+
20+
public IPEndPoint RemoteEndPoint => throw new NotImplementedException();
21+
1322
public SocketMock()
1423
{
1524
DataToReceive = new();
@@ -60,4 +69,14 @@ public void Dispose()
6069
{
6170
_disposed = true;
6271
}
72+
73+
public bool Poll(int v, SelectMode selectRead)
74+
{
75+
throw new NotImplementedException();
76+
}
77+
78+
public void Close()
79+
{
80+
throw new NotImplementedException();
81+
}
6382
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace Socksy.Core.Common
8+
{
9+
public enum AuthenticationMETHOD
10+
{
11+
NO_AUTHENTICATION_REQUIRED = 0x00,
12+
GSSAPI = 0x01,
13+
USERNAME_PASSWORD = 0x02,
14+
to_X_7F_IANA_ASSIGNED = 0x03,
15+
to_X_FE_RESERVED_FOR_PRIVATE_METHODS = 0x80,
16+
NO_ACCEPTABLE_METHODS = 0xFF
17+
}
18+
}

Socksy.Core/Common/Request.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
public struct Request
44
{
55
public TcpClient TcpClient { get; internal init; }
6+
internal ISocket CreateSocket() => new SocketWrapper(TcpClient.Client);
67

78
internal static Request CreateFromTcpClient(TcpClient client)
89
=> new Request { TcpClient = client };

Socksy.Core/Dtos/RequestDTO.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,17 @@ private RequestDTO()
2525

2626
public static RequestDTO GetFromSocket(ISocket socket)
2727
{
28-
var data = Helper.RentByteArray(256);
28+
var data = new byte[4];
2929

30-
var received = socket.Receive(data, 0, 4);
30+
var received = socket.Receive(data);
3131
Helper.EnsureReceivedBytes(received, 4);
32-
3332
var ver = data[0];
3433
var cmd = data[1];
3534
var rsv = data[2];
3635
var atype = data[3];
3736

37+
data = Helper.RentByteArray(256);
38+
3839
var dstAddrLen = 0;
3940
switch (atype)
4041
{

Socksy.Core/Dtos/SetMethodDTO.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1-
namespace Socksy.Core.Dtos;
1+
using Socksy.Core.Common;
2+
3+
namespace Socksy.Core.Dtos;
24

35
internal class SetMethodDTO
46
{
57
public byte VER { get; private set; }
6-
public byte METHOD { get; private set; }
8+
public AuthenticationMETHOD METHOD { get; private set; }
79

810
private SetMethodDTO()
911
{
1012
}
1113

12-
public static SetMethodDTO Create(byte ver, byte method)
14+
public static SetMethodDTO Create(byte ver, AuthenticationMETHOD method)
1315
{
1416
return new SetMethodDTO
1517
{
@@ -20,7 +22,7 @@ public static SetMethodDTO Create(byte ver, byte method)
2022

2123
public void Send(ISocket socket)
2224
{
23-
var sent = socket.Send(stackalloc byte[] { VER, METHOD });
25+
var sent = socket.Send(stackalloc byte[] { VER, (byte)METHOD });
2426
Helper.EnsureSentBytes(sent, 2);
2527
}
2628
}

Socksy.Core/Network/ISocket.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,17 @@
22

33
internal interface ISocket : IDisposable
44
{
5+
bool Connected { get; }
6+
int Available { get; }
7+
int ReceiveTimeout { get; set; }
8+
int SendTimeout { get; set; }
9+
public IPEndPoint RemoteEndPoint { get; }
10+
511
public int Send(Span<byte> data);
612
public int Send(byte[] data, int offset, int length);
713
public int Receive(byte[] data);
814
public int Receive(Span<byte> data);
915
public int Receive(byte[] data, int offset, int length);
16+
bool Poll(int v, SelectMode selectRead);
17+
void Close();
1018
}

Socksy.Core/Network/SocketWrapper.cs

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,42 @@
1-
namespace Socksy.Core.Network;
1+
using System.Net.Sockets;
22

3-
internal class SocketWrapper : ISocket, IDisposable
3+
namespace Socksy.Core.Network;
4+
5+
internal struct SocketWrapper : ISocket, IDisposable
46
{
57
private Socket _socket;
68

9+
public bool Connected => _socket.Connected;
10+
11+
public int Available => _socket.Available;
12+
13+
public int ReceiveTimeout
14+
{
15+
get
16+
{
17+
return _socket.ReceiveTimeout;
18+
}
19+
set
20+
{
21+
_socket.ReceiveTimeout = value;
22+
}
23+
}
24+
25+
public IPEndPoint RemoteEndPoint
26+
=> _socket.RemoteEndPoint as IPEndPoint;
27+
28+
public int SendTimeout
29+
{
30+
get
31+
{
32+
return _socket.SendTimeout;
33+
}
34+
set
35+
{
36+
_socket.SendTimeout = value;
37+
}
38+
}
39+
740
public SocketWrapper(Socket socket)
841
{
942
_socket = socket;
@@ -16,7 +49,10 @@ public int Receive(byte[] data)
1649

1750
public int Receive(byte[] data, int offset, int length)
1851
{
19-
return _socket.Receive(data, offset, length, SocketFlags.None);
52+
Span<byte> buff = stackalloc byte[length];
53+
int received = _socket.Receive(buff);
54+
buff.CopyTo(data.AsSpan(offset, length));
55+
return received;
2056
}
2157

2258
public int Receive(Span<byte> data)
@@ -31,11 +67,22 @@ public int Send(Span<byte> data)
3167

3268
public int Send(byte[] data, int offset, int length)
3369
{
34-
return _socket.Send(data, offset, length, SocketFlags.None);
70+
Span<byte> buff = data.AsSpan(offset, length);
71+
return _socket.Send(buff);
3572
}
3673

3774
public void Dispose()
3875
{
3976
_socket.Dispose();
4077
}
78+
79+
public bool Poll(int v, SelectMode selectRead)
80+
{
81+
return _socket.Poll(v, selectRead);
82+
}
83+
84+
public void Close()
85+
{
86+
_socket.Close();
87+
}
4188
}

Socksy.Core/Network/TcpServer.cs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,27 @@ namespace Socksy.Core.Network;
55
internal sealed class TcpServer : IDisposable
66
{
77
private readonly TcpListener _listener;
8-
private readonly Func<TcpClient, Task> _onConnectionEstablished;
8+
private readonly Func<int, Request, Task> _onConnectionEstablished;
99
private CancellationTokenSource? _cancellationTokenSource;
1010
private CancellationToken _cancellationToken;
11+
private IPEndPoint _localEndPoint;
1112
private int _activeRequests;
1213
private bool _isListening;
14+
private int _reqNum = 0;
1315

14-
public TcpServer(IPEndPoint localEndPoint, Func<TcpClient, Task> onConnectionEstablished)
16+
public TcpServer(IPEndPoint localEndPoint, Func<int, Request, Task> onConnectionEstablished)
1517
{
18+
_localEndPoint = localEndPoint;
1619
_listener = new TcpListener(localEndPoint);
1720
_onConnectionEstablished = onConnectionEstablished;
1821
_isListening = false;
1922
}
2023

2124
public bool IsListening => _isListening;
2225

26+
public int ListeningPort => _localEndPoint.Port;
27+
public IPAddress ListeningAddress => _localEndPoint.Address;
28+
2329
public void Start()
2430
{
2531
if (_isListening)
@@ -34,7 +40,7 @@ public void Start()
3440

3541
public void Stop()
3642
{
37-
if(!_isListening)
43+
if (!_isListening)
3844
return;
3945

4046
_listener.Stop();
@@ -45,20 +51,22 @@ public void Stop()
4551

4652
private async Task MainLoop()
4753
{
48-
while(!_cancellationToken.IsCancellationRequested)
54+
while (!_cancellationToken.IsCancellationRequested)
4955
{
5056
var tcpClient = await _listener.AcceptTcpClientAsync(_cancellationToken);
5157
Interlocked.Add(ref _activeRequests, 1);
58+
Interlocked.Add(ref _reqNum, 1);
5259

53-
_ = _onConnectionEstablished(tcpClient).ContinueWith((t) => {
60+
_ = _onConnectionEstablished(_reqNum, Request.CreateFromTcpClient(tcpClient)).ContinueWith((t) =>
61+
{
5462
Interlocked.Add(ref _activeRequests, -1);
5563
});
5664
}
5765
}
5866

5967
private async Task WaitForAllActiveConnectionRequestsToComplete()
6068
{
61-
while(_activeRequests > 0)
69+
while (_activeRequests > 0)
6270
{
6371
await Task.Delay(10);
6472
}

0 commit comments

Comments
 (0)