From 50e9d2a93d5f6d776c648393f878ae132b5c484f Mon Sep 17 00:00:00 2001 From: breakwa11 Date: Mon, 24 Aug 2015 14:20:28 +0800 Subject: [PATCH] 3.4.0 --- shadowsocks-csharp.sln | 3 + shadowsocks-csharp/Controller/GfwListUpdater.cs | 2 +- shadowsocks-csharp/Controller/Local.cs | 404 +++++- shadowsocks-csharp/Controller/TDP.cs | 1573 +++++++++++++++++++++++ shadowsocks-csharp/Controller/UpdateChecker.cs | 2 +- shadowsocks-csharp/Data/cn.txt | 6 +- shadowsocks-csharp/Util/CRC.cs | 44 + shadowsocks-csharp/View/ConfigForm.Designer.cs | 81 +- shadowsocks-csharp/View/ConfigForm.cs | 4 + shadowsocks-csharp/View/MenuViewController.cs | 6 +- shadowsocks-csharp/shadowsocks-csharp.csproj | 2 + shadowsocks-csharp/shadowsocks-csharp4.0.csproj | 2 + 12 files changed, 2048 insertions(+), 81 deletions(-) create mode 100644 shadowsocks-csharp/Controller/TDP.cs create mode 100644 shadowsocks-csharp/Util/CRC.cs diff --git a/shadowsocks-csharp.sln b/shadowsocks-csharp.sln index 77ae7686..07259abc 100755 --- a/shadowsocks-csharp.sln +++ b/shadowsocks-csharp.sln @@ -4,6 +4,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "shadowsocks-csharp", "shadowsocks-csharp\shadowsocks-csharp.csproj", "{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}" + ProjectSection(ProjectDependencies) = postProject + {0F2A0C8A-6C06-485B-AA13-AEEC19CA9637} = {0F2A0C8A-6C06-485B-AA13-AEEC19CA9637} + EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "test", "test\test.csproj", "{45913187-0685-4903-B250-DCEF0479CD86}" ProjectSection(ProjectDependencies) = postProject diff --git a/shadowsocks-csharp/Controller/GfwListUpdater.cs b/shadowsocks-csharp/Controller/GfwListUpdater.cs index d46834d8..61f5f2a2 100644 --- a/shadowsocks-csharp/Controller/GfwListUpdater.cs +++ b/shadowsocks-csharp/Controller/GfwListUpdater.cs @@ -12,7 +12,7 @@ namespace Shadowsocks.Controller { public class GFWListUpdater { - private const string GFWLIST_URL = "https://autoproxy-gfwlist.googlecode.com/svn/trunk/gfwlist.txt"; + private const string GFWLIST_URL = "https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt"; private static string PAC_FILE = PACServer.PAC_FILE; diff --git a/shadowsocks-csharp/Controller/Local.cs b/shadowsocks-csharp/Controller/Local.cs index f697517d..067ce99b 100644 --- a/shadowsocks-csharp/Controller/Local.cs +++ b/shadowsocks-csharp/Controller/Local.cs @@ -7,6 +7,130 @@ using Shadowsocks.Encryption; using Shadowsocks.Model; using System.Timers; +/* +shadowsocks TCP/UDP rand data packet (Server + Client) ++------+------+----------+----------------+ +| Ver. | size | Rnd DATA | TCP/UDP packet | ++------+------+----------+----------------+ +| 1 | 1 | Variable | Variable | ++------+------+----------+----------------+ +Ver: always 0x80 +size: Rnd DATA size + +shadowsocks TCP/UDP rand data packet 2 (Server + Client) ++------+----------------+ +| Ver. | TCP/UDP packet | ++------+----------------+ +| 1 | Variable | ++------+----------------+ +Ver: always 0x81 + +shadowsocks TCP/UDP rand data packet (Server + Client) ++------+------+----------+----------------+ +| Ver. | size | Rnd DATA | TCP/UDP packet | ++------+------+----------+----------------+ +| 1 | 2 | Variable | Variable | ++------+------+----------+----------------+ +Ver: always 0x82 + */ + +/* + +shadowsocks UDP Request Connect (Client) ++------+-----+-----------+----------+----------+-------+ +| Ver. | Cmd | requestid | local id | Rnd DATA | CRC32 | ++------+-----+-----------+----------+----------+-------+ +| 1 | 1 | 2 | 4 | Variable | 4 | ++------+-----+-----------+----------+----------+-------+ +Ver: always 8 +Cmd: 0 +Rnd DATA: size from 2 to 32, fill with 0 is ok + +shadowsocks UDP Request Connect Recv (Server) -------------------------- TODO port/ip redir ++------+-----+-----------+-----+----------+-----------+ +| Ver. | Cmd | requestid |state| Rnd DATA | requestid | ++------+-----+-----------+-----+----------+-----------+ +| 1 | 1 | 2 | 1 | Variable | 2 | ++------+-----+-----------+-----+----------+-----------+ +Cmd: 1 +Rnd DATA: size from 0 to 32, the same as below +state: + * 0 Reject + * 1 Connected + * 2 Connected Remote + * 3 Error + * 4 Disconnected + * 5 Redirect +Note: client should save the requestid for next communication if state is 1 + +shadowsocks UDP Request Connect Remote (Client) ++------+-----+-----------+----------+------+----------+----------+----------+-------+ +| Ver. | Cmd | requestid | local id | ATYP | DST.ADDR | DST.PORT | Rnd DATA | CRC32 | ++------+-----+-----------+----------+------+----------+----------+----------+-------+ +| 1 | 1 | 2 | 4 | 1 | Variable | 2 | Variable | 4 | ++------+-----+-----------+----------+------+----------+----------+----------+-------+ +Cmd: 2 +ATYP: 1: IPv4; 4: IPv6; 3: a host name need resolved + +shadowsocks UDP Request Connect Remote Recv (Server) ++------+-----+-----------+-----+----------+-----------+ +| Ver. | Cmd | requestid |state| Rnd DATA | requestid | ++------+-----+-----------+-----+----------+-----------+ +| 1 | 1 | 2 | 1 | Variable | 2 | ++------+-----+-----------+-----+----------+-----------+ +Cmd: 3 + +================== start proxy + +Post Data (Server + Client) ------------------------ TODO compress support ++------+-----+-----------+------------------+-------------------+-----------+----------+---------------+-------------------+ +| Ver. | Cmd | requestid | local id(Client) | recv next pack id | pack id | DATA | CRC32(Client) | requestid(Server) | ++------+-----+-----------+------------------+-------------------+-----------+----------+---------------+-------------------+ +| 1 | 1 | 2 | 4 | 4 | 4 | Payload | 4 | 2 | ++------+-----+-----------+------------------+-------------------+-----------+----------+---------------+-------------------+ +Cmd: 4 +local id: Server not send the id back +Note: + * We should split a big tcp packet (> 1400 bytes) into random size. + * Otherwise, we should add 0x80 rand header, size is more then 0 and less then 8 for performance reason. + +Syn status (Client + Server) ++------+-----+-----------+------------------+-------------------+-------------+----------+---------------+-------------------+ +| Ver. | Cmd | requestid | local id(Client) | recv next pack id | max send id | ids | CRC32(Client) | requestid(Server) | ++------+-----+-----------+------------------+-------------------+-------------+----------+---------------+-------------------+ +| 1 | 1 | 2 | 4 | 4 | 4 | Variable | 4 | 2 | ++------+-----+-----------+------------------+-------------------+-------------+----------+---------------+-------------------+ +Cmd: 5 +ids: An array of id which offset of "recv next pack id" include your missing packets, 2 bytes each. Should add an extra byte randomly + + +Post Data (Server + Client) ++------+-----+-----------+------------------+-------------------+-----------+----------+---------------+-------------------+ +| Ver. | Cmd | requestid | local id(Client) | recv next pack id | pack id | DATA | CRC32(Client) | requestid(Server) | ++------+-----+-----------+------------------+-------------------+-----------+----------+---------------+-------------------+ +| 1 | 1 | 2 | 4 | 8 | 8 | Payload | 4 | 2 | ++------+-----+-----------+------------------+-------------------+-----------+----------+---------------+-------------------+ +Cmd: 6 + +Syn status (Client + Server) ++------+-----+-----------+------------------+-------------------+-------------+----------+---------------+-------------------+ +| Ver. | Cmd | requestid | local id(Client) | recv next pack id | max send id | ids | CRC32(Client) | requestid(Server) | ++------+-----+-----------+------------------+-------------------+-------------+----------+---------------+-------------------+ +| 1 | 1 | 2 | 4 | 8 | 8 | Variable | 4 | 2 | ++------+-----+-----------+------------------+-------------------+-------------+----------+---------------+-------------------+ +Cmd: 7 + + +Disconnect (Server + Client) ++------+-----+-----------+------------------+----------+---------------+-------------------+ +| Ver. | Cmd | requestid | local id(Client) | Rnd DATA | CRC32(Client) | requestid(Server) | ++------+-----+-----------+------------------+----------+---------------+-------------------+ +| 1 | 1 | 2 | 4 | Variable | 4 | 2 | ++------+-----+-----------+------------------+----------+---------------+-------------------+ +Cmd: 8 + + */ + namespace Shadowsocks.Controller { @@ -29,7 +153,7 @@ namespace Shadowsocks.Controller Handler handler = new Handler(); //handler.config = _config; - handler.getCurrentServer = delegate(bool usingRandom, bool forceRandom) { return _config.GetCurrentServer(usingRandom, forceRandom); }; + handler.getCurrentServer = delegate (bool usingRandom, bool forceRandom) { return _config.GetCurrentServer(usingRandom, forceRandom); }; handler.connection = socket; handler.reconnectTimesRemain = _config.reconnectTimes; @@ -42,6 +166,7 @@ namespace Shadowsocks.Controller handler.socks5RemotePassword = _config.socks5Pass; } handler.TTL = _config.TTL; + handler.autoSwitchOff = _config.autoban; handler.Start(firstPacket, length); return true; @@ -116,6 +241,8 @@ namespace Shadowsocks.Controller public int socks5RemotePort = 0; public string socks5RemoteUsername; public string socks5RemotePassword; + // auto ban + public bool autoSwitchOff = true; // Reconnect public int reconnectTimesRemain = 0; protected int reconnectTimes = 0; @@ -126,6 +253,8 @@ namespace Shadowsocks.Controller protected Socket remote; protected Socket remoteUDP; protected IPEndPoint remoteUDPEndPoint; + // TDP + protected TDPHandler remoteTDP; // Connect command protected byte command; // Init data @@ -161,10 +290,10 @@ namespace Shadowsocks.Controller protected bool connectionUDPIdle; protected bool remoteTCPIdle; protected bool remoteUDPIdle; + protected bool remoteTDPIdle; protected SpeedTester speedTester = new SpeedTester(); protected int lastErrCode; - protected bool autoSwitchOff = true; protected Random random = new Random(); protected Timer timer; protected object timerLock = new object(); @@ -384,6 +513,19 @@ namespace Shadowsocks.Controller CloseSocket(ref remote); CloseSocket(ref remoteUDP); + if (remoteTDP != null) + { + try + { + remoteTDP.Shutdown(); + //remoteTDP.Close(); + } + catch (Exception e) + { + Logging.LogUsefulException(e); + } + remoteTDP = null; + } connectionShutdown = false; remoteShutdown = false; @@ -426,6 +568,10 @@ namespace Shadowsocks.Controller IPEndPoint remoteEP = new IPEndPoint(ipAddress, serverPort); remoteUDPEndPoint = remoteEP; + if (server.tcp_over_udp && connectionUDP == null) + { + remoteTDP = new TDPHandler(); + } if (socks5RemotePort != 0 || connectionUDP == null && !server.tcp_over_udp || connectionUDP != null && server.udp_over_tcp) @@ -449,6 +595,13 @@ namespace Shadowsocks.Controller } } + if (remoteTDP != null && server.tcp_over_udp && socks5RemotePort == 0) + { + speedTester.BeginConnect(); + remoteTDP.BeginConnect(server.method, server.password, remoteEP, "", 0, + new AsyncCallback(ConnectCallback), null); + } + else { // Connect to the remote endpoint. if (socks5RemotePort == 0 && connectionUDP != null && !server.udp_over_tcp) @@ -568,6 +721,19 @@ namespace Shadowsocks.Controller CloseSocket(ref connectionUDP); CloseSocket(ref remote); CloseSocket(ref remoteUDP); + if (remoteTDP != null) + { + try + { + remoteTDP.Shutdown(); + //remoteTDP.Close(); + } + catch (Exception e) + { + Logging.LogUsefulException(e); + } + remoteTDP = null; + } lock (encryptionLock) { @@ -1036,7 +1202,6 @@ namespace Shadowsocks.Controller } else { - RspSocks5TCPHeader(); if (socks5RemotePort > 0) { if (server.tcp_over_udp) @@ -1044,6 +1209,7 @@ namespace Shadowsocks.Controller command = 3; } } + RspSocks5TCPHeader(); } } else @@ -1166,13 +1332,24 @@ namespace Shadowsocks.Controller try { // Complete the connection. + if (remoteTDP == null || socks5RemotePort != 0) { remote.EndConnect(ar); } + else + { + remoteTDP.EndConnect(ar); + } if (socks5RemotePort > 0) { if (ConnectProxyServer(server.server, server.server_port, remote, (int)SocketError.ConnectionReset)) { + if (server.tcp_over_udp && remoteTDP != null) + { + remoteTDP.BeginConnect(server.method, server.password, remoteUDPEndPoint, server.server, server.server_port, + new AsyncCallback(ConnectTDPCallback), null); + return; + } } else { @@ -1205,6 +1382,38 @@ namespace Shadowsocks.Controller } } + private void ConnectTDPCallback(IAsyncResult ar) + { + if (closed) + { + return; + } + try + { + remoteTDP.EndConnect(ar); + + speedTester.EndConnect(); + server.ServerSpeedLog().AddConnectTime((int)(speedTester.timeConnectEnd - speedTester.timeConnectBegin).TotalMilliseconds); + + ConnectState _state = this.State; + if (_state == ConnectState.CONNECTING) + { + this.State = ConnectState.CONNECTED; + StartPipe(); + } + else if (_state == ConnectState.CONNECTED) + { + //ERROR + } + } + catch (Exception e) + { + LogSocketException(e); + if (!Logging.LogSocketException(server.remarks, server.server, e)) + Logging.LogUsefulException(e); + this.Close(); + } + } // do/end xxx tcp/udp Recv private void doConnectionTCPRecv() { @@ -1296,6 +1505,29 @@ namespace Shadowsocks.Controller return 0; } + private void doRemoteTDPRecv() + { + if (remoteTDP != null && remoteTDPIdle) + { + //IPEndPoint sender = new IPEndPoint(remoteUDP.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0); + //EndPoint tempEP = (EndPoint)sender; + remoteTDPIdle = false; + remoteTDP.BeginReceiveFrom(remoteRecvBuffer, RecvSize, + new AsyncCallback(PipeRemoteTDPReceiveCallback), null); + } + } + + private int endRemoteTDPRecv(IAsyncResult ar, ref EndPoint endPoint) + { + if (remoteTDP != null) + { + int bytesRead = remoteTDP.EndReceiveFrom(ar, ref endPoint); + remoteTDPIdle = true; + return bytesRead; + } + return 0; + } + // 2 sides connection start private void StartPipe() { @@ -1310,6 +1542,7 @@ namespace Shadowsocks.Controller connectionUDPIdle = true; remoteTCPIdle = true; remoteUDPIdle = true; + remoteTDPIdle = true; connectionPacketNumber = 0; remoteUDPRecvBufferLength = 0; @@ -1321,6 +1554,18 @@ namespace Shadowsocks.Controller { if (connectionUDP == null) // TCP { + if (server.tcp_over_udp && + remoteTDP != null) + { + doRemoteTDPRecv(); + //RemoteTDPSend(remoteHeaderSendBuffer, remoteHeaderSendBuffer.Length); + //remoteHeaderSendBuffer = null; + } + else + { + //RemoteSend(remoteHeaderSendBuffer, remoteHeaderSendBuffer.Length); + //remoteHeaderSendBuffer = null; + } } else // UDP { @@ -1472,6 +1717,73 @@ namespace Shadowsocks.Controller } } + // end ReceiveCallback + private void PipeRemoteTDPReceiveCallback(IAsyncResult ar) + { + if (closed) + { + return; + } + try + { + IPEndPoint sender = new IPEndPoint(remoteTDP.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0); + EndPoint tempEP = (EndPoint)sender; + + int bytesRead = endRemoteTDPRecv(ar, ref tempEP); + ResetTimeout(TTL); + + if (bytesRead > 0) + { + int bytesToSend = bytesRead; + //byte[] buffer = new byte[bytesToSend]; + //Array.Copy(remoteRecvBuffer, buffer, bytesToSend); + //if (connectionUDP == null) + // Logging.LogBin(LogLevel.Debug, "remote recv", buffer, bytesToSend); + //else + // Logging.LogBin(LogLevel.Debug, "udp remote recv", buffer, bytesToSend); + lock (decryptionLock) + { + if (closed) + { + return; + } + Array.Copy(remoteRecvBuffer, remoteSendBuffer, bytesToSend); + } + server.ServerSpeedLog().AddDownloadBytes(bytesToSend); + server.ServerSpeedLog().HasData(); + speedTester.AddDownloadSize(bytesToSend); + + ConnectionSend(remoteSendBuffer, bytesToSend); + } + else + { + //Console.WriteLine("bytesRead: " + bytesRead.ToString()); + connection.Shutdown(SocketShutdown.Send); + connectionShutdown = true; + if (lastErrCode == 0) + { + lastErrCode = 8; + if (speedTester.sizeDownload == 0) + { + server.ServerSpeedLog().AddNoDataTimes(); + if (server.ServerSpeedLog().ErrorContinurousTimes >= AutoSwitchOffErrorTimes && autoSwitchOff) + { + server.setEnable(false); + } + } + } + CheckClose(); + } + } + catch (Exception e) + { + LogSocketException(e); + if (!Logging.LogSocketException(server.remarks, server.server, e)) + Logging.LogUsefulException(e); + this.Close(); + } + } + private bool RemoveRemoteUDPRecvBufferHeader(ref int bytesRead) { if (socks5RemotePort > 0) @@ -1523,48 +1835,6 @@ namespace Shadowsocks.Controller bytesToSend += 3; } - public static byte[] ParseUDPHeader(byte[] buffer, ref int len) - { - if (buffer.Length == 0) - return buffer; - if (buffer[0] == 0x81) - { - len = len - 1; - byte[] ret = new byte[len]; - Array.Copy(buffer, 1, ret, 0, len); - return ret; - } - if (buffer[0] == 0x80 && len >= 2) - { - int ofbs_len = buffer[1]; - if (ofbs_len + 2 < len) - { - len = len - ofbs_len - 2; - byte[] ret = new byte[len]; - Array.Copy(buffer, ofbs_len + 2, ret, 0, len); - return ret; - } - } - if (buffer[0] == 0x82 && len >= 3) - { - int ofbs_len = (buffer[1] << 8) + buffer[2]; - if (ofbs_len + 3 < len) - { - len = len - ofbs_len - 3; - byte[] ret = new byte[len]; - Array.Copy(buffer, ofbs_len + 3, ret, 0, len); - return ret; - } - } - if (len < buffer.Length) - { - byte[] ret = new byte[len]; - Array.Copy(buffer, ret, len); - return ret; - } - return buffer; - } - // end ReceiveCallback private void PipeRemoteUDPReceiveCallback(IAsyncResult ar) { @@ -1596,7 +1866,7 @@ namespace Shadowsocks.Controller } encryptorUDP.Reset(); encryptorUDP.Decrypt(remoteRecvBuffer, bytesRead, decryptBuffer, out bytesToSend); - decryptBuffer = ParseUDPHeader(decryptBuffer, ref bytesToSend); + decryptBuffer = TDPHandler.ParseUDPHeader(decryptBuffer, ref bytesToSend); AddRemoteUDPRecvBufferHeader(decryptBuffer, ref bytesToSend); } if (connectionUDP == null) @@ -1692,6 +1962,13 @@ namespace Shadowsocks.Controller remote.BeginSend(connetionSendBuffer, 0, bytesToSend, 0, new AsyncCallback(PipeRemoteSendCallback), null); } + private void RemoteTDPSend(byte[] bytes, int length) + { + server.ServerSpeedLog().AddUploadBytes(length); + speedTester.AddUploadSize(length); + remoteTDP.BeginSendTo(bytes, length, new AsyncCallback(PipeRemoteTDPSendCallback), null); + } + private void RemoteSendto(byte[] bytes, int length, bool obfs, int obfs_max = 40) { int bytesToSend; @@ -1827,6 +2104,12 @@ namespace Shadowsocks.Controller { Logging.LogBin(LogLevel.Debug, "remote send", connetionRecvBuffer, bytesRead); } + if (server.tcp_over_udp && + remoteTDP != null) + { + RemoteTDPSend(connetionRecvBuffer, bytesRead); + } + else { { RemoteSend(connetionRecvBuffer, bytesRead); @@ -1835,6 +2118,12 @@ namespace Shadowsocks.Controller } else { + if (server.tcp_over_udp && + remoteTDP != null) + { + remoteTDP.Shutdown(); + } + else { remote.Shutdown(SocketShutdown.Send); } @@ -1952,6 +2241,27 @@ namespace Shadowsocks.Controller } } + private void PipeRemoteTDPSendCallback(IAsyncResult ar) + { + if (closed) + { + return; + } + try + { + //remoteTDP.EndSendTo(ar); + doConnectionTCPRecv(); + doConnectionUDPRecv(); + } + catch (Exception e) + { + LogSocketException(e); + if (!Logging.LogSocketException(server.remarks, server.server, e)) + Logging.LogUsefulException(e); + this.Close(); + } + } + private void PipeConnectionSendCallback(IAsyncResult ar) { if (closed) @@ -1963,6 +2273,7 @@ namespace Shadowsocks.Controller connection.EndSend(ar); doRemoteTCPRecv(); doRemoteUDPRecv(); + doRemoteTDPRecv(); } catch (Exception e) { @@ -1984,6 +2295,7 @@ namespace Shadowsocks.Controller connectionUDP.EndSendTo(ar); doRemoteTCPRecv(); doRemoteUDPRecv(); + doRemoteTDPRecv(); } catch (Exception e) { diff --git a/shadowsocks-csharp/Controller/TDP.cs b/shadowsocks-csharp/Controller/TDP.cs new file mode 100644 index 00000000..caf68309 --- /dev/null +++ b/shadowsocks-csharp/Controller/TDP.cs @@ -0,0 +1,1573 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Net.Sockets; +using Shadowsocks.Encryption; +using System.Timers; + +namespace Shadowsocks.Controller +{ + class PacketInfo + { + public DateTime time; + public byte[] data; + public PacketInfo(byte[] data) + { + this.data = data; + this.time = DateTime.Now; + } + } + class SendQueue + { + private Dictionary id_to_Buffer = new Dictionary(); + private ulong BeginID = 0; + private ulong EndID = 1; + public const int MTU_MIN = 1000; + public const int MTU_MAX = 1400; + public double Interval = 0.5; + private Random random = new Random(); + + public ulong sendBeginID + { + get + { + lock (this) + { + return BeginID; + } + } + } + public ulong sendEndID + { + get + { + lock (this) + { + return EndID; + } + } + } + + public void SetSendBeginID(ulong recvid) + { + lock (this) + { + for (; BeginID < recvid; ++BeginID) + { + if (id_to_Buffer.ContainsKey(BeginID + 1)) + id_to_Buffer.Remove(BeginID + 1); + else + return; + } + } + } + + public bool Contains(ulong id) + { + lock (this) + { + return id_to_Buffer.ContainsKey(id); + } + } + + public byte[] Get(ulong id) + { + lock (this) + { + if (id_to_Buffer.ContainsKey(id)) + return id_to_Buffer[id].data; + return null; + } + } + + public List GetDataList(List idList) + { + List ret = new List(); + lock (this) + { + DateTime curTime = DateTime.Now; + foreach (ulong id in idList) + { + if (id_to_Buffer.ContainsKey(id)) + { + if ((curTime - id_to_Buffer[id].time).TotalSeconds > this.Interval) + { + id_to_Buffer[id].time = DateTime.Now; + ret.Add(id); + } + } + } + } + return ret; + } + + public ulong PushBack(byte[] dataBuffer) + { + lock (this) + { + for (int beg_pos = 0; beg_pos < dataBuffer.Length;) + { + int split_pos = beg_pos + MTU_MAX; + if (split_pos > dataBuffer.Length) + split_pos = dataBuffer.Length; + else + split_pos = beg_pos + random.Next(MTU_MIN, MTU_MAX); + byte[] sub_buffer = new byte[split_pos - beg_pos]; + Array.Copy(dataBuffer, beg_pos, sub_buffer, 0, sub_buffer.Length); + beg_pos = split_pos; + + id_to_Buffer[EndID] = new PacketInfo(sub_buffer); + ++EndID; + } + return EndID; + } + } + } + + class RecvQueue + { + private Dictionary id_to_Buffer = new Dictionary(); + private SortedDictionary id_missing = new SortedDictionary(); + private ulong CallbackBeginID = 0; + private ulong BeginID = 0; + private ulong EndID = 1; + + + public ulong recvCallbackID + { + get + { + lock (this) + { + return CallbackBeginID; + } + } + } + public ulong recvBeginID + { + get + { + lock (this) + { + return BeginID; + } + } + } + public ulong recvEndID + { + get + { + lock (this) + { + return EndID; + } + } + } + + public bool CanInsertID(ulong id) + { + lock (this) + { + return BeginID < id; + } + } + + public void InsertData(ulong id, byte[] data) + { + lock (this) + { + if (id_to_Buffer.ContainsKey(id)) + return; + if (BeginID < id) + { + id_to_Buffer[id] = data; + if (id_missing.ContainsKey(id)) + { + id_missing.Remove(id); + } + else if (EndID < id) + { + while (EndID < id) + { + id_missing[EndID] = true; + EndID++; + } + EndID++; + } + while (id_to_Buffer.ContainsKey(BeginID + 1)) + { + BeginID++; + } + } + } + } + + public bool HasCallbackData() + { + lock (this) + { + return CallbackBeginID < BeginID; + } + } + + public int GetCallbackData(byte[] data, int maxsize) + { + lock (this) + { + if (id_to_Buffer.ContainsKey(CallbackBeginID + 1)) + { + int len = id_to_Buffer[CallbackBeginID + 1].Length; + if (len > maxsize) + return 0; + CallbackBeginID++; + id_to_Buffer[CallbackBeginID].CopyTo(data, 0); + id_to_Buffer.Remove(CallbackBeginID); + return len; + } + } + return 0; + } + + public void SetEndID(ulong recvid) + { + lock (this) + { + while (EndID < recvid) + { + id_missing[EndID] = true; + EndID++; + } + } + } + + public List GetMissing(ref ulong recvid) + { + lock (this) + { + List ids = new List(); + recvid = BeginID; + //ulong end = EndID; + //if (end > recvid + 1024 * 32) + // end = recvid + 1024 * 32; + //for (ulong id = recvid + 1; id < end; ++id) + //{ + // if (this.id_to_Buffer.ContainsKey(id)) + // continue; + // ids.Add((ushort)(id - recvid)); + //} + foreach (ulong id in id_missing.Keys) + { + if (id - recvid > 32768) + break; + ids.Add((ushort)(id - recvid)); + } + return ids; + } + } + + } + + class TDPHandler + { + public enum Command + { + CMD_CONNECT = 0, + CMD_RSP_CONNECT = 1, + CMD_CONNECT_REMOTE = 2, + CMD_RSP_CONNECT_REMOTE = 3, + CMD_POST = 4, + CMD_SYN_STATUS = 5, + CMD_POST_64 = 6, + CMD_REQ_PACKET_64 = 7, + CMD_DISCONNECT = 8, + } + + enum ConnectState + { + END = -1, + READY = 0, + CONNECTING = 1, + CONNECTINGREMOTE = 2, + WAITCONNECTINGREMOTE = 3, + CONNECTED = 4, + CONNECTIONEND = 5, + DISCONNECTING = 6, + } + private ConnectState state = ConnectState.READY; + //private object stateLock = new object(); + + protected IEncryptor encryptor; + protected IEncryptor decryptor; + protected Socket sock; + private IPEndPoint sockEndPoint; + private string proxyServerURI; + private int proxyServerPort; + private string encryptMethod; + private string encryptPassword; + private uint requestid = 0; + private byte[] localid = new byte[4]; + + private object encryptionLock = new object(); + private object decryptionLock = new object(); + + // Size of receive buffer. + public const int RecvSize = 65536; + public const int BufferSize = RecvSize + 32; + // remote receive buffer + private byte[] recvBuffer = new byte[RecvSize]; + //private object recvLock = new object(); + // remote send buffer + //private List sendBufferList = new List(); + private LinkedList sendBufferList = new LinkedList(); + private byte[] sendConnectBuffer; + // callback buffer + private byte[] beginReceiveFromBuffer; + + private SendQueue id_to_sendBuffer = new SendQueue(); + private RecvQueue id_to_recvBuffer = new RecvQueue(); + //private ulong recvCallbackID = 0; + + protected Timer timer; + protected object timerLock = new object(); + + static uint logReqid = 0; + + private bool recvIdle; + public DateTime updateTime; + public int TTL = 60; + + private Random random = new Random(); + + private AsyncCallback asyncCallBackSend; + private object asyncCallBackSendLock = new object(); + private AsyncCallback asyncCallBackRecv; + private object asyncCallBackRecvLock = new object(); + + private int callBackBufferSize; + private object endReceiveFromLock = new object(); + + //private Object callBackState; + private readonly double time_CONNECTING = 0.2; + private readonly double time_CONNECTINGREMOTE = 0.2; + private readonly double time_WAITCONNECTINGREMOTE = 0.3; + private readonly double time_CONNECTED = 0.5; + private readonly double time_CONNECTIONEND = 1; + private readonly double time_DEFAULT = 1; + + private ConnectState State + { + get + { + return state; + } + set + { + state = value; + if (value == ConnectState.CONNECTING) + { + ResetTimeout(time_CONNECTING); + } + else if (value == ConnectState.WAITCONNECTINGREMOTE) + { + ResetTimeout(time_WAITCONNECTINGREMOTE); + } + else if (value == ConnectState.CONNECTED) + { + ResetTimeout(time_CONNECTED); + } + else if (value == ConnectState.END) + { + ResetTimeout(0); + } + } + } + + public AddressFamily AddressFamily + { + get + { + return sock.AddressFamily; + } + } + public TDPHandler() + { + recvIdle = true; + } + + private void ResetTimeout(Double time) + { + if (time <= 0 && timer == null) + return; + + lock (timerLock) + { + if (time <= 0) + { + if (timer != null) + { + timer.Enabled = false; + timer.Elapsed -= timer_Elapsed; + timer.Dispose(); + timer = null; + } + } + else + { + if (timer == null) + { + timer = new Timer(time * 1000.0); + timer.Elapsed += timer_Elapsed; + timer.Start(); + } + else + { + timer.Interval = time * 1000.0; + timer.Stop(); + timer.Start(); + } + } + } + } + + private void timer_Elapsed(object sender, ElapsedEventArgs e) + { + if (this.State == ConnectState.END) + { + return; + } + Idle(); + } + + protected void Update() + { + updateTime = DateTime.Now; + } + + protected bool isTimeout() + { + return (DateTime.Now - updateTime).TotalSeconds > TTL; + } + + private static void SetCRC32(byte[] buffer) + { + ulong crc = ~Shadowsocks.Util.CRC32.CalcCRC32(buffer, buffer.Length - 4); + buffer[buffer.Length - 1] = (byte)(crc >> 24); + buffer[buffer.Length - 2] = (byte)(crc >> 16); + buffer[buffer.Length - 3] = (byte)(crc >> 8); + buffer[buffer.Length - 4] = (byte)(crc); + } + + private byte[] CheckCRC32(byte[] buffer) + { + ulong crc = ~Shadowsocks.Util.CRC32.CalcCRC32(buffer, buffer.Length); + if (crc != 0xffffffff00000000u) + return null; + byte[] ret = new byte[buffer.Length - 4]; + Array.Copy(buffer, ret, buffer.Length - 4); + return ret; + } + private byte[] CheckRecvData(byte[] buffer) + { + if (buffer[buffer.Length - 2] != buffer[2] || buffer[buffer.Length - 1] != buffer[3]) + return null; + //ushort req_id = (ushort)(((ushort)buffer[buffer.Length - 2] << (ushort)8) + buffer[buffer.Length - 1]); + //if (this.requestid == 0) + //{ + //} + //else + //{ + // if (req_id != this.requestid) + // return null; + //} + byte[] ret = new byte[buffer.Length - 2]; + Array.Copy(buffer, ret, buffer.Length - 2); + return ret; + } + + private void doRecv() + { + if (sock != null && recvIdle) + { + //lock (recvLock) + if (sock != null && recvIdle) + { + IPEndPoint sender = new IPEndPoint(sock.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0); + EndPoint tempEP = (EndPoint)sender; + recvIdle = false; + sock.BeginReceiveFrom(recvBuffer, 0, RecvSize, SocketFlags.None, ref tempEP, + new AsyncCallback(UDPReceiveCallback), null); + } + } + } + + private int endRecv(IAsyncResult ar, ref EndPoint endPoint) + { + if (sock != null && !recvIdle) + { + //lock (recvLock) + if (sock != null && !recvIdle) + { + int bytesRead = sock.EndReceiveFrom(ar, ref endPoint); + recvIdle = true; + return bytesRead; + } + } + return 0; + } + private int tryRecv(ref EndPoint endPoint) + { + if (sock != null) + { + int bytesRead = sock.ReceiveFrom(recvBuffer, ref endPoint); + return bytesRead; + } + return 0; + } + + public static byte[] ParseUDPHeader(byte[] buffer, ref int len) + { + if (buffer.Length == 0) + return buffer; + if (buffer[0] == 0x81) + { + len = len - 1; + byte[] ret = new byte[len]; + Array.Copy(buffer, 1, ret, 0, len); + return ret; + } + if (buffer[0] == 0x80 && len >= 2) + { + int ofbs_len = buffer[1]; + if (ofbs_len + 2 < len) + { + len = len - ofbs_len - 2; + byte[] ret = new byte[len]; + Array.Copy(buffer, ofbs_len + 2, ret, 0, len); + return ret; + } + } + if (buffer[0] == 0x82 && len >= 3) + { + int ofbs_len = (buffer[1] << 8) + buffer[2]; + if (ofbs_len + 3 < len) + { + len = len - ofbs_len - 3; + byte[] ret = new byte[len]; + Array.Copy(buffer, ofbs_len + 3, ret, 0, len); + return ret; + } + } + if (len < buffer.Length) + { + byte[] ret = new byte[len]; + Array.Copy(buffer, ret, len); + return ret; + } + return buffer; + } + + private void RemoteSendto(byte[] bytes, int length, int insert_index, bool obfs, int obfs_max = 40) + { + int bytesToSend; + byte[] bytesToEncrypt = null; + int bytes_beg = 0; + length -= bytes_beg; + if (bytes[0] != 8) + { + bytesToEncrypt = new byte[1]; + } + { + bytesToEncrypt = new byte[length]; + Array.Copy(bytes, bytes_beg, bytesToEncrypt, 0, length); + } + Logging.LogBin(LogLevel.Debug, "remote sendto", bytesToEncrypt, length); + byte[] sendBuffer; + try + { + lock (encryptionLock) + { + if (this.State == ConnectState.END) + { + return; + } + sendBuffer = new byte[BufferSize]; + encryptor.Reset(); + encryptor.Encrypt(bytesToEncrypt, length, sendBuffer, out bytesToSend); + } + sendBuffer = CreateProxyWrapper(sendBuffer, ref bytesToSend); + byte[] buffer = sendBuffer; + if (bytesToSend != buffer.Length) + { + buffer = new byte[bytesToSend]; + Array.Copy(sendBuffer, buffer, bytesToSend); + } + lock (sendBufferList) + { + if (insert_index == -1) + { + sendBufferList.AddLast(buffer); + } + else + { + if (sendBufferList.Count > 0) + { + sendBufferList.AddAfter(sendBufferList.First, buffer); + } + else + { + sendBufferList.AddLast(buffer); + } + } + if (sendBufferList.Count == 1) + { + sock.BeginSendTo(buffer, 0, bytesToSend, 0, sockEndPoint, new AsyncCallback(UDPSendCallback), null); + } + } + } + catch (Exception e) + { + Logging.LogUsefulException(e); + this.Shutdown(); + } + } + + private bool RemoveRemoteUDPRecvBufferHeader(byte[] remoteRecvBuffer, ref int bytesRead) + { + if (proxyServerPort > 0) + { + if (bytesRead < 7) + { + return false; + } + int port = -1; + if (remoteRecvBuffer[3] == 1) + { + int head = 3 + 1 + 4 + 2; + bytesRead = bytesRead - head; + port = remoteRecvBuffer[head - 2] * 0x100 + remoteRecvBuffer[head - 1]; + Array.Copy(remoteRecvBuffer, head, remoteRecvBuffer, 0, bytesRead); + } + else if (remoteRecvBuffer[3] == 4) + { + int head = 3 + 1 + 16 + 2; + bytesRead = bytesRead - head; + port = remoteRecvBuffer[head - 2] * 0x100 + remoteRecvBuffer[head - 1]; + Array.Copy(remoteRecvBuffer, head, remoteRecvBuffer, 0, bytesRead); + } + else if (remoteRecvBuffer[3] == 3) + { + int head = 3 + 1 + 1 + remoteRecvBuffer[4] + 2; + bytesRead = bytesRead - head; + port = remoteRecvBuffer[head - 2] * 0x100 + remoteRecvBuffer[head - 1]; + Array.Copy(remoteRecvBuffer, head, remoteRecvBuffer, 0, bytesRead); + } + else + { + return false; + } + if (port != proxyServerPort) + { + return false; + } + } + return true; + } + + + private void UDPSendCallback(IAsyncResult ar) + { + if (this.State == ConnectState.END) + { + return; + } + try + { + sock.EndSendTo(ar); + lock (sendBufferList) + { + sendBufferList.RemoveFirst(); + if (sendBufferList.Count > 0) + { + sock.BeginSendTo(sendBufferList.First.Value, 0, sendBufferList.First.Value.Length, 0, sockEndPoint, new AsyncCallback(UDPSendCallback), null); + } + } + } + catch (Exception e) + { + Logging.LogUsefulException(e); + this.Shutdown(); + } + } + + private void UDPReceiveCallback(IAsyncResult ar) + { + if (this.State == ConnectState.END) + { + return; + } + try + { + IPEndPoint sender = new IPEndPoint(sock.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0); + EndPoint tempEP = (EndPoint)sender; + + int bytesRead = endRecv(ar, ref tempEP); + + if (bytesRead > 0) + { + Update(); + while (bytesRead > 0) + { + if (RemoveRemoteUDPRecvBufferHeader(recvBuffer, ref bytesRead)) + { + int bytesRecv; + byte[] decryptBuffer = new byte[RecvSize]; + lock (decryptionLock) + { + if (this.State == ConnectState.END) + { + return; + } + decryptor.Reset(); + decryptor.Decrypt(recvBuffer, bytesRead, decryptBuffer, out bytesRecv); + decryptBuffer = ParseUDPHeader(decryptBuffer, ref bytesRecv); + } + + if (bytesRecv > 6) + { + //decryptBuffer = CheckCRC32(decryptBuffer); + //if (decryptBuffer != null) + byte[] debugBuffer = decryptBuffer; + decryptBuffer = CheckRecvData(decryptBuffer); + if (decryptBuffer != null) + { + HandleReceive(decryptBuffer); + //doRecv(); + return; + } + //else + //{ + // break; + //} + } + if (DataCallbackRecvInvoke()) + return; + } + //else + //{ + // break; + //} + //bytesRead = tryRecv(ref tempEP); + break; + } + doRecv(); + } + else + { + Shutdown(); + } + } + catch (Exception e) + { + Logging.LogUsefulException(e); + Shutdown(); + } + } + + private void HandleReceive(byte[] buffer) + { + if (buffer[0] == 8) + { + if ((Command)buffer[1] == Command.CMD_DISCONNECT) + { + if (requestid == 0) + { + } + else + { + uint reqid = ((uint)buffer[2] << 8) + buffer[3]; + if (reqid == requestid) + { + System.Diagnostics.Debug.Write("HandleReceive DISCONNECT\r\n"); + this.State = ConnectState.DISCONNECTING; + } + } + } + if (this.State == ConnectState.CONNECTING) + { + if ((Command)buffer[1] == Command.CMD_RSP_CONNECT + && requestid == 0) + { + if (buffer[4] == 1) + { + requestid = ((uint)buffer[2] << 8) + buffer[3]; + this.State = ConnectState.CONNECTINGREMOTE; + if (!CallbackSendInvoke()) + { + throw new SocketException((int)SocketError.ConnectionAborted); + } + if (logReqid == 0) + logReqid = requestid; + } + else //if (buffer[4] == 0 || buffer[4] == 3 || buffer[4] == 4 || buffer[4] == 5) + { + throw new SocketException((int)SocketError.ConnectionAborted); + } + } + return; + } + else if (this.State == ConnectState.WAITCONNECTINGREMOTE) + { + if ((Command)buffer[1] == Command.CMD_RSP_CONNECT_REMOTE + && requestid != 0) + { + if (buffer[4] == 2) + { + uint reqid = ((uint)buffer[2] << 8) + buffer[3]; + if (reqid == requestid) + { + this.State = ConnectState.CONNECTED; + { + for (uint id = 1; id < id_to_sendBuffer.sendEndID; ++id) + { + SendData(id); + if (id >= 1024) break; + } + } + } + } + else if (buffer[4] == 0 || buffer[4] == 3 || buffer[4] == 4) + { + throw new SocketException((int)SocketError.ConnectionAborted); + } + } + else + { + return; + } + } + else if (this.State == ConnectState.CONNECTED) + { + uint reqid = ((uint)buffer[2] << 8) + buffer[3]; + if (reqid == requestid) + { + if ((Command)buffer[1] == Command.CMD_POST) + { + int beg_index = 4 + 8; + uint recv_id = ((uint)buffer[4] << 24) + ((uint)buffer[5] << 16) + ((uint)buffer[6] << 8) + buffer[7]; + uint pack_id = ((uint)buffer[8] << 24) + ((uint)buffer[9] << 16) + ((uint)buffer[10] << 8) + buffer[11]; + id_to_sendBuffer.SetSendBeginID(recv_id); + id_to_recvBuffer.SetEndID(pack_id + 1); + if (id_to_recvBuffer.CanInsertID(pack_id)) + { + byte[] ret_buf = new byte[buffer.Length - beg_index]; + Array.Copy(buffer, beg_index, ret_buf, 0, ret_buf.Length); + id_to_recvBuffer.InsertData(pack_id, ret_buf); + } + //if (true + // //requestid == logReqid && logReqid != 0 + // //&& (this.sendBeginID + 1 < this.sendEndID || !id_to_recvBuffer.Empty()) + // ) + // System.Diagnostics.Debug.Write("HandleReceive CMD_POST" + // + " req=" + requestid + // + " p_recv=" + recv_id + // + " id=" + pack_id + // + " pack " + pack_id.ToString() + " " + // + " send " + id_to_sendBuffer.sendBeginID.ToString() + " " + // + id_to_sendBuffer.sendEndID.ToString() + // + " recv " + id_to_recvBuffer.recvCallbackID + " " + id_to_recvBuffer.recvBeginID.ToString() + " " + // + id_to_recvBuffer.recvEndID.ToString() + // + "\r\n" + // ); + } + else if ((Command)buffer[1] == Command.CMD_SYN_STATUS) + { + int beg_index = 4 + 8; + uint recv_id = ((uint)buffer[4] << 24) + ((uint)buffer[5] << 16) + ((uint)buffer[6] << 8) + buffer[7]; + uint send_id = ((uint)buffer[8] << 24) + ((uint)buffer[9] << 16) + ((uint)buffer[10] << 8) + buffer[11]; + id_to_sendBuffer.SetSendBeginID(recv_id); + id_to_recvBuffer.SetEndID(send_id); + + int id_count = (buffer.Length - beg_index) / 2; + + //if (true + // //requestid == logReqid && logReqid != 0 + // //&& (this.sendBeginID + 1 < this.sendEndID || !id_to_recvBuffer.Empty()) + // ) + // System.Diagnostics.Debug.Write("HandleReceive CMD_SYN_STATUS" + // + " req=" + requestid + // + " p_recv=" + recv_id + // + " p_send=" + send_id + // + " size=" + id_count.ToString() + // + " send " + id_to_sendBuffer.sendBeginID.ToString() + " " + // + id_to_sendBuffer.sendEndID.ToString() + // + " recv " + id_to_recvBuffer.recvCallbackID + " " + id_to_recvBuffer.recvBeginID.ToString() + " " + // + id_to_recvBuffer.recvEndID.ToString() + // + "\r\n" + // ); + List idList = new List(); + for (int index = 0; index < id_count; ++index) + { + ulong id = recv_id + buffer[beg_index + index * 2] * 0x100u + buffer[beg_index + index * 2 + 1]; + idList.Add(id); + } + List packetList = this.id_to_sendBuffer.GetDataList(idList); + foreach (ulong id in packetList) + { + SendData(id); + } + + //for (int index = 0; index < id_count; ++index) + //{ + // ulong id = recv_id + buffer[beg_index + index * 2] * 0x100u + buffer[beg_index + index * 2 + 1]; + // if (id > id_to_sendBuffer.sendBeginID) + // { + // if (this.id_to_sendBuffer.Contains(id)) + // { + // if (requestid == logReqid && logReqid != 0) + // System.Diagnostics.Debug.Write("HandleReceive " + // + " req=" + requestid + // + " send " + id.ToString() + // + "\r\n" + // ); + // SendData(id); + // } + // else + // { + // if (requestid == logReqid && logReqid != 0) + // System.Diagnostics.Debug.Write("HandleReceive MISSING" + // + " req=" + requestid + // + " send " + id.ToString() + // + "\r\n" + // ); + // } + // } + //} + } + } + } + } + if (DataCallbackRecvInvoke()) + { + return; + } + else if (this.State == ConnectState.DISCONNECTING) + { + CallbackRecvInvoke(); + } + doRecv(); + } + + private byte[] CreateProxyWrapper(byte[] data, ref int bytesToSend) + { + if (proxyServerPort == 0) + return data; + + byte[] bytesToEncrypt; + int bytes_beg = 3; + + IPAddress ipAddress; + string serverURI = proxyServerURI; + int serverPort = proxyServerPort; + bool parsed = IPAddress.TryParse(serverURI, out ipAddress); + if (!parsed) + { + bytesToEncrypt = new byte[bytes_beg + 1 + 1 + serverURI.Length + 2 + bytesToSend]; + Array.Copy(data, 0, bytesToEncrypt, bytes_beg + 1 + 1 + serverURI.Length + 2, bytesToSend); + bytesToEncrypt[0] = 0; + bytesToEncrypt[1] = 0; + bytesToEncrypt[2] = 0; + bytesToEncrypt[3] = (byte)3; + bytesToEncrypt[4] = (byte)serverURI.Length; + for (int i = 0; i < serverURI.Length; ++i) + { + bytesToEncrypt[5 + i] = (byte)serverURI[i]; + } + bytesToEncrypt[5 + serverURI.Length] = (byte)(serverPort / 0x100); + bytesToEncrypt[5 + serverURI.Length + 1] = (byte)(serverPort % 0x100); + } + else + { + byte[] addBytes = ipAddress.GetAddressBytes(); + bytesToEncrypt = new byte[bytes_beg + 1 + addBytes.Length + 2 + bytesToSend]; + Array.Copy(data, 0, bytesToEncrypt, bytes_beg + 1 + addBytes.Length + 2, bytesToSend); + bytesToEncrypt[0] = 0; + bytesToEncrypt[1] = 0; + bytesToEncrypt[2] = 0; + bytesToEncrypt[3] = ipAddress.AddressFamily == AddressFamily.InterNetworkV6 ? (byte)4 : (byte)1; + for (int i = 0; i < addBytes.Length; ++i) + { + bytesToEncrypt[4 + i] = addBytes[i]; + } + bytesToEncrypt[4 + addBytes.Length] = (byte)(serverPort / 0x100); + bytesToEncrypt[4 + addBytes.Length + 1] = (byte)(serverPort % 0x100); + } + + bytesToSend = bytesToEncrypt.Length; + //Array.Copy(bytesToEncrypt, connetionSendBuffer, bytesToSend); + return bytesToEncrypt; + + //if (proxyEndPoint.AddressFamily == AddressFamily.InterNetwork) + //{ + // byte[] buffer = new byte[4 + 4 + 2 + data.Length]; + // data.CopyTo(buffer, 4 + 4 + 2); + // buffer[3] = 1; + // proxyEndPoint.Address.GetAddressBytes().CopyTo(buffer, 4); + // buffer[4 + 4] = (byte)(proxyEndPoint.Port >> 8); + // buffer[4 + 4 + 1] = (byte)(proxyEndPoint.Port); + // return data; + //} + //else + //{ + // byte[] buffer = new byte[4 + 16 + 2 + data.Length]; + // data.CopyTo(buffer, 4 + 16 + 2); + // buffer[3] = 4; + // proxyEndPoint.Address.GetAddressBytes().CopyTo(buffer, 4); + // buffer[4 + 16] = (byte)(proxyEndPoint.Port >> 8); + // buffer[4 + 16 + 1] = (byte)(proxyEndPoint.Port); + // return data; + //} + } + + private byte[] CreateConnectData() + { + int size = random.Next(64); + byte[] buffer = new byte[4 + 4 + size + 4]; + buffer[0] = 0x8; + buffer[1] = (byte)Command.CMD_CONNECT; + localid.CopyTo(buffer, 4); + SetCRC32(buffer); + return buffer; + } + + private byte[] CreateRequestConnectData(byte[] connectInfo) + { + int size = random.Next(64); + byte[] buffer = new byte[4 + 4 + connectInfo.Length + size + 4]; + buffer[0] = 0x8; + buffer[1] = (byte)Command.CMD_CONNECT_REMOTE; + buffer[2] = (byte)(requestid / 256); + buffer[3] = (byte)(requestid % 256); + localid.CopyTo(buffer, 4); + Array.Copy(connectInfo, 0, buffer, 8, connectInfo.Length); + SetCRC32(buffer); + return buffer; + } + + private byte[] CreateCloseConnectData() + { + int size = random.Next(64); + byte[] buffer = new byte[4 + 4 + size + 4]; + buffer[0] = 0x8; + buffer[1] = (byte)Command.CMD_DISCONNECT; + buffer[2] = (byte)(requestid / 256); + buffer[3] = (byte)(requestid % 256); + localid.CopyTo(buffer, 4); + SetCRC32(buffer); + return buffer; + } + + private byte[] CreateSendData(ulong id, byte[] data) + { + if (data == null) + return null; + byte[] buffer; + ulong recvid = id_to_recvBuffer.recvBeginID; + int beginIndex; + if (id > 0xffffffff || recvid > 0xffffffff) + { + beginIndex = 8 + 16; + buffer = new byte[beginIndex + data.Length + 4]; + buffer[0] = 0x8; + buffer[1] = (byte)Command.CMD_POST_64; + buffer[2] = (byte)(requestid / 256); + buffer[3] = (byte)(requestid % 256); + byte[] bytes = BitConverter.GetBytes(recvid); + Array.Reverse(bytes); + Array.Copy(bytes, 0, buffer, 8, 8); + bytes = BitConverter.GetBytes(id); + Array.Reverse(bytes); + Array.Copy(bytes, 0, buffer, 16, 8); + } + else + { + beginIndex = 8 + 8; + buffer = new byte[beginIndex + data.Length + 4]; + buffer[0] = 0x8; + buffer[1] = (byte)Command.CMD_POST; + buffer[2] = (byte)(requestid / 256); + buffer[3] = (byte)(requestid % 256); + + buffer[8] = (byte)((recvid >> 24) & 0xff); + buffer[9] = (byte)((recvid >> 16) & 0xff); + buffer[10] = (byte)((recvid >> 8) & 0xff); + buffer[11] = (byte)((recvid) & 0xff); + + buffer[12] = (byte)((id >> 24) & 0xff); + buffer[13] = (byte)((id >> 16) & 0xff); + buffer[14] = (byte)((id >> 8) & 0xff); + buffer[15] = (byte)((id) & 0xff); + } + localid.CopyTo(buffer, 4); + Array.Copy(data, 0, buffer, beginIndex, data.Length); + SetCRC32(buffer); + return buffer; + } + + private byte[] CreateRndData(byte[] data) + { + byte[] buffer; + int length = random.Next(1024); + if (length == 0) return data; + else if (length == 1) + { + buffer = new byte[data.Length + 1]; + data.CopyTo(buffer, 1); + buffer[0] = 0x81; + } + else if (length < 256) + { + buffer = new byte[data.Length + length]; + data.CopyTo(buffer, length); + buffer[0] = 0x80; + buffer[1] = (byte)length; + } + else + { + buffer = new byte[data.Length + length]; + data.CopyTo(buffer, length); + buffer[0] = 0x82; + buffer[1] = (byte)(length >> 8); + buffer[2] = (byte)(length); + } + return buffer; + } + + private byte[] CreateSyncData() + { + byte[] buffer; + ulong recvid = 0; + ulong sendid = id_to_sendBuffer.sendEndID; + if (sendid > 0xffffffff || id_to_recvBuffer.recvEndID > 0xffffffff) + { + // 64 + } + { + List ids = id_to_recvBuffer.GetMissing(ref recvid); + + buffer = new byte[8 + 8 + ids.Count * 2 + 4]; + buffer[0] = 0x8; + buffer[1] = (byte)Command.CMD_SYN_STATUS; + buffer[2] = (byte)(requestid / 256); + buffer[3] = (byte)(requestid % 256); + + buffer[8] = (byte)((recvid >> 24) & 0xff); + buffer[9] = (byte)((recvid >> 16) & 0xff); + buffer[10] = (byte)((recvid >> 8) & 0xff); + buffer[11] = (byte)((recvid) & 0xff); + + buffer[12] = (byte)((sendid >> 24) & 0xff); + buffer[13] = (byte)((sendid >> 16) & 0xff); + buffer[14] = (byte)((sendid >> 8) & 0xff); + buffer[15] = (byte)((sendid) & 0xff); + + for (int index = 0; index < ids.Count; ++index) + { + buffer[16 + index * 2] = (byte)(ids[index] >> 8); + buffer[16 + index * 2 + 1] = (byte)(ids[index] & 0xff); + } + //if (requestid == logReqid && logReqid != 0 + // //&& (this.sendBeginID + 1 < this.sendEndID || !id_to_recvBuffer.Empty()) + // ) + // System.Diagnostics.Debug.Write("CreateSyncData" + // + " req=" + requestid + // + " size=" + ids.Count.ToString() + // + " send " + id_to_sendBuffer.sendBeginID.ToString() + " " + // + id_to_sendBuffer.sendEndID.ToString() + // + " recv " + id_to_recvBuffer.recvBeginID.ToString() + " " + // + id_to_recvBuffer.recvEndID.ToString() + // + "\r\n" + // ); + } + localid.CopyTo(buffer, 4); + SetCRC32(buffer); + return buffer; + } + + private void SendData(ulong id) + { + byte[] buf = CreateSendData(id, id_to_sendBuffer.Get(id)); + if (buf != null) RemoteSendto(buf, buf.Length, -1, false); + if (id <= 16) + { + buf = CreateSendData(id, id_to_sendBuffer.Get(id)); + if (buf != null) RemoteSendto(buf, buf.Length, -1, false); + } + } + + public void BeginConnect(string method, string password, IPEndPoint ep, string proxyServerURI, int proxyServerPort, AsyncCallback callback, Object state) + { + if (this.State == ConnectState.END) + { + throw new SocketException((int)SocketError.ConnectionAborted); + } + Update(); + { + if (this.State == ConnectState.READY) + { + encryptMethod = method; + encryptPassword = password; + this.encryptor = EncryptorFactory.GetEncryptor(method, password); + this.decryptor = EncryptorFactory.GetEncryptor(method, password); + this.sockEndPoint = ep; + this.proxyServerURI = proxyServerURI; + this.proxyServerPort = proxyServerPort; + + sock = new Socket(ep.AddressFamily, SocketType.Dgram, ProtocolType.Udp); + sock.SendBufferSize = 1024 * 1024 * 4; + sock.ReceiveBufferSize = 1024 * 1024 * 4; + + random.NextBytes(localid); + byte[] sendBuffer = CreateConnectData(); + + lock (asyncCallBackSendLock) + { + this.asyncCallBackSend = callback; + //this.callBackState = state; + } + + RemoteSendto(sendBuffer, sendBuffer.Length, -1, false); + doRecv(); + this.State = ConnectState.CONNECTING; + } + } + } + public void EndConnect(IAsyncResult ar) + { + if (this.State == ConnectState.END) + { + throw new SocketException((int)SocketError.ConnectionAborted); + } + } + + public void Shutdown() + { + if (this.State != ConnectState.END && this.State != ConnectState.DISCONNECTING) + { + this.State = ConnectState.CONNECTIONEND; + } + + CallbackSendInvoke(); + if (DataCallbackRecvInvoke()) + return; + } + + public void Close() + { + lock (this) + { + if (this.State == ConnectState.END) + { + return; + } + else + { + this.State = ConnectState.END; + } + } + + sendBufferList = new LinkedList(); + lock (encryptionLock) + { + lock (decryptionLock) + { + if (encryptor != null) + ((IDisposable)encryptor).Dispose(); + if (decryptor != null) + ((IDisposable)decryptor).Dispose(); + } + } + + CallbackSendInvoke(); + CallbackRecvInvoke(); + + lock (this) + { + if (sock != null) + { + try + { + sock.Shutdown(SocketShutdown.Both); + sock.Close(); + } + catch (Exception e) + { + Logging.LogUsefulException(e); + } + sock = null; + } + } + + id_to_sendBuffer = new SendQueue(); + id_to_recvBuffer = new RecvQueue(); + } + + private bool CallbackSendInvoke() + { + AsyncCallback lastCallback = null; + lock (asyncCallBackSendLock) + { + if (this.asyncCallBackSend != null) + { + Update(); + lastCallback = this.asyncCallBackSend; + this.asyncCallBackSend = null; + } + } + if (lastCallback != null) + { + lastCallback.Invoke(null); //ConnectCallback + return true; + } + return false; + } + + private bool CallbackRecvInvoke() + { + AsyncCallback lastCallback = null; + lock (asyncCallBackRecvLock) + { + if (this.asyncCallBackRecv != null) + { + Update(); + lastCallback = this.asyncCallBackRecv; + this.asyncCallBackRecv = null; + } + } + if (lastCallback != null) + { + lastCallback.Invoke(null); + return true; + } + return false; + } + + private bool DataCallbackRecvInvoke() + { + lock (asyncCallBackRecvLock) + { + if (id_to_recvBuffer.HasCallbackData()) + { + return CallbackRecvInvoke(); + } + } + return false; + } + + public void BeginSendTo(byte[] sendbuffer, int size, AsyncCallback callback, object state) + { + if (this.State == ConnectState.END) + { + throw new SocketException((int)SocketError.ConnectionAborted); + } + Update(); + lock (this) + { + lock (asyncCallBackSendLock) + { + this.asyncCallBackSend = callback; + //this.callBackState = state; + } + byte[] buffer = new byte[size]; + Array.Copy(sendbuffer, 0, buffer, 0, size); + if (this.State == ConnectState.CONNECTINGREMOTE) + { + if (sendConnectBuffer == null) + { + int headerSize = 0; + if (buffer[0] == 3) + { + headerSize = 2 + buffer[1] + 2; + } + else if (buffer[0] == 1) + { + headerSize = 1 + 4 + 2; + } + else if (buffer[0] == 4) + { + headerSize = 1 + 16 + 2; + } + if (headerSize < buffer.Length) + { + byte[] dataBuffer = new byte[buffer.Length - headerSize]; + Array.Copy(buffer, headerSize, dataBuffer, 0, dataBuffer.Length); + buffer = new byte[headerSize]; + Array.Copy(sendbuffer, buffer, headerSize); + id_to_sendBuffer.PushBack(dataBuffer); + } + sendConnectBuffer = buffer; + } + else + { + id_to_sendBuffer.PushBack(buffer); + } + this.State = ConnectState.WAITCONNECTINGREMOTE; + for (int i = 0; i < 2; ++i) + { + byte[] sendBuffer = CreateRequestConnectData(buffer); + RemoteSendto(sendBuffer, sendBuffer.Length, -1, false); + } + } + else if (this.State == ConnectState.WAITCONNECTINGREMOTE || this.State == ConnectState.CONNECTED) + { + if (this.State == ConnectState.WAITCONNECTINGREMOTE) + { + id_to_sendBuffer.PushBack(buffer); + } + else if (this.State == ConnectState.CONNECTED) + { + ulong end_id = id_to_sendBuffer.PushBack(buffer); + ulong beg_id = id_to_sendBuffer.sendBeginID; + if (beg_id + 1024 >= end_id) + SendData(end_id - 1); + } + } + CallbackSendInvoke(); + } + } + + public void BeginReceiveFrom(byte[] buffer, int size, AsyncCallback callback, object state) + { + lock (asyncCallBackRecvLock) + { + beginReceiveFromBuffer = buffer; + this.asyncCallBackRecv = callback; + this.callBackBufferSize = size; + } + if (DataCallbackRecvInvoke()) + return; + if (this.State == ConnectState.END) + { + throw new SocketException((int)SocketError.ConnectionAborted); + } + if (this.State == ConnectState.CONNECTIONEND) + { + CallbackRecvInvoke(); + } + else + { + doRecv(); + } + } + + public int EndReceiveFrom(IAsyncResult ar, ref EndPoint endPoint) + { + return id_to_recvBuffer.GetCallbackData(beginReceiveFromBuffer, callBackBufferSize); + + //int total_len = 0; + //lock (endReceiveFromLock) + //{ + // byte[] recvBuffer = new byte[callBackBufferSize]; + // while (total_len < callBackBufferSize) + // { + // int len = id_to_recvBuffer.GetCallbackData(recvBuffer, callBackBufferSize - total_len); //this.id_to_recvBuffer[recvCallbackID].Length; + // if (len == 0) + // break; + // Array.Copy(recvBuffer, 0, beginReceiveFromBuffer, total_len, len); + // total_len += len; + + // if (requestid == logReqid && logReqid != 0) + // { + // System.Diagnostics.Debug.Write("EndReceiveFrom" + // + " req=" + requestid + // + " send " + id_to_sendBuffer.sendBeginID.ToString() + " " + // + id_to_sendBuffer.sendEndID.ToString() + // + " recv " + id_to_recvBuffer.recvCallbackID.ToString() + " " + // + id_to_recvBuffer.recvEndID.ToString() + // + " " + id_to_recvBuffer.ToString() + // + "\r\n" + // ); + // } + // } + //} + //return total_len; + } + + protected void Idle() + { + //if (requestid == logReqid && logReqid != 0) + //{ + // System.Diagnostics.Debug.Write("Idle" + requestid + " " + this.State + "\r\n"); + //} + if (//this.State == ConnectState.DISCONNECTING || + this.State == ConnectState.END) + { + ResetTimeout(0); + return; + } + if (isTimeout()) + { + Close(); + } + if (this.State == ConnectState.READY) + { + ResetTimeout(0); + } + else if (this.State == ConnectState.CONNECTING) + { + byte[] sendBuffer = CreateConnectData(); + RemoteSendto(sendBuffer, sendBuffer.Length, -1, false); + ResetTimeout(time_CONNECTING); + } + else if (this.State == ConnectState.CONNECTINGREMOTE) + { + ResetTimeout(time_CONNECTINGREMOTE); + } + else if (this.State == ConnectState.WAITCONNECTINGREMOTE) + { + byte[] sendBuffer = CreateRequestConnectData(sendConnectBuffer); + RemoteSendto(sendBuffer, sendBuffer.Length, -1, false); + ResetTimeout(time_WAITCONNECTINGREMOTE); + } + else if (this.State == ConnectState.CONNECTED) + { + byte[] sendBuffer = CreateSyncData(); + RemoteSendto(sendBuffer, sendBuffer.Length, 0, false); + ResetTimeout(time_CONNECTED); + } + else if (this.State == ConnectState.CONNECTIONEND) + { + try + { + if (requestid != 0 && sock != null) + { + byte[] buf = CreateCloseConnectData(); + RemoteSendto(buf, buf.Length, -1, false); + } + } + catch + { + //pass + } + if (requestid == 0 || sock == null) + { + ResetTimeout(0); + Close(); + } + else + { + ResetTimeout(time_CONNECTIONEND); + } + } + else if (this.State == ConnectState.DISCONNECTING) + { + ResetTimeout(0); + Close(); + } + else + { + ResetTimeout(time_DEFAULT); + } + } + } +} diff --git a/shadowsocks-csharp/Controller/UpdateChecker.cs b/shadowsocks-csharp/Controller/UpdateChecker.cs index cbffdb15..db76f2f2 100755 --- a/shadowsocks-csharp/Controller/UpdateChecker.cs +++ b/shadowsocks-csharp/Controller/UpdateChecker.cs @@ -21,7 +21,7 @@ namespace Shadowsocks.Controller public const string Name = "ShadowsocksR"; public const string Copyright = "Copyright © BreakWall 2015"; - public const string Version = "3.3.6"; + public const string Version = "3.4.0"; public const string FullVersion = Version + " Final"; private static bool UseProxy = true; diff --git a/shadowsocks-csharp/Data/cn.txt b/shadowsocks-csharp/Data/cn.txt index ec69cff4..05580fb4 100644 --- a/shadowsocks-csharp/Data/cn.txt +++ b/shadowsocks-csharp/Data/cn.txt @@ -48,13 +48,13 @@ Encryption=加密 Remarks=备注 Adv. Setting=高级选项 +TCPoverUDP=TCP over UDP UDPoverTCP=UDP over TCP -UDPoverUDP=UDP over UDP Obfs TCP=混淆TCP协议头 Obfs UDP=混淆UDP协议 NOT all server support belows=以下选项不是所有服务端都支持 +TCP over TCP if not checked=不打钩使用 TCP over TCP UDP over UDP if not checked=不打钩使用 UDP over UDP -UDP over TCP if not checked=不打钩使用 UDP over TCP Recommend checked=保留功能 Checked if server support=服务端支持的话打钩 Link=链接 @@ -67,7 +67,7 @@ LowException=低错误优先 SelectedFirst=选中优先 AutoBan=自动禁用出错服务器 -Socks5 Proxy=Socks5代理(连接服务器用) +Socks5 Proxy=Socks5代理(前置代理) Socks5 Proxy On=开启Socks5 Username=用户名 diff --git a/shadowsocks-csharp/Util/CRC.cs b/shadowsocks-csharp/Util/CRC.cs new file mode 100644 index 00000000..c7bcb20f --- /dev/null +++ b/shadowsocks-csharp/Util/CRC.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Shadowsocks.Util +{ + class CRC32 + { + static protected ulong[] Crc32Table; + //生成CRC32码表 + static public void CreateCRC32Table() + { + ulong Crc; + Crc32Table = new ulong[256]; + int i, j; + for (i = 0; i < 256; i++) + { + Crc = (ulong)i; + for (j = 8; j > 0; j--) + { + if ((Crc & 1) == 1) + Crc = (Crc >> 1) ^ 0xEDB88320; + else + Crc >>= 1; + } + Crc32Table[i] = Crc; + } + } + + //获取字符串的CRC32校验值 + static public ulong CalcCRC32(byte[] input, int len, ulong value = 0xffffffff) + { + //生成码表 + if (Crc32Table == null) + CreateCRC32Table(); + byte[] buffer = input; + for (int i = 0; i < len; i++) + { + value = (value >> 8) ^ Crc32Table[(value & 0xFF) ^ buffer[i]]; + } + return value ^ 0xffffffff; + } + } +} diff --git a/shadowsocks-csharp/View/ConfigForm.Designer.cs b/shadowsocks-csharp/View/ConfigForm.Designer.cs index e08fecc8..6338265e 100755 --- a/shadowsocks-csharp/View/ConfigForm.Designer.cs +++ b/shadowsocks-csharp/View/ConfigForm.Designer.cs @@ -49,6 +49,8 @@ this.LabelNote = new System.Windows.Forms.Label(); this.LabelExpertSetting = new System.Windows.Forms.Label(); this.PasswordLabel = new System.Windows.Forms.CheckBox(); + this.TCPoverUDPLabel = new System.Windows.Forms.Label(); + this.CheckTCPoverUDP = new System.Windows.Forms.CheckBox(); this.panel2 = new System.Windows.Forms.Panel(); this.DeleteButton = new System.Windows.Forms.Button(); this.AddButton = new System.Windows.Forms.Button(); @@ -117,24 +119,26 @@ this.tableLayoutPanel1.Controls.Add(this.PasswordTextBox, 1, 2); this.tableLayoutPanel1.Controls.Add(this.EncryptionLabel, 0, 3); this.tableLayoutPanel1.Controls.Add(this.EncryptionSelect, 1, 3); - this.tableLayoutPanel1.Controls.Add(this.LabelLink, 0, 9); - this.tableLayoutPanel1.Controls.Add(this.TextLink, 1, 9); + this.tableLayoutPanel1.Controls.Add(this.LabelLink, 0, 10); + this.tableLayoutPanel1.Controls.Add(this.TextLink, 1, 10); this.tableLayoutPanel1.Controls.Add(this.RemarksLabel, 0, 4); this.tableLayoutPanel1.Controls.Add(this.RemarksTextBox, 1, 4); - this.tableLayoutPanel1.Controls.Add(this.ObfsUDPLabel, 0, 8); - this.tableLayoutPanel1.Controls.Add(this.CheckObfsUDP, 1, 8); - this.tableLayoutPanel1.Controls.Add(this.ObfsTCPLabel, 0, 7); - this.tableLayoutPanel1.Controls.Add(this.UDPoverTCPLabel, 0, 6); - this.tableLayoutPanel1.Controls.Add(this.CheckObfsTCP, 1, 7); - this.tableLayoutPanel1.Controls.Add(this.CheckUDPoverUDP, 1, 6); + this.tableLayoutPanel1.Controls.Add(this.ObfsUDPLabel, 0, 9); + this.tableLayoutPanel1.Controls.Add(this.CheckObfsUDP, 1, 9); + this.tableLayoutPanel1.Controls.Add(this.ObfsTCPLabel, 0, 8); + this.tableLayoutPanel1.Controls.Add(this.UDPoverTCPLabel, 0, 7); + this.tableLayoutPanel1.Controls.Add(this.CheckObfsTCP, 1, 8); + this.tableLayoutPanel1.Controls.Add(this.CheckUDPoverUDP, 1, 7); this.tableLayoutPanel1.Controls.Add(this.LabelNote, 1, 5); this.tableLayoutPanel1.Controls.Add(this.LabelExpertSetting, 0, 5); this.tableLayoutPanel1.Controls.Add(this.PasswordLabel, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.TCPoverUDPLabel, 0, 6); + this.tableLayoutPanel1.Controls.Add(this.CheckTCPoverUDP, 1, 6); this.tableLayoutPanel1.Location = new System.Drawing.Point(8, 21); this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(0); this.tableLayoutPanel1.Name = "tableLayoutPanel1"; this.tableLayoutPanel1.Padding = new System.Windows.Forms.Padding(3); - this.tableLayoutPanel1.RowCount = 10; + this.tableLayoutPanel1.RowCount = 11; this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); @@ -145,8 +149,8 @@ this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); - this.tableLayoutPanel1.Size = new System.Drawing.Size(304, 270); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.Size = new System.Drawing.Size(304, 294); this.tableLayoutPanel1.TabIndex = 0; // // IPLabel @@ -236,7 +240,7 @@ // this.LabelLink.Anchor = System.Windows.Forms.AnchorStyles.Right; this.LabelLink.AutoSize = true; - this.LabelLink.Location = new System.Drawing.Point(58, 246); + this.LabelLink.Location = new System.Drawing.Point(58, 270); this.LabelLink.Name = "LabelLink"; this.LabelLink.Size = new System.Drawing.Size(28, 14); this.LabelLink.TabIndex = 11; @@ -245,7 +249,7 @@ // TextLink // this.TextLink.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.TextLink.Location = new System.Drawing.Point(92, 242); + this.TextLink.Location = new System.Drawing.Point(92, 266); this.TextLink.MaxLength = 32; this.TextLink.Name = "TextLink"; this.TextLink.Size = new System.Drawing.Size(206, 22); @@ -278,7 +282,7 @@ // this.ObfsUDPLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; this.ObfsUDPLabel.AutoSize = true; - this.ObfsUDPLabel.Location = new System.Drawing.Point(27, 220); + this.ObfsUDPLabel.Location = new System.Drawing.Point(27, 244); this.ObfsUDPLabel.Margin = new System.Windows.Forms.Padding(3, 5, 3, 5); this.ObfsUDPLabel.Name = "ObfsUDPLabel"; this.ObfsUDPLabel.Size = new System.Drawing.Size(59, 14); @@ -288,7 +292,7 @@ // CheckObfsUDP // this.CheckObfsUDP.AutoSize = true; - this.CheckObfsUDP.Location = new System.Drawing.Point(92, 218); + this.CheckObfsUDP.Location = new System.Drawing.Point(92, 242); this.CheckObfsUDP.Name = "CheckObfsUDP"; this.CheckObfsUDP.Size = new System.Drawing.Size(144, 18); this.CheckObfsUDP.TabIndex = 28; @@ -299,7 +303,7 @@ // this.ObfsTCPLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; this.ObfsTCPLabel.AutoSize = true; - this.ObfsTCPLabel.Location = new System.Drawing.Point(28, 196); + this.ObfsTCPLabel.Location = new System.Drawing.Point(28, 220); this.ObfsTCPLabel.Margin = new System.Windows.Forms.Padding(3, 5, 3, 5); this.ObfsTCPLabel.Name = "ObfsTCPLabel"; this.ObfsTCPLabel.Size = new System.Drawing.Size(58, 14); @@ -311,7 +315,7 @@ // this.UDPoverTCPLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; this.UDPoverTCPLabel.AutoSize = true; - this.UDPoverTCPLabel.Location = new System.Drawing.Point(10, 172); + this.UDPoverTCPLabel.Location = new System.Drawing.Point(10, 196); this.UDPoverTCPLabel.Margin = new System.Windows.Forms.Padding(3, 5, 3, 5); this.UDPoverTCPLabel.Name = "UDPoverTCPLabel"; this.UDPoverTCPLabel.Size = new System.Drawing.Size(76, 14); @@ -321,7 +325,7 @@ // CheckObfsTCP // this.CheckObfsTCP.AutoSize = true; - this.CheckObfsTCP.Location = new System.Drawing.Point(92, 194); + this.CheckObfsTCP.Location = new System.Drawing.Point(92, 218); this.CheckObfsTCP.Name = "CheckObfsTCP"; this.CheckObfsTCP.Size = new System.Drawing.Size(144, 18); this.CheckObfsTCP.TabIndex = 27; @@ -332,7 +336,7 @@ // CheckUDPoverUDP // this.CheckUDPoverUDP.AutoSize = true; - this.CheckUDPoverUDP.Location = new System.Drawing.Point(92, 170); + this.CheckUDPoverUDP.Location = new System.Drawing.Point(92, 194); this.CheckUDPoverUDP.Name = "CheckUDPoverUDP"; this.CheckUDPoverUDP.Size = new System.Drawing.Size(187, 18); this.CheckUDPoverUDP.TabIndex = 26; @@ -373,6 +377,27 @@ this.PasswordLabel.UseVisualStyleBackColor = true; this.PasswordLabel.CheckedChanged += new System.EventHandler(this.PasswordLabel_CheckedChanged); // + // TCPoverUDPLabel + // + this.TCPoverUDPLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.TCPoverUDPLabel.AutoSize = true; + this.TCPoverUDPLabel.Location = new System.Drawing.Point(10, 172); + this.TCPoverUDPLabel.Margin = new System.Windows.Forms.Padding(3, 5, 3, 5); + this.TCPoverUDPLabel.Name = "TCPoverUDPLabel"; + this.TCPoverUDPLabel.Size = new System.Drawing.Size(76, 14); + this.TCPoverUDPLabel.TabIndex = 23; + this.TCPoverUDPLabel.Text = "TCPoverUDP"; + // + // CheckTCPoverUDP + // + this.CheckTCPoverUDP.AutoSize = true; + this.CheckTCPoverUDP.Location = new System.Drawing.Point(92, 170); + this.CheckTCPoverUDP.Name = "CheckTCPoverUDP"; + this.CheckTCPoverUDP.Size = new System.Drawing.Size(185, 18); + this.CheckTCPoverUDP.TabIndex = 26; + this.CheckTCPoverUDP.Text = "TCP over TCP if not checked"; + this.CheckTCPoverUDP.UseVisualStyleBackColor = true; + // // panel2 // this.panel2.Anchor = System.Windows.Forms.AnchorStyles.Top; @@ -414,7 +439,7 @@ this.ServerGroupBox.Location = new System.Drawing.Point(218, 0); this.ServerGroupBox.Margin = new System.Windows.Forms.Padding(12, 0, 0, 0); this.ServerGroupBox.Name = "ServerGroupBox"; - this.ServerGroupBox.Size = new System.Drawing.Size(316, 309); + this.ServerGroupBox.Size = new System.Drawing.Size(316, 333); this.ServerGroupBox.TabIndex = 6; this.ServerGroupBox.TabStop = false; this.ServerGroupBox.Text = "Server"; @@ -464,7 +489,7 @@ this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); - this.tableLayoutPanel2.Size = new System.Drawing.Size(740, 487); + this.tableLayoutPanel2.Size = new System.Drawing.Size(740, 511); this.tableLayoutPanel2.TabIndex = 7; // // Socks5ProxyGroup @@ -473,7 +498,7 @@ | System.Windows.Forms.AnchorStyles.Right))); this.Socks5ProxyGroup.AutoSize = true; this.Socks5ProxyGroup.Controls.Add(this.tableLayoutPanel9); - this.Socks5ProxyGroup.Location = new System.Drawing.Point(218, 309); + this.Socks5ProxyGroup.Location = new System.Drawing.Point(218, 333); this.Socks5ProxyGroup.Margin = new System.Windows.Forms.Padding(12, 0, 0, 0); this.Socks5ProxyGroup.Name = "Socks5ProxyGroup"; this.Socks5ProxyGroup.Size = new System.Drawing.Size(316, 178); @@ -603,7 +628,7 @@ this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); - this.tableLayoutPanel7.Size = new System.Drawing.Size(200, 481); + this.tableLayoutPanel7.Size = new System.Drawing.Size(200, 505); this.tableLayoutPanel7.TabIndex = 16; // // CheckAutoBan @@ -611,7 +636,7 @@ this.CheckAutoBan.Anchor = System.Windows.Forms.AnchorStyles.None; this.CheckAutoBan.AutoSize = true; this.tableLayoutPanel7.SetColumnSpan(this.CheckAutoBan, 2); - this.CheckAutoBan.Location = new System.Drawing.Point(63, 449); + this.CheckAutoBan.Location = new System.Drawing.Point(63, 461); this.CheckAutoBan.Name = "CheckAutoBan"; this.CheckAutoBan.Size = new System.Drawing.Size(73, 18); this.CheckAutoBan.TabIndex = 17; @@ -716,14 +741,14 @@ this.tableLayoutPanel8.RowCount = 2; this.tableLayoutPanel8.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel8.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel8.Size = new System.Drawing.Size(200, 303); + this.tableLayoutPanel8.Size = new System.Drawing.Size(200, 327); this.tableLayoutPanel8.TabIndex = 17; // // LinkUpdate // this.LinkUpdate.Anchor = System.Windows.Forms.AnchorStyles.None; this.LinkUpdate.AutoSize = true; - this.LinkUpdate.Location = new System.Drawing.Point(39, 244); + this.LinkUpdate.Location = new System.Drawing.Point(39, 256); this.LinkUpdate.Margin = new System.Windows.Forms.Padding(5); this.LinkUpdate.Name = "LinkUpdate"; this.LinkUpdate.Size = new System.Drawing.Size(122, 14); @@ -740,7 +765,7 @@ this.tableLayoutPanel10.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel10.Controls.Add(this.tableLayoutPanel3, 0, 2); this.tableLayoutPanel10.Controls.Add(this.tableLayoutPanel5, 0, 1); - this.tableLayoutPanel10.Location = new System.Drawing.Point(548, 334); + this.tableLayoutPanel10.Location = new System.Drawing.Point(548, 358); this.tableLayoutPanel10.Name = "tableLayoutPanel10"; this.tableLayoutPanel10.RowCount = 3; this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); @@ -985,6 +1010,8 @@ private System.Windows.Forms.CheckBox CheckSocks5Proxy; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel10; private System.Windows.Forms.CheckBox CheckAutoBan; + private System.Windows.Forms.Label TCPoverUDPLabel; + private System.Windows.Forms.CheckBox CheckTCPoverUDP; } } diff --git a/shadowsocks-csharp/View/ConfigForm.cs b/shadowsocks-csharp/View/ConfigForm.cs index 0b12aa43..d6e273d1 100755 --- a/shadowsocks-csharp/View/ConfigForm.cs +++ b/shadowsocks-csharp/View/ConfigForm.cs @@ -63,10 +63,12 @@ namespace Shadowsocks.View RemarksLabel.Text = I18N.GetString("Remarks"); LabelExpertSetting.Text = I18N.GetString(LabelExpertSetting.Text); + TCPoverUDPLabel.Text = I18N.GetString(TCPoverUDPLabel.Text); UDPoverTCPLabel.Text = I18N.GetString(UDPoverTCPLabel.Text); ObfsTCPLabel.Text = I18N.GetString(ObfsTCPLabel.Text); ObfsUDPLabel.Text = I18N.GetString(ObfsUDPLabel.Text); LabelNote.Text = I18N.GetString(LabelNote.Text); + CheckTCPoverUDP.Text = I18N.GetString(CheckTCPoverUDP.Text); CheckUDPoverUDP.Text = I18N.GetString(CheckUDPoverUDP.Text); CheckObfsTCP.Text = I18N.GetString(CheckObfsTCP.Text); CheckObfsUDP.Text = I18N.GetString(CheckObfsUDP.Text); @@ -124,6 +126,7 @@ namespace Shadowsocks.View password = PasswordTextBox.Text, method = EncryptionSelect.Text, remarks = RemarksTextBox.Text, + tcp_over_udp = CheckTCPoverUDP.Checked, udp_over_tcp = CheckUDPoverUDP.Checked, obfs_tcp = CheckObfsTCP.Checked, obfs_udp = CheckObfsUDP.Checked @@ -204,6 +207,7 @@ namespace Shadowsocks.View ProxyPortTextBox.Text = _modifiedConfiguration.localPort.ToString(); EncryptionSelect.Text = server.method ?? "aes-256-cfb"; RemarksTextBox.Text = server.remarks; + CheckTCPoverUDP.Checked = server.tcp_over_udp; CheckUDPoverUDP.Checked = server.udp_over_tcp; CheckObfsTCP.Checked = server.obfs_tcp; CheckObfsUDP.Checked = server.obfs_udp; diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index 27ad4f52..644e4862 100755 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -84,9 +84,9 @@ namespace Shadowsocks.View ShowConfigForm(); } - //timerDelayCheckUpdate = new System.Timers.Timer(1000 * 10.0); - //timerDelayCheckUpdate.Elapsed += timer_Elapsed; - //timerDelayCheckUpdate.Start(); + timerDelayCheckUpdate = new System.Timers.Timer(1000 * 10.0); + timerDelayCheckUpdate.Elapsed += timer_Elapsed; + timerDelayCheckUpdate.Start(); } private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index be017c8a..6cd1a7db 100755 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -131,6 +131,7 @@ + @@ -149,6 +150,7 @@ True Resources.resx + Form diff --git a/shadowsocks-csharp/shadowsocks-csharp4.0.csproj b/shadowsocks-csharp/shadowsocks-csharp4.0.csproj index 7b35413e..8002393d 100644 --- a/shadowsocks-csharp/shadowsocks-csharp4.0.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp4.0.csproj @@ -131,6 +131,7 @@ + @@ -149,6 +150,7 @@ True Resources.resx + Form