add port forwarder
This commit is contained in:
Executable
+143
@@ -0,0 +1,143 @@
|
||||
using Shadowsocks.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace Shadowsocks.Controller
|
||||
{
|
||||
public class Listener
|
||||
{
|
||||
public interface Service
|
||||
{
|
||||
bool Handle(byte[] firstPacket, int length, Socket socket);
|
||||
}
|
||||
|
||||
Configuration _config;
|
||||
bool _shareOverLAN;
|
||||
Socket _socket;
|
||||
IList<Service> _services;
|
||||
|
||||
public Listener(IList<Service> services)
|
||||
{
|
||||
this._services = services;
|
||||
}
|
||||
|
||||
public void Start(Configuration config)
|
||||
{
|
||||
this._config = config;
|
||||
this._shareOverLAN = config.shareOverLan;
|
||||
try
|
||||
{
|
||||
// Create a TCP/IP socket.
|
||||
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||||
IPEndPoint localEndPoint = null;
|
||||
if (_shareOverLAN)
|
||||
{
|
||||
localEndPoint = new IPEndPoint(IPAddress.Any, _config.localPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
localEndPoint = new IPEndPoint(IPAddress.Loopback, _config.localPort);
|
||||
}
|
||||
|
||||
// Bind the socket to the local endpoint and listen for incoming connections.
|
||||
_socket.Bind(localEndPoint);
|
||||
_socket.Listen(1024);
|
||||
|
||||
|
||||
// Start an asynchronous socket to listen for connections.
|
||||
Console.WriteLine("Shadowsocks started");
|
||||
_socket.BeginAccept(
|
||||
new AsyncCallback(AcceptCallback),
|
||||
_socket);
|
||||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
_socket.Close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (_socket != null)
|
||||
{
|
||||
_socket.Close();
|
||||
_socket = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void AcceptCallback(IAsyncResult ar)
|
||||
{
|
||||
Socket listener = (Socket)ar.AsyncState;
|
||||
try
|
||||
{
|
||||
Socket conn = listener.EndAccept(ar);
|
||||
|
||||
byte[] buf = new byte[4096];
|
||||
object[] state = new object[] {
|
||||
conn,
|
||||
buf
|
||||
};
|
||||
|
||||
conn.BeginReceive(buf, 0, buf.Length, 0,
|
||||
new AsyncCallback(ReceiveCallback), state);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
listener.BeginAccept(
|
||||
new AsyncCallback(AcceptCallback),
|
||||
listener);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ReceiveCallback(IAsyncResult ar)
|
||||
{
|
||||
object[] state = (object[])ar.AsyncState;
|
||||
|
||||
Socket conn = (Socket)state[0];
|
||||
byte[] buf = (byte[])state[1];
|
||||
try
|
||||
{
|
||||
int bytesRead = conn.EndReceive(ar);
|
||||
foreach (Service service in _services)
|
||||
{
|
||||
if (service.Handle(buf, bytesRead, conn))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
// no service found for this
|
||||
// shouldn't happen
|
||||
conn.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
conn.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+265
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -221,6 +221,7 @@ namespace Shadowsocks.Controller
|
||||
List<Listener.Service> services = new List<Listener.Service>();
|
||||
services.Add(local);
|
||||
services.Add(_pacServer);
|
||||
services.Add(new PortForwarder(8123));
|
||||
_listener = new Listener(services);
|
||||
_listener.Start(_config);
|
||||
}
|
||||
|
||||
@@ -129,6 +129,7 @@
|
||||
<Compile Include="Controller\I18N.cs" />
|
||||
<Compile Include="Controller\Listener.cs" />
|
||||
<Compile Include="Controller\Logging.cs" />
|
||||
<Compile Include="Controller\PortForwarder.cs" />
|
||||
<Compile Include="Controller\UpdateChecker.cs" />
|
||||
<Compile Include="Encryption\EncryptorBase.cs" />
|
||||
<Compile Include="Encryption\EncryptorFactory.cs" />
|
||||
|
||||
Reference in New Issue
Block a user