Skip to content

Commit

Permalink
refactor: Socks5 UDP server
Browse files Browse the repository at this point in the history
  • Loading branch information
HMBSbige committed Sep 16, 2021
1 parent 005f0ff commit 0c6d539
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 28 deletions.
24 changes: 15 additions & 9 deletions Socks5/Servers/SimpleSocks5Server.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,6 @@ public class SimpleSocks5Server
Port = IPEndPoint.MinPort,
};

public ServerBound ReplyUdpBound { get; set; } = new()
{
Type = AddressType.IPv4,
Address = IPAddress.Any,
Domain = default,
Port = IPEndPoint.MinPort,
};

private readonly UsernamePassword? _credential;
private readonly CancellationTokenSource _cts;

Expand Down Expand Up @@ -102,11 +94,25 @@ private async ValueTask HandleAsync(Socket socket, CancellationToken token)
}
case Command.UdpAssociate:
{
await service.SendReplyAsync(Socks5Reply.Succeeded, ReplyUdpBound, token);
var remote = (IPEndPoint)socket.RemoteEndPoint!;
var local = new IPEndPoint(((IPEndPoint)TcpListener.LocalEndpoint).Address, IPEndPoint.MinPort);
using var udpServer = new SimpleSocks5UdpServer(local, remote);
udpServer.StartAsync().Forget();

ServerBound replyUdpBound = new()
{
Type = AddressType.IPv4,
Address = local.Address,
Domain = default,
Port = (ushort)((IPEndPoint)udpServer.UdpListener.Client.LocalEndPoint!).Port,
};

await service.SendReplyAsync(Socks5Reply.Succeeded, replyUdpBound, token);

// wait remote close
var result = await pipe.Input.ReadAsync(token);
Report.IfNot(result.IsCompleted);

break;
}
default:
Expand Down
24 changes: 16 additions & 8 deletions Socks5/Servers/SimpleSocks5UdpServer.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Microsoft;
using Microsoft.VisualStudio.Threading;
using Socks5.Enums;
using Socks5.Utils;
using System;
Expand All @@ -14,14 +13,21 @@ namespace Socks5.Servers
/// <summary>
/// Just for test use only
/// </summary>
public class SimpleSocks5UdpServer
public class SimpleSocks5UdpServer : IDisposable
{
public UdpClient UdpListener { get; }
private readonly IPEndPoint _remoteEndpoint;

private readonly CancellationTokenSource _cts;

public SimpleSocks5UdpServer(IPEndPoint bindEndPoint)
private const int MaxUdpSize = 0x10000;

public SimpleSocks5UdpServer(IPEndPoint bindEndPoint, IPEndPoint remoteEndpoint)
{
_remoteEndpoint = remoteEndpoint;
Requires.NotNull(bindEndPoint, nameof(bindEndPoint));
Requires.NotNull(remoteEndpoint, nameof(remoteEndpoint));

UdpListener = new UdpClient(bindEndPoint);

_cts = new CancellationTokenSource();
Expand All @@ -35,13 +41,15 @@ public async ValueTask StartAsync()
{
//TODO .NET6.0
var message = await UdpListener.ReceiveAsync();

HandleAsync(message, _cts.Token).Forget();
if (Equals(message.RemoteEndPoint.Address, _remoteEndpoint.Address))
{
await HandleAsync(message, _cts.Token);
}
}
}
catch (Exception)
{
Stop();
Dispose();
}
}

Expand Down Expand Up @@ -74,7 +82,7 @@ private async ValueTask HandleAsync(UdpReceiveResult result, CancellationToken t
await client.Client.SendAsync(socks5UdpPacket.Data, SocketFlags.None, token);

var headerLength = result.Buffer.Length - socks5UdpPacket.Data.Length;
var receiveBuffer = ArrayPool<byte>.Shared.Rent(0x10000);
var receiveBuffer = ArrayPool<byte>.Shared.Rent(MaxUdpSize);
try
{
var receiveLength = await client.Client.ReceiveAsync(receiveBuffer.AsMemory(headerLength), SocketFlags.None, token);
Expand All @@ -93,7 +101,7 @@ await UdpListener.Client.SendToAsync(
}
}

public void Stop()
public void Dispose()
{
try
{
Expand Down
11 changes: 0 additions & 11 deletions UnitTest/Socks5Test.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.Threading;
using Socks5.Enums;
using Socks5.Models;
using Socks5.Servers;
using Socks5.Utils;
Expand Down Expand Up @@ -50,15 +49,6 @@ public async Task UdpAssociateTestAsync()
Password = @"1919810¥"
};
var server = new SimpleSocks5Server(serverEndpoint, userPass);
var udpServer = new SimpleSocks5UdpServer(serverEndpoint);
udpServer.StartAsync().Forget();
server.ReplyUdpBound = new ServerBound
{
Type = AddressType.IPv4,
Address = ((IPEndPoint)udpServer.UdpListener.Client.LocalEndPoint!).Address,
Domain = default,
Port = (ushort)((IPEndPoint)udpServer.UdpListener.Client.LocalEndPoint!).Port,
};
server.StartAsync().Forget();
try
{
Expand All @@ -74,7 +64,6 @@ public async Task UdpAssociateTestAsync()
finally
{
server.Stop();
udpServer.Stop();
}
}
}
Expand Down

0 comments on commit 0c6d539

Please sign in to comment.