Browse Source

Send first chunk with Socks5 header (#984)

* Send socks5 handshake respond before read the target address
So that the next package will (hopefully) contain the first data chunk which means we could get a 'random' first package size.

* Try read available data before send first packet

* Add random size first packet
But commented out ^u^

* Oops forget to delete some test code
tags/3.4.3
Noisyfox Syrone Wong 8 years ago
parent
commit
2e7518d802
1 changed files with 78 additions and 44 deletions
  1. +78
    -44
      shadowsocks-csharp/Controller/Service/TCPRelay.cs

+ 78
- 44
shadowsocks-csharp/Controller/Service/TCPRelay.cs View File

@@ -322,24 +322,15 @@ namespace Shadowsocks.Controller
} }
else else
{ {
int atyp = _connetionRecvBuffer[3];
switch (atyp)
if (_command == 1)
{
byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 };
_connection.BeginSend(response, 0, response.Length, SocketFlags.None,
new AsyncCallback(ResponseCallback), null);
}
else if (_command == 3)
{ {
case 1: // IPv4 address, 4 bytes
ReadAddress(4 + 2 - 1);
break;
case 3: // domain name, length + str
int len = _connetionRecvBuffer[4];
ReadAddress(len + 2);
break;
case 4: // IPv6 address, 16 bytes
ReadAddress(16 + 2 - 1);
break;
default:
Logging.Debug("Unsupported ATYP=" + atyp);
Close();
break;
ReadAddress(HandleUDPAssociate);
} }
} }
} }
@@ -356,12 +347,50 @@ namespace Shadowsocks.Controller
} }
} }
private void ReadAddress(int bytesRemain)
private void ResponseCallback(IAsyncResult ar)
{
try
{
_connection.EndSend(ar);
ReadAddress(StartConnect);
}
catch (Exception e)
{
Logging.LogUsefulException(e);
Close();
}
}
private void ReadAddress(Action onSuccess)
{
int atyp = _connetionRecvBuffer[3];
switch (atyp)
{
case 1: // IPv4 address, 4 bytes
ReadAddress(4 + 2 - 1, onSuccess);
break;
case 3: // domain name, length + str
int len = _connetionRecvBuffer[4];
ReadAddress(len + 2, onSuccess);
break;
case 4: // IPv6 address, 16 bytes
ReadAddress(16 + 2 - 1, onSuccess);
break;
default:
Logging.Debug("Unsupported ATYP=" + atyp);
Close();
break;
}
}
private void ReadAddress(int bytesRemain, Action onSuccess)
{ {
Array.Copy(_connetionRecvBuffer, 3, _connetionRecvBuffer, 0, 2); Array.Copy(_connetionRecvBuffer, 3, _connetionRecvBuffer, 0, 2);
// Read the remain address bytes // Read the remain address bytes
_connection.BeginReceive(_connetionRecvBuffer, 2, RecvSize - 2, SocketFlags.None, OnAddressFullyRead, bytesRemain);
_connection.BeginReceive(_connetionRecvBuffer, 2, RecvSize - 2, SocketFlags.None, OnAddressFullyRead, new object[] {bytesRemain, onSuccess});
} }
private void OnAddressFullyRead(IAsyncResult ar) private void OnAddressFullyRead(IAsyncResult ar)
@@ -370,7 +399,12 @@ namespace Shadowsocks.Controller
try try
{ {
int bytesRead = _connection.EndReceive(ar); int bytesRead = _connection.EndReceive(ar);
int bytesRemain = (int) ar.AsyncState;
var states = (object[]) ar.AsyncState;
int bytesRemain = (int)states[0];
var onSuccess = (Action) states[1];
if (bytesRead >= bytesRemain) if (bytesRead >= bytesRemain)
{ {
_firstPacketLength = bytesRead + 2; _firstPacketLength = bytesRead + 2;
@@ -405,16 +439,7 @@ namespace Shadowsocks.Controller
_destEndPoint = SocketUtil.GetEndPoint(dst_addr, dst_port); _destEndPoint = SocketUtil.GetEndPoint(dst_addr, dst_port);
if (_command == 1)
{
byte[] response = {5, 0, 0, 1, 0, 0, 0, 0, 0, 0};
_connection.BeginSend(response, 0, response.Length, SocketFlags.None,
new AsyncCallback(ResponseCallback), null);
}
else if (_command == 3)
{
HandleUDPAssociate();
}
onSuccess.Invoke();
} }
else else
{ {
@@ -479,20 +504,6 @@ namespace Shadowsocks.Controller
} }
} }
private void ResponseCallback(IAsyncResult ar)
{
try
{
_connection.EndSend(ar);
StartConnect();
}
catch (Exception e)
{
Logging.LogUsefulException(e);
Close();
}
}
// inner class // inner class
private class ProxyTimer : Timer private class ProxyTimer : Timer
{ {
@@ -716,6 +727,26 @@ namespace Shadowsocks.Controller
} }
} }
// private static readonly Random Rnd = new Random();
private void TryReadAvailableData()
{
int available = Math.Min(_connection.Available, RecvSize - _firstPacketLength);
if (available > 0)
{
// Pick a random chunk size, or is it truly necessary? Random packet size is some sort of 'characteristic' itself.
//lock (Rnd)
//{
// available = Rnd.Next(available + 1);
//}
var size = _connection.Receive(_connetionRecvBuffer, _firstPacketLength, available,
SocketFlags.None);
_firstPacketLength += size;
}
}
private void StartPipe(AsyncSession session) private void StartPipe(AsyncSession session)
{ {
if (_closed) return; if (_closed) return;
@@ -723,6 +754,9 @@ namespace Shadowsocks.Controller
{ {
_startReceivingTime = DateTime.Now; _startReceivingTime = DateTime.Now;
session.Remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeRemoteReceiveCallback), session); session.Remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeRemoteReceiveCallback), session);
TryReadAvailableData();
Logging.Debug($"_firstPacketLength = {_firstPacketLength}");
SendToServer(_firstPacketLength, session); SendToServer(_firstPacketLength, session);
} }
catch (Exception e) catch (Exception e)


Loading…
Cancel
Save