Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60a5572808 | ||
|
|
877644609b | ||
|
|
54335d4889 | ||
|
|
08f12b3b24 | ||
|
|
1c8f4168cf | ||
|
|
43672a8bda |
@@ -1,3 +1,8 @@
|
||||
4.0.1 2017-04-08
|
||||
- Fix UDP relay
|
||||
- Allow to add multiple servers via Shadowsocks URL
|
||||
- Bug fixes and improvements
|
||||
|
||||
4.0 2017-04-04
|
||||
- Add AEAD ciphers support, removed OTA
|
||||
- I18N: add Japanese support, update Traditional Chinese strings
|
||||
|
||||
@@ -7,11 +7,11 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
class PortForwarder : Listener.Service
|
||||
{
|
||||
int _targetPort;
|
||||
private readonly int _targetPort;
|
||||
|
||||
public PortForwarder(int targetPort)
|
||||
{
|
||||
this._targetPort = targetPort;
|
||||
_targetPort = targetPort;
|
||||
}
|
||||
|
||||
public override bool Handle(byte[] firstPacket, int length, Socket socket, object state)
|
||||
@@ -20,11 +20,11 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
return false;
|
||||
}
|
||||
new Handler().Start(firstPacket, length, socket, this._targetPort);
|
||||
new Handler().Start(firstPacket, length, socket, _targetPort);
|
||||
return true;
|
||||
}
|
||||
|
||||
class Handler
|
||||
private class Handler
|
||||
{
|
||||
private byte[] _firstPacket;
|
||||
private int _firstPacketLength;
|
||||
@@ -33,7 +33,7 @@ namespace Shadowsocks.Controller
|
||||
private bool _closed = false;
|
||||
private bool _localShutdown = false;
|
||||
private bool _remoteShutdown = false;
|
||||
public const int RecvSize = 16384;
|
||||
private const int RecvSize = 2048;
|
||||
// remote receive buffer
|
||||
private byte[] remoteRecvBuffer = new byte[RecvSize];
|
||||
// connection receive buffer
|
||||
@@ -44,9 +44,9 @@ namespace Shadowsocks.Controller
|
||||
|
||||
public void Start(byte[] firstPacket, int length, Socket socket, int targetPort)
|
||||
{
|
||||
this._firstPacket = firstPacket;
|
||||
this._firstPacketLength = length;
|
||||
this._local = socket;
|
||||
_firstPacket = firstPacket;
|
||||
_firstPacketLength = length;
|
||||
_local = socket;
|
||||
try
|
||||
{
|
||||
EndPoint remoteEP = SocketUtil.GetEndPoint("127.0.0.1", targetPort);
|
||||
@@ -58,7 +58,7 @@ namespace Shadowsocks.Controller
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
this.Close();
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace Shadowsocks.Controller
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
this.Close();
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,12 +89,12 @@ namespace Shadowsocks.Controller
|
||||
}
|
||||
try
|
||||
{
|
||||
_remote.BeginSend(_firstPacket, 0, _firstPacketLength, 0, new AsyncCallback(StartPipe), null);
|
||||
_remote.BeginSend(_firstPacket, 0, _firstPacketLength, 0, StartPipe, null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
this.Close();
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,14 +108,14 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
_remote.EndSend(ar);
|
||||
_remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0,
|
||||
new AsyncCallback(PipeRemoteReceiveCallback), null);
|
||||
PipeRemoteReceiveCallback, null);
|
||||
_local.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0,
|
||||
new AsyncCallback(PipeConnectionReceiveCallback), null);
|
||||
PipeConnectionReceiveCallback, null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
this.Close();
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,10 +128,9 @@ namespace Shadowsocks.Controller
|
||||
try
|
||||
{
|
||||
int bytesRead = _remote.EndReceive(ar);
|
||||
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
_local.BeginSend(remoteRecvBuffer, 0, bytesRead, 0, new AsyncCallback(PipeConnectionSendCallback), null);
|
||||
_local.BeginSend(remoteRecvBuffer, 0, bytesRead, 0, PipeConnectionSendCallback, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -143,7 +142,7 @@ namespace Shadowsocks.Controller
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
this.Close();
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,10 +155,9 @@ namespace Shadowsocks.Controller
|
||||
try
|
||||
{
|
||||
int bytesRead = _local.EndReceive(ar);
|
||||
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
_remote.BeginSend(connetionRecvBuffer, 0, bytesRead, 0, new AsyncCallback(PipeRemoteSendCallback), null);
|
||||
_remote.BeginSend(connetionRecvBuffer, 0, bytesRead, 0, PipeRemoteSendCallback, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -171,7 +169,7 @@ namespace Shadowsocks.Controller
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
this.Close();
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,13 +182,13 @@ namespace Shadowsocks.Controller
|
||||
try
|
||||
{
|
||||
_remote.EndSend(ar);
|
||||
_local.BeginReceive(this.connetionRecvBuffer, 0, RecvSize, 0,
|
||||
new AsyncCallback(PipeConnectionReceiveCallback), null);
|
||||
_local.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0,
|
||||
PipeConnectionReceiveCallback, null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
this.Close();
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,13 +201,13 @@ namespace Shadowsocks.Controller
|
||||
try
|
||||
{
|
||||
_local.EndSend(ar);
|
||||
_remote.BeginReceive(this.remoteRecvBuffer, 0, RecvSize, 0,
|
||||
new AsyncCallback(PipeRemoteReceiveCallback), null);
|
||||
_remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0,
|
||||
PipeRemoteReceiveCallback, null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
this.Close();
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +215,7 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
if (_localShutdown && _remoteShutdown)
|
||||
{
|
||||
this.Close();
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Shadowsocks.Controller
|
||||
private Socket _remote;
|
||||
|
||||
private Server _server;
|
||||
private byte[] _buffer = new byte[1500];
|
||||
private byte[] _buffer = new byte[65536];
|
||||
|
||||
private IPEndPoint _localEndPoint;
|
||||
private IPEndPoint _remoteEndPoint;
|
||||
@@ -81,7 +81,7 @@ namespace Shadowsocks.Controller
|
||||
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];
|
||||
byte[] dataOut = new byte[65536]; // enough space for AEAD ciphers
|
||||
int outlen;
|
||||
encryptor.EncryptUDP(dataIn, length - 3, dataOut, out outlen);
|
||||
Logging.Debug(_localEndPoint, _remoteEndPoint, outlen, "UDP Relay");
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Shadowsocks.Controller
|
||||
public string LatestVersionLocalName;
|
||||
public event EventHandler CheckUpdateCompleted;
|
||||
|
||||
public const string Version = "4.0";
|
||||
public const string Version = "4.0.1";
|
||||
|
||||
private class CheckUpdateTimer : System.Timers.Timer
|
||||
{
|
||||
|
||||
@@ -163,8 +163,13 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
var server = new Server(ssURL);
|
||||
_config.configs.Add(server);
|
||||
if (ssURL.IsNullOrEmpty() || ssURL.IsWhiteSpace()) return false;
|
||||
var servers = Server.GetServers(ssURL);
|
||||
if (servers == null || servers.Count == 0) return false;
|
||||
foreach (var server in servers)
|
||||
{
|
||||
_config.configs.Add(server);
|
||||
}
|
||||
_config.index = _config.configs.Count - 1;
|
||||
SaveConfig(_config);
|
||||
return true;
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Shadowsocks.Encryption.AEAD
|
||||
private static readonly byte[] InfoBytes = Encoding.ASCII.GetBytes(Info);
|
||||
|
||||
// for UDP only
|
||||
protected static byte[] _udpTmpBuf = new byte[MAX_INPUT_SIZE];
|
||||
protected static byte[] _udpTmpBuf = new byte[65536];
|
||||
|
||||
// every connection should create its own buffer
|
||||
private CircularBuffer<byte> _encCircularBuffer = new CircularBuffer<byte>(MAX_INPUT_SIZE * 2, false);
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Shadowsocks.Encryption.Stream
|
||||
: EncryptorBase
|
||||
{
|
||||
// for UDP only
|
||||
protected static byte[] _udpTmpBuf = new byte[MAX_INPUT_SIZE];
|
||||
protected static byte[] _udpTmpBuf = new byte[65536];
|
||||
|
||||
// every connection should create its own buffer
|
||||
private CircularBuffer<byte> _encCircularBuffer = new CircularBuffer<byte>(TCPHandler.BufferSize * 2, false);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
@@ -10,9 +11,8 @@ namespace Shadowsocks.Model
|
||||
public class Server
|
||||
{
|
||||
public static readonly Regex
|
||||
UrlFinder = new Regex("^(?i)ss://([A-Za-z0-9+-/=_]+)(#(.+))?$", RegexOptions.IgnoreCase),
|
||||
DetailsParser = new Regex("^((?<method>.+?):(?<password>.*)@(?<hostname>.+?)" +
|
||||
":(?<port>\\d+?))$", RegexOptions.IgnoreCase);
|
||||
UrlFinder = new Regex(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase),
|
||||
DetailsParser = new Regex(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase);
|
||||
|
||||
private const int DefaultServerTimeoutSec = 5;
|
||||
public const int MaxServerTimeoutSec = 20;
|
||||
@@ -43,9 +43,10 @@ namespace Shadowsocks.Model
|
||||
}
|
||||
string serverStr;
|
||||
// CheckHostName() won't do a real DNS lookup
|
||||
var hostType = Uri.CheckHostName( server );
|
||||
var hostType = Uri.CheckHostName(server);
|
||||
|
||||
switch ( hostType ) {
|
||||
switch (hostType)
|
||||
{
|
||||
case UriHostNameType.IPv6:
|
||||
serverStr = $"[{server}]:{server_port}";
|
||||
break;
|
||||
@@ -69,20 +70,32 @@ namespace Shadowsocks.Model
|
||||
timeout = DefaultServerTimeoutSec;
|
||||
}
|
||||
|
||||
public Server(string ssURL) : this()
|
||||
public static List<Server> GetServers(string ssURL)
|
||||
{
|
||||
var match = UrlFinder.Match(ssURL);
|
||||
if (!match.Success) throw new FormatException();
|
||||
var base64 = match.Groups[1].Value;
|
||||
var tag = match.Groups[3].Value;
|
||||
if (!tag.IsNullOrEmpty())
|
||||
remarks = HttpUtility.UrlDecode(tag, Encoding.UTF8);
|
||||
match = DetailsParser.Match(Encoding.UTF8.GetString(Convert.FromBase64String(
|
||||
base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '='))));
|
||||
method = match.Groups["method"].Value;
|
||||
password = match.Groups["password"].Value;
|
||||
server = match.Groups["hostname"].Value;
|
||||
server_port = int.Parse(match.Groups["port"].Value);
|
||||
var matches = UrlFinder.Matches(ssURL);
|
||||
if (matches.Count <= 0) return null;
|
||||
List<Server> servers = new List<Server>();
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
Server tmp = new Server();
|
||||
var base64 = match.Groups["base64"].Value;
|
||||
var tag = match.Groups["tag"].Value;
|
||||
if (!tag.IsNullOrEmpty())
|
||||
{
|
||||
tmp.remarks = HttpUtility.UrlDecode(tag, Encoding.UTF8);
|
||||
}
|
||||
Match details = DetailsParser.Match(Encoding.UTF8.GetString(Convert.FromBase64String(
|
||||
base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '='))));
|
||||
if (!details.Success)
|
||||
continue;
|
||||
tmp.method = details.Groups["method"].Value;
|
||||
tmp.password = details.Groups["password"].Value;
|
||||
tmp.server = details.Groups["hostname"].Value;
|
||||
tmp.server_port = int.Parse(details.Groups["port"].Value);
|
||||
|
||||
servers.Add(tmp);
|
||||
}
|
||||
return servers;
|
||||
}
|
||||
|
||||
public string Identifier()
|
||||
|
||||
Reference in New Issue
Block a user