@@ -12,12 +12,19 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
public interface Service | public interface Service | ||||
{ | { | ||||
bool Handle(byte[] firstPacket, int length, Socket socket); | |||||
bool Handle(byte[] firstPacket, int length, Socket socket, object state); | |||||
} | |||||
public class UDPState | |||||
{ | |||||
public byte[] buffer = new byte[4096]; | |||||
public EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); | |||||
} | } | ||||
Configuration _config; | Configuration _config; | ||||
bool _shareOverLAN; | bool _shareOverLAN; | ||||
Socket _socket; | |||||
Socket _tcpSocket; | |||||
Socket _udpSocket; | |||||
IList<Service> _services; | IList<Service> _services; | ||||
public Listener(IList<Service> services) | public Listener(IList<Service> services) | ||||
@@ -51,8 +58,10 @@ namespace Shadowsocks.Controller | |||||
try | try | ||||
{ | { | ||||
// Create a TCP/IP socket. | // Create a TCP/IP socket. | ||||
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); | |||||
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); | |||||
_tcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); | |||||
_udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); | |||||
_tcpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); | |||||
_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); | |||||
IPEndPoint localEndPoint = null; | IPEndPoint localEndPoint = null; | ||||
if (_shareOverLAN) | if (_shareOverLAN) | ||||
{ | { | ||||
@@ -64,29 +73,73 @@ namespace Shadowsocks.Controller | |||||
} | } | ||||
// Bind the socket to the local endpoint and listen for incoming connections. | // Bind the socket to the local endpoint and listen for incoming connections. | ||||
_socket.Bind(localEndPoint); | |||||
_socket.Listen(1024); | |||||
_tcpSocket.Bind(localEndPoint); | |||||
_udpSocket.Bind(localEndPoint); | |||||
_tcpSocket.Listen(1024); | |||||
// Start an asynchronous socket to listen for connections. | // Start an asynchronous socket to listen for connections. | ||||
Console.WriteLine("Shadowsocks started"); | Console.WriteLine("Shadowsocks started"); | ||||
_socket.BeginAccept( | |||||
_tcpSocket.BeginAccept( | |||||
new AsyncCallback(AcceptCallback), | new AsyncCallback(AcceptCallback), | ||||
_socket); | |||||
_tcpSocket); | |||||
UDPState udpState = new UDPState(); | |||||
_udpSocket.BeginReceiveFrom(udpState.buffer, 0, udpState.buffer.Length, 0, ref udpState.remoteEndPoint, new AsyncCallback(RecvFromCallback), udpState); | |||||
} | } | ||||
catch (SocketException) | catch (SocketException) | ||||
{ | { | ||||
_socket.Close(); | |||||
_tcpSocket.Close(); | |||||
throw; | throw; | ||||
} | } | ||||
} | } | ||||
public void Stop() | public void Stop() | ||||
{ | { | ||||
if (_socket != null) | |||||
if (_tcpSocket != null) | |||||
{ | |||||
_tcpSocket.Close(); | |||||
_tcpSocket = null; | |||||
} | |||||
if (_udpSocket != null) | |||||
{ | |||||
_udpSocket.Close(); | |||||
_udpSocket = null; | |||||
} | |||||
} | |||||
public void RecvFromCallback(IAsyncResult ar) | |||||
{ | |||||
UDPState state = (UDPState)ar.AsyncState; | |||||
try | |||||
{ | |||||
int bytesRead = _udpSocket.EndReceiveFrom(ar, ref state.remoteEndPoint); | |||||
foreach (Service service in _services) | |||||
{ | |||||
if (service.Handle(state.buffer, bytesRead, _udpSocket, state)) | |||||
{ | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
catch (ObjectDisposedException) | |||||
{ | { | ||||
_socket.Close(); | |||||
_socket = null; | |||||
} | |||||
catch (Exception e) | |||||
{ | |||||
} | |||||
finally | |||||
{ | |||||
try | |||||
{ | |||||
_udpSocket.BeginReceiveFrom(state.buffer, 0, state.buffer.Length, 0, ref state.remoteEndPoint, new AsyncCallback(RecvFromCallback), state); | |||||
} | |||||
catch (ObjectDisposedException) | |||||
{ | |||||
// do nothing | |||||
} | |||||
catch (Exception e) | |||||
{ | |||||
} | |||||
} | } | ||||
} | } | ||||
@@ -144,14 +197,16 @@ namespace Shadowsocks.Controller | |||||
int bytesRead = conn.EndReceive(ar); | int bytesRead = conn.EndReceive(ar); | ||||
foreach (Service service in _services) | foreach (Service service in _services) | ||||
{ | { | ||||
if (service.Handle(buf, bytesRead, conn)) | |||||
if (service.Handle(buf, bytesRead, conn, null)) | |||||
{ | { | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
// no service found for this | // no service found for this | ||||
// shouldn't happen | |||||
conn.Close(); | |||||
if (conn.ProtocolType == ProtocolType.Tcp) | |||||
{ | |||||
conn.Close(); | |||||
} | |||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
{ | { | ||||
@@ -33,8 +33,12 @@ namespace Shadowsocks.Controller | |||||
this._config = config; | this._config = config; | ||||
} | } | ||||
public bool Handle(byte[] firstPacket, int length, Socket socket) | |||||
public bool Handle(byte[] firstPacket, int length, Socket socket, object state) | |||||
{ | { | ||||
if (socket.ProtocolType != ProtocolType.Tcp) | |||||
{ | |||||
return false; | |||||
} | |||||
try | try | ||||
{ | { | ||||
string request = Encoding.UTF8.GetString(firstPacket, 0, length); | string request = Encoding.UTF8.GetString(firstPacket, 0, length); | ||||
@@ -15,8 +15,12 @@ namespace Shadowsocks.Controller | |||||
this._targetPort = targetPort; | this._targetPort = targetPort; | ||||
} | } | ||||
public bool Handle(byte[] firstPacket, int length, Socket socket) | |||||
public bool Handle(byte[] firstPacket, int length, Socket socket, object state) | |||||
{ | { | ||||
if (socket.ProtocolType != ProtocolType.Tcp) | |||||
{ | |||||
return false; | |||||
} | |||||
new Handler().Start(firstPacket, length, socket, this._targetPort); | new Handler().Start(firstPacket, length, socket, this._targetPort); | ||||
return true; | return true; | ||||
} | } | ||||
@@ -250,9 +250,11 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
polipoRunner.Start(_config); | polipoRunner.Start(_config); | ||||
Local local = new Local(_config); | |||||
TCPRelay tcpRelay = new TCPRelay(_config); | |||||
UDPRelay udpRelay = new UDPRelay(_config); | |||||
List<Listener.Service> services = new List<Listener.Service>(); | List<Listener.Service> services = new List<Listener.Service>(); | ||||
services.Add(local); | |||||
services.Add(tcpRelay); | |||||
services.Add(udpRelay); | |||||
services.Add(_pacServer); | services.Add(_pacServer); | ||||
services.Add(new PortForwarder(polipoRunner.RunningPort)); | services.Add(new PortForwarder(polipoRunner.RunningPort)); | ||||
_listener = new Listener(services); | _listener = new Listener(services); | ||||
@@ -9,16 +9,20 @@ using Shadowsocks.Model; | |||||
namespace Shadowsocks.Controller | namespace Shadowsocks.Controller | ||||
{ | { | ||||
class Local : Listener.Service | |||||
class TCPRelay : Listener.Service | |||||
{ | { | ||||
private Configuration _config; | private Configuration _config; | ||||
public Local(Configuration config) | |||||
public TCPRelay(Configuration config) | |||||
{ | { | ||||
this._config = config; | this._config = config; | ||||
} | } | ||||
public bool Handle(byte[] firstPacket, int length, Socket socket) | |||||
public bool Handle(byte[] firstPacket, int length, Socket socket, object state) | |||||
{ | { | ||||
if (socket.ProtocolType != ProtocolType.Tcp) | |||||
{ | |||||
return false; | |||||
} | |||||
if (length < 2 || firstPacket[0] != 5) | if (length < 2 || firstPacket[0] != 5) | ||||
{ | { | ||||
return false; | return false; | ||||
@@ -238,8 +242,8 @@ namespace Shadowsocks.Controller | |||||
response[3] = 4; | response[3] = 4; | ||||
} | } | ||||
address.CopyTo(response, 4); | address.CopyTo(response, 4); | ||||
response[response.Length - 2] = (byte)(port & 0xFF); | |||||
response[response.Length - 1] = (byte)((port >> 8) & 0xFF); | |||||
response[response.Length - 1] = (byte)(port & 0xFF); | |||||
response[response.Length - 2] = (byte)((port >> 8) & 0xFF); | |||||
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(ReadAll), true); | connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(ReadAll), true); | ||||
} | } | ||||
@@ -0,0 +1,113 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using Shadowsocks.Encryption; | |||||
using Shadowsocks.Model; | |||||
using System.Net.Sockets; | |||||
using System.Net; | |||||
namespace Shadowsocks.Controller | |||||
{ | |||||
class UDPRelay : Listener.Service | |||||
{ | |||||
private Configuration _config; | |||||
public UDPRelay(Configuration config) | |||||
{ | |||||
this._config = config; | |||||
} | |||||
public bool Handle(byte[] firstPacket, int length, Socket socket, object state) | |||||
{ | |||||
if (socket.ProtocolType != ProtocolType.Udp) | |||||
{ | |||||
return false; | |||||
} | |||||
if (length < 4) | |||||
{ | |||||
return false; | |||||
} | |||||
Listener.UDPState udpState = (Listener.UDPState)state; | |||||
// TODO add cache | |||||
UDPHandler handler = new UDPHandler(socket, _config.GetCurrentServer(), (IPEndPoint)udpState.remoteEndPoint); | |||||
handler.Send(firstPacket, length); | |||||
handler.Receive(); | |||||
return true; | |||||
} | |||||
class UDPHandler | |||||
{ | |||||
private Socket _local; | |||||
private Socket _remote; | |||||
private Server _server; | |||||
private byte[] _buffer = new byte[1500]; | |||||
private IPEndPoint _localEndPoint; | |||||
private IPEndPoint _remoteEndPoint; | |||||
public UDPHandler(Socket local, Server server, IPEndPoint localEndPoint) | |||||
{ | |||||
// TODO add timeout | |||||
_local = local; | |||||
_server = server; | |||||
_localEndPoint = localEndPoint; | |||||
// TODO async resolving | |||||
IPAddress ipAddress; | |||||
bool parsed = IPAddress.TryParse(server.server, out ipAddress); | |||||
if (!parsed) | |||||
{ | |||||
IPHostEntry ipHostInfo = Dns.GetHostEntry(server.server); | |||||
ipAddress = ipHostInfo.AddressList[0]; | |||||
} | |||||
_remoteEndPoint = new IPEndPoint(ipAddress, server.server_port); | |||||
_remote = new Socket(_remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); | |||||
} | |||||
public void Send(byte[] data, int length) | |||||
{ | |||||
IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password); | |||||
byte[] dataIn = new byte[length - 3]; | |||||
Array.Copy(data, 3, dataIn, 0, length - 3); | |||||
byte[] dataOut = new byte[length - 3 + 16]; | |||||
int outlen; | |||||
encryptor.Encrypt(dataIn, dataIn.Length, dataOut, out outlen); | |||||
_remote.SendTo(dataOut, _remoteEndPoint); | |||||
} | |||||
public void Receive() | |||||
{ | |||||
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); | |||||
_remote.BeginReceiveFrom(_buffer, 0, _buffer.Length, 0, ref remoteEndPoint, new AsyncCallback(RecvFromCallback), null); | |||||
} | |||||
public void RecvFromCallback(IAsyncResult ar) | |||||
{ | |||||
try | |||||
{ | |||||
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); | |||||
int bytesRead = _remote.EndReceiveFrom(ar, ref remoteEndPoint); | |||||
byte[] dataOut = new byte[bytesRead]; | |||||
int outlen; | |||||
IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password); | |||||
encryptor.Decrypt(_buffer, bytesRead, dataOut, out outlen); | |||||
byte[] sendBuf = new byte[outlen + 3]; | |||||
Array.Copy(dataOut, 0, sendBuf, 3, outlen); | |||||
_local.SendTo(sendBuf, outlen + 3, 0, _localEndPoint); | |||||
Receive(); | |||||
} | |||||
catch (ObjectDisposedException) | |||||
{ | |||||
} | |||||
catch (Exception e) | |||||
{ | |||||
} | |||||
finally | |||||
{ | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -131,6 +131,7 @@ | |||||
<Compile Include="Controller\Listener.cs" /> | <Compile Include="Controller\Listener.cs" /> | ||||
<Compile Include="Controller\Logging.cs" /> | <Compile Include="Controller\Logging.cs" /> | ||||
<Compile Include="Controller\PortForwarder.cs" /> | <Compile Include="Controller\PortForwarder.cs" /> | ||||
<Compile Include="Controller\UDPRelay.cs" /> | |||||
<Compile Include="Controller\UpdateChecker.cs" /> | <Compile Include="Controller\UpdateChecker.cs" /> | ||||
<Compile Include="Encryption\EncryptorBase.cs" /> | <Compile Include="Encryption\EncryptorBase.cs" /> | ||||
<Compile Include="Encryption\EncryptorFactory.cs" /> | <Compile Include="Encryption\EncryptorFactory.cs" /> | ||||
@@ -156,7 +157,7 @@ | |||||
<Compile Include="View\ConfigForm.Designer.cs"> | <Compile Include="View\ConfigForm.Designer.cs"> | ||||
<DependentUpon>ConfigForm.cs</DependentUpon> | <DependentUpon>ConfigForm.cs</DependentUpon> | ||||
</Compile> | </Compile> | ||||
<Compile Include="Controller\Local.cs" /> | |||||
<Compile Include="Controller\TCPRelay.cs" /> | |||||
<Compile Include="Controller\PolipoRunner.cs" /> | <Compile Include="Controller\PolipoRunner.cs" /> | ||||
<Compile Include="Program.cs" /> | <Compile Include="Program.cs" /> | ||||
<Compile Include="Properties\AssemblyInfo.cs" /> | <Compile Include="Properties\AssemblyInfo.cs" /> | ||||