|
|
@@ -0,0 +1,265 @@ |
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Net;
|
|
|
|
using System.Net.Sockets;
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
namespace Shadowsocks.Controller
|
|
|
|
{
|
|
|
|
class PortForwarder : Listener.Service
|
|
|
|
{
|
|
|
|
int _targetPort;
|
|
|
|
|
|
|
|
public PortForwarder(int targetPort)
|
|
|
|
{
|
|
|
|
this._targetPort = targetPort;
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool Handle(byte[] firstPacket, int length, Socket socket)
|
|
|
|
{
|
|
|
|
new Handler().Start(firstPacket, length, socket, this._targetPort);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
class Handler
|
|
|
|
{
|
|
|
|
private byte[] _firstPacket;
|
|
|
|
private int _firstPacketLength;
|
|
|
|
private Socket _local;
|
|
|
|
private Socket _remote;
|
|
|
|
private bool _closed = false;
|
|
|
|
private bool _localShutdown = false;
|
|
|
|
private bool _remoteShutdown = false;
|
|
|
|
public const int RecvSize = 16384;
|
|
|
|
// remote receive buffer
|
|
|
|
private byte[] remoteRecvBuffer = new byte[RecvSize];
|
|
|
|
// connection receive buffer
|
|
|
|
private byte[] connetionRecvBuffer = new byte[RecvSize];
|
|
|
|
|
|
|
|
public void Start(byte[] firstPacket, int length, Socket socket, int targetPort)
|
|
|
|
{
|
|
|
|
this._firstPacket = firstPacket;
|
|
|
|
this._firstPacketLength = length;
|
|
|
|
this._local = socket;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// TODO async resolving
|
|
|
|
IPAddress ipAddress;
|
|
|
|
bool parsed = IPAddress.TryParse("127.0.0.1", out ipAddress);
|
|
|
|
IPEndPoint remoteEP = new IPEndPoint(ipAddress, targetPort);
|
|
|
|
|
|
|
|
|
|
|
|
_remote = new Socket(ipAddress.AddressFamily,
|
|
|
|
SocketType.Stream, ProtocolType.Tcp);
|
|
|
|
_remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
|
|
|
|
|
|
|
|
// Connect to the remote endpoint.
|
|
|
|
_remote.BeginConnect(remoteEP,
|
|
|
|
new AsyncCallback(ConnectCallback), null);
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
Logging.LogUsefulException(e);
|
|
|
|
this.Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void ConnectCallback(IAsyncResult ar)
|
|
|
|
{
|
|
|
|
if (_closed)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
try
|
|
|
|
{
|
|
|
|
_remote.EndConnect(ar);
|
|
|
|
HandshakeReceive();
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
Logging.LogUsefulException(e);
|
|
|
|
this.Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void HandshakeReceive()
|
|
|
|
{
|
|
|
|
if (_closed)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
try
|
|
|
|
{
|
|
|
|
_remote.BeginSend(_firstPacket, 0, _firstPacketLength, 0, new AsyncCallback(StartPipe), null);
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
Logging.LogUsefulException(e);
|
|
|
|
this.Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void StartPipe(IAsyncResult ar)
|
|
|
|
{
|
|
|
|
if (_closed)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
try
|
|
|
|
{
|
|
|
|
_remote.EndSend(ar);
|
|
|
|
_remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0,
|
|
|
|
new AsyncCallback(PipeRemoteReceiveCallback), null);
|
|
|
|
_local.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0,
|
|
|
|
new AsyncCallback(PipeConnectionReceiveCallback), null);
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
Logging.LogUsefulException(e);
|
|
|
|
this.Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void PipeRemoteReceiveCallback(IAsyncResult ar)
|
|
|
|
{
|
|
|
|
if (_closed)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
try
|
|
|
|
{
|
|
|
|
int bytesRead = _remote.EndReceive(ar);
|
|
|
|
|
|
|
|
if (bytesRead > 0)
|
|
|
|
{
|
|
|
|
int bytesToSend;
|
|
|
|
_local.BeginSend(remoteRecvBuffer, 0, bytesRead, 0, new AsyncCallback(PipeConnectionSendCallback), null);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//Console.WriteLine("bytesRead: " + bytesRead.ToString());
|
|
|
|
_local.Shutdown(SocketShutdown.Send);
|
|
|
|
_localShutdown = true;
|
|
|
|
CheckClose();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
Logging.LogUsefulException(e);
|
|
|
|
this.Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void PipeConnectionReceiveCallback(IAsyncResult ar)
|
|
|
|
{
|
|
|
|
if (_closed)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
try
|
|
|
|
{
|
|
|
|
int bytesRead = _local.EndReceive(ar);
|
|
|
|
|
|
|
|
if (bytesRead > 0)
|
|
|
|
{
|
|
|
|
_remote.BeginSend(connetionRecvBuffer, 0, bytesRead, 0, new AsyncCallback(PipeRemoteSendCallback), null);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_remote.Shutdown(SocketShutdown.Send);
|
|
|
|
_remoteShutdown = true;
|
|
|
|
CheckClose();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
Logging.LogUsefulException(e);
|
|
|
|
this.Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void PipeRemoteSendCallback(IAsyncResult ar)
|
|
|
|
{
|
|
|
|
if (_closed)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
try
|
|
|
|
{
|
|
|
|
_remote.EndSend(ar);
|
|
|
|
_local.BeginReceive(this.connetionRecvBuffer, 0, RecvSize, 0,
|
|
|
|
new AsyncCallback(PipeConnectionReceiveCallback), null);
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
Logging.LogUsefulException(e);
|
|
|
|
this.Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void PipeConnectionSendCallback(IAsyncResult ar)
|
|
|
|
{
|
|
|
|
if (_closed)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
try
|
|
|
|
{
|
|
|
|
_local.EndSend(ar);
|
|
|
|
_remote.BeginReceive(this.remoteRecvBuffer, 0, RecvSize, 0,
|
|
|
|
new AsyncCallback(PipeRemoteReceiveCallback), null);
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
Logging.LogUsefulException(e);
|
|
|
|
this.Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void CheckClose()
|
|
|
|
{
|
|
|
|
if (_localShutdown && _remoteShutdown)
|
|
|
|
{
|
|
|
|
this.Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Close()
|
|
|
|
{
|
|
|
|
lock (this)
|
|
|
|
{
|
|
|
|
if (_closed)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_closed = true;
|
|
|
|
}
|
|
|
|
if (_local != null)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
_local.Shutdown(SocketShutdown.Both);
|
|
|
|
_local.Close();
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
Logging.LogUsefulException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (_remote != null)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
_remote.Shutdown(SocketShutdown.Both);
|
|
|
|
_remote.Close();
|
|
|
|
}
|
|
|
|
catch (SocketException e)
|
|
|
|
{
|
|
|
|
Logging.LogUsefulException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|