Browse Source

add UDPRelay

tags/2.4
clowwindy 10 years ago
parent
commit
680d465393
7 changed files with 208 additions and 25 deletions
  1. +70
    -15
      shadowsocks-csharp/Controller/Listener.cs
  2. +5
    -1
      shadowsocks-csharp/Controller/PACServer.cs
  3. +5
    -1
      shadowsocks-csharp/Controller/PortForwarder.cs
  4. +4
    -2
      shadowsocks-csharp/Controller/ShadowsocksController.cs
  5. +9
    -5
      shadowsocks-csharp/Controller/TCPRelay.cs
  6. +113
    -0
      shadowsocks-csharp/Controller/UDPRelay.cs
  7. +2
    -1
      shadowsocks-csharp/shadowsocks-csharp.csproj

+ 70
- 15
shadowsocks-csharp/Controller/Listener.cs View File

@@ -12,12 +12,19 @@ namespace Shadowsocks.Controller
{
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;
bool _shareOverLAN;
Socket _socket;
Socket _tcpSocket;
Socket _udpSocket;
IList<Service> _services;
public Listener(IList<Service> services)
@@ -51,8 +58,10 @@ namespace Shadowsocks.Controller
try
{
// 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;
if (_shareOverLAN)
{
@@ -64,29 +73,73 @@ namespace Shadowsocks.Controller
}
// 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.
Console.WriteLine("Shadowsocks started");
_socket.BeginAccept(
_tcpSocket.BeginAccept(
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)
{
_socket.Close();
_tcpSocket.Close();
throw;
}
}
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);
foreach (Service service in _services)
{
if (service.Handle(buf, bytesRead, conn))
if (service.Handle(buf, bytesRead, conn, null))
{
return;
}
}
// no service found for this
// shouldn't happen
conn.Close();
if (conn.ProtocolType == ProtocolType.Tcp)
{
conn.Close();
}
}
catch (Exception e)
{


+ 5
- 1
shadowsocks-csharp/Controller/PACServer.cs View File

@@ -33,8 +33,12 @@ namespace Shadowsocks.Controller
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
{
string request = Encoding.UTF8.GetString(firstPacket, 0, length);


+ 5
- 1
shadowsocks-csharp/Controller/PortForwarder.cs View File

@@ -15,8 +15,12 @@ namespace Shadowsocks.Controller
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);
return true;
}


+ 4
- 2
shadowsocks-csharp/Controller/ShadowsocksController.cs View File

@@ -250,9 +250,11 @@ namespace Shadowsocks.Controller
{
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>();
services.Add(local);
services.Add(tcpRelay);
services.Add(udpRelay);
services.Add(_pacServer);
services.Add(new PortForwarder(polipoRunner.RunningPort));
_listener = new Listener(services);


shadowsocks-csharp/Controller/Local.cs → shadowsocks-csharp/Controller/TCPRelay.cs View File

@@ -9,16 +9,20 @@ using Shadowsocks.Model;
namespace Shadowsocks.Controller
{
class Local : Listener.Service
class TCPRelay : Listener.Service
{
private Configuration _config;
public Local(Configuration config)
public TCPRelay(Configuration 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)
{
return false;
@@ -238,8 +242,8 @@ namespace Shadowsocks.Controller
response[3] = 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);
}

+ 113
- 0
shadowsocks-csharp/Controller/UDPRelay.cs View File

@@ -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
{
}
}
}
}
}

+ 2
- 1
shadowsocks-csharp/shadowsocks-csharp.csproj View File

@@ -131,6 +131,7 @@
<Compile Include="Controller\Listener.cs" />
<Compile Include="Controller\Logging.cs" />
<Compile Include="Controller\PortForwarder.cs" />
<Compile Include="Controller\UDPRelay.cs" />
<Compile Include="Controller\UpdateChecker.cs" />
<Compile Include="Encryption\EncryptorBase.cs" />
<Compile Include="Encryption\EncryptorFactory.cs" />
@@ -156,7 +157,7 @@
<Compile Include="View\ConfigForm.Designer.cs">
<DependentUpon>ConfigForm.cs</DependentUpon>
</Compile>
<Compile Include="Controller\Local.cs" />
<Compile Include="Controller\TCPRelay.cs" />
<Compile Include="Controller\PolipoRunner.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />


Loading…
Cancel
Save