@@ -1,3 +1,6 @@ | |||
2.2.1 2015-01-18 | |||
- Fix QR Code compatibility | |||
2.2 2015-01-14 | |||
- Support updating PAC from GFWList | |||
- Support adding server by scanning QR Code | |||
@@ -20,6 +20,8 @@ a pull request, or ask some of your friends to do so. | |||
3. We don't answer questions of any other types here. Since very few people | |||
are watching the issue tracker here, you'll probably get no help from here. | |||
Read [Troubleshooting] and get help from forums or [mailing lists]. | |||
4. Issues in languages other than English will be Google translated into English | |||
later. | |||
[Troubleshooting]: https://github.com/clowwindy/shadowsocks/wiki/Troubleshooting | |||
@@ -23,11 +23,10 @@ For >= Windows 8, download Shadowsocks-win-dotnet4.0-x.x.x.zip, unless you have | |||
1. Find Shadowsocks icon in notification tray | |||
2. You can add multiple servers in servers menu | |||
3. Select Enable menu to enable system proxy | |||
4. Leave Enable menu unchecked, Shadowsocks will still provide an HTTP proxy at 127.0.0.1:8123 | |||
5. After you saved PAC file with any editor, Shadowsocks will notify browsers | |||
3. Select Enable System Proxy menu to enable system proxy | |||
4. After you saved PAC file with any editor, Shadowsocks will notify browsers | |||
about the change automatically | |||
6. Please disable other proxy addons in your browser, or set them to use | |||
5. Please disable other proxy addons in your browser, or set them to use | |||
system proxy | |||
### Develop | |||
@@ -6,6 +6,7 @@ using System.IO; | |||
using Shadowsocks.Properties; | |||
using SimpleJson; | |||
using Shadowsocks.Util; | |||
using Shadowsocks.Model; | |||
namespace Shadowsocks.Controller | |||
{ | |||
@@ -42,10 +43,10 @@ namespace Shadowsocks.Controller | |||
} | |||
} | |||
public void UpdatePACFromGFWList() | |||
public void UpdatePACFromGFWList(Configuration config) | |||
{ | |||
WebClient http = new WebClient(); | |||
http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), 8123); | |||
http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), config.localPort); | |||
http.DownloadStringCompleted += http_DownloadStringCompleted; | |||
http.DownloadStringAsync(new Uri(GFWLIST_URL)); | |||
} | |||
@@ -0,0 +1,143 @@ | |||
using Shadowsocks.Model; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Net.Sockets; | |||
using System.Text; | |||
namespace Shadowsocks.Controller | |||
{ | |||
public class Listener | |||
{ | |||
public interface Service | |||
{ | |||
bool Handle(byte[] firstPacket, int length, Socket socket); | |||
} | |||
Configuration _config; | |||
bool _shareOverLAN; | |||
Socket _socket; | |||
IList<Service> _services; | |||
public Listener(IList<Service> services) | |||
{ | |||
this._services = services; | |||
} | |||
public void Start(Configuration config) | |||
{ | |||
this._config = config; | |||
this._shareOverLAN = config.shareOverLan; | |||
try | |||
{ | |||
// Create a TCP/IP socket. | |||
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); | |||
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); | |||
IPEndPoint localEndPoint = null; | |||
if (_shareOverLAN) | |||
{ | |||
localEndPoint = new IPEndPoint(IPAddress.Any, _config.localPort); | |||
} | |||
else | |||
{ | |||
localEndPoint = new IPEndPoint(IPAddress.Loopback, _config.localPort); | |||
} | |||
// Bind the socket to the local endpoint and listen for incoming connections. | |||
_socket.Bind(localEndPoint); | |||
_socket.Listen(1024); | |||
// Start an asynchronous socket to listen for connections. | |||
Console.WriteLine("Shadowsocks started"); | |||
_socket.BeginAccept( | |||
new AsyncCallback(AcceptCallback), | |||
_socket); | |||
} | |||
catch (SocketException) | |||
{ | |||
_socket.Close(); | |||
throw; | |||
} | |||
} | |||
public void Stop() | |||
{ | |||
if (_socket != null) | |||
{ | |||
_socket.Close(); | |||
_socket = null; | |||
} | |||
} | |||
public void AcceptCallback(IAsyncResult ar) | |||
{ | |||
Socket listener = (Socket)ar.AsyncState; | |||
try | |||
{ | |||
Socket conn = listener.EndAccept(ar); | |||
byte[] buf = new byte[4096]; | |||
object[] state = new object[] { | |||
conn, | |||
buf | |||
}; | |||
conn.BeginReceive(buf, 0, buf.Length, 0, | |||
new AsyncCallback(ReceiveCallback), state); | |||
} | |||
catch (ObjectDisposedException) | |||
{ | |||
} | |||
catch (Exception e) | |||
{ | |||
Console.WriteLine(e); | |||
} | |||
finally | |||
{ | |||
try | |||
{ | |||
listener.BeginAccept( | |||
new AsyncCallback(AcceptCallback), | |||
listener); | |||
} | |||
catch (ObjectDisposedException) | |||
{ | |||
// do nothing | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.LogUsefulException(e); | |||
} | |||
} | |||
} | |||
private void ReceiveCallback(IAsyncResult ar) | |||
{ | |||
object[] state = (object[])ar.AsyncState; | |||
Socket conn = (Socket)state[0]; | |||
byte[] buf = (byte[])state[1]; | |||
try | |||
{ | |||
int bytesRead = conn.EndReceive(ar); | |||
foreach (Service service in _services) | |||
{ | |||
if (service.Handle(buf, bytesRead, conn)) | |||
{ | |||
return; | |||
} | |||
} | |||
// no service found for this | |||
// shouldn't happen | |||
conn.Close(); | |||
} | |||
catch (Exception e) | |||
{ | |||
Console.WriteLine(e); | |||
conn.Close(); | |||
} | |||
} | |||
} | |||
} |
@@ -9,105 +9,43 @@ using Shadowsocks.Model; | |||
namespace Shadowsocks.Controller | |||
{ | |||
class Local | |||
class Local : Listener.Service | |||
{ | |||
private Server _server; | |||
private bool _shareOverLAN; | |||
//private Encryptor encryptor; | |||
Socket _listener; | |||
private Configuration _config; | |||
public Local(Configuration config) | |||
{ | |||
this._server = config.GetCurrentServer(); | |||
_shareOverLAN = config.shareOverLan; | |||
//this.encryptor = new Encryptor(config.method, config.password); | |||
this._config = config; | |||
} | |||
public void Start() | |||
public bool Handle(byte[] firstPacket, int length, Socket socket) | |||
{ | |||
try | |||
if (length < 2 || firstPacket[0] != 5) | |||
{ | |||
// Create a TCP/IP socket. | |||
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); | |||
_listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); | |||
IPEndPoint localEndPoint = null; | |||
if (_shareOverLAN) | |||
{ | |||
localEndPoint = new IPEndPoint(IPAddress.Any, _server.local_port); | |||
} | |||
else | |||
{ | |||
localEndPoint = new IPEndPoint(IPAddress.Loopback, _server.local_port); | |||
} | |||
// Bind the socket to the local endpoint and listen for incoming connections. | |||
_listener.Bind(localEndPoint); | |||
_listener.Listen(100); | |||
// Start an asynchronous socket to listen for connections. | |||
Console.WriteLine("Shadowsocks started"); | |||
_listener.BeginAccept( | |||
new AsyncCallback(AcceptCallback), | |||
_listener); | |||
} | |||
catch(SocketException) | |||
{ | |||
_listener.Close(); | |||
throw; | |||
return false; | |||
} | |||
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); | |||
Handler handler = new Handler(); | |||
handler.connection = socket; | |||
Server server = _config.GetCurrentServer(); | |||
handler.encryptor = EncryptorFactory.GetEncryptor(server.method, server.password); | |||
handler.server = server; | |||
handler.Start(firstPacket, length); | |||
return true; | |||
} | |||
public void Stop() | |||
{ | |||
_listener.Close(); | |||
} | |||
public void AcceptCallback(IAsyncResult ar) | |||
{ | |||
Socket listener = (Socket)ar.AsyncState; | |||
try | |||
{ | |||
Socket conn = listener.EndAccept(ar); | |||
conn.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); | |||
Handler handler = new Handler(); | |||
handler.connection = conn; | |||
handler.encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password); | |||
handler.config = _server; | |||
handler.Start(); | |||
} | |||
catch | |||
{ | |||
//Console.WriteLine(e.Message); | |||
} | |||
finally | |||
{ | |||
try | |||
{ | |||
listener.BeginAccept( | |||
new AsyncCallback(AcceptCallback), | |||
listener); | |||
} | |||
catch | |||
{ | |||
//Console.WriteLine(e.Message); | |||
} | |||
} | |||
} | |||
} | |||
class Handler | |||
{ | |||
//public Encryptor encryptor; | |||
public IEncryptor encryptor; | |||
public Server config; | |||
public Server server; | |||
// Client socket. | |||
public Socket remote; | |||
public Socket connection; | |||
private byte[] _firstPacket; | |||
private int _firstPacketLength; | |||
// Size of receive buffer. | |||
public const int RecvSize = 16384; | |||
public const int BufferSize = RecvSize + 32; | |||
@@ -128,19 +66,21 @@ namespace Shadowsocks.Controller | |||
private object encryptionLock = new object(); | |||
private object decryptionLock = new object(); | |||
public void Start() | |||
public void Start(byte[] firstPacket, int length) | |||
{ | |||
this._firstPacket = firstPacket; | |||
this._firstPacketLength = length; | |||
try | |||
{ | |||
// TODO async resolving | |||
IPAddress ipAddress; | |||
bool parsed = IPAddress.TryParse(config.server, out ipAddress); | |||
bool parsed = IPAddress.TryParse(server.server, out ipAddress); | |||
if (!parsed) | |||
{ | |||
IPHostEntry ipHostInfo = Dns.GetHostEntry(config.server); | |||
IPHostEntry ipHostInfo = Dns.GetHostEntry(server.server); | |||
ipAddress = ipHostInfo.AddressList[0]; | |||
} | |||
IPEndPoint remoteEP = new IPEndPoint(ipAddress, config.server_port); | |||
IPEndPoint remoteEP = new IPEndPoint(ipAddress, server.server_port); | |||
remote = new Socket(ipAddress.AddressFamily, | |||
@@ -240,33 +180,15 @@ namespace Shadowsocks.Controller | |||
} | |||
try | |||
{ | |||
connection.BeginReceive(connetionRecvBuffer, 0, 256, 0, | |||
new AsyncCallback(HandshakeReceiveCallback), null); | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.LogUsefulException(e); | |||
this.Close(); | |||
} | |||
} | |||
private void HandshakeReceiveCallback(IAsyncResult ar) | |||
{ | |||
if (closed) | |||
{ | |||
return; | |||
} | |||
try | |||
{ | |||
int bytesRead = connection.EndReceive(ar); | |||
int bytesRead = _firstPacketLength; | |||
if (bytesRead > 1) | |||
{ | |||
byte[] response = { 5, 0 }; | |||
if (connetionRecvBuffer[0] != 5) | |||
if (_firstPacket[0] != 5) | |||
{ | |||
// reject socks 4 | |||
response = new byte[]{ 0, 91 }; | |||
response = new byte[] { 0, 91 }; | |||
Console.WriteLine("socks 5 protocol error"); | |||
} | |||
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(HandshakeSendCallback), null); | |||
@@ -12,59 +12,73 @@ using System.Text; | |||
namespace Shadowsocks.Controller | |||
{ | |||
class PACServer | |||
class PACServer : Listener.Service | |||
{ | |||
private static int PORT = 8093; | |||
public static string PAC_FILE = "pac.txt"; | |||
private static Configuration config; | |||
Socket _listener; | |||
FileSystemWatcher watcher; | |||
private Configuration _config; | |||
public event EventHandler PACFileChanged; | |||
public void Start(Configuration configuration) | |||
public PACServer() | |||
{ | |||
this.WatchPacFile(); | |||
} | |||
public void UpdateConfiguration(Configuration config) | |||
{ | |||
this._config = config; | |||
} | |||
public bool Handle(byte[] firstPacket, int length, Socket socket) | |||
{ | |||
try | |||
{ | |||
config = configuration; | |||
// Create a TCP/IP socket. | |||
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); | |||
_listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); | |||
IPEndPoint localEndPoint = null; | |||
if (configuration.shareOverLan) | |||
string request = Encoding.UTF8.GetString(firstPacket, 0, length); | |||
string[] lines = request.Split('\r', '\n'); | |||
bool hostMatch = false, pathMatch = false, useSocks = false; | |||
foreach (string line in lines) | |||
{ | |||
localEndPoint = new IPEndPoint(IPAddress.Any, PORT); | |||
string[] kv = line.Split(new char[]{':'}, 2); | |||
if (kv.Length == 2) | |||
{ | |||
if (kv[0] == "Host") | |||
{ | |||
if (kv[1].Trim() == ((IPEndPoint)socket.LocalEndPoint).ToString()) | |||
{ | |||
hostMatch = true; | |||
} | |||
} | |||
else if (kv[0] == "User-Agent") | |||
{ | |||
if (kv[1].IndexOf("Chrome") >= 0) | |||
{ | |||
useSocks = true; | |||
} | |||
} | |||
} | |||
else if (kv.Length == 1) | |||
{ | |||
if (line.IndexOf("pac") >= 0) | |||
{ | |||
pathMatch = true; | |||
} | |||
} | |||
} | |||
else | |||
if (hostMatch && pathMatch) | |||
{ | |||
localEndPoint = new IPEndPoint(IPAddress.Loopback, PORT); | |||
SendResponse(firstPacket, length, socket, useSocks); | |||
return true; | |||
} | |||
// Bind the socket to the local endpoint and listen for incoming connections. | |||
_listener.Bind(localEndPoint); | |||
_listener.Listen(100); | |||
_listener.BeginAccept( | |||
new AsyncCallback(AcceptCallback), | |||
_listener); | |||
WatchPacFile(); | |||
return false; | |||
} | |||
catch (SocketException) | |||
catch (ArgumentException) | |||
{ | |||
_listener.Close(); | |||
throw; | |||
return false; | |||
} | |||
} | |||
public void Stop() | |||
{ | |||
if (_listener != null) | |||
{ | |||
_listener.Close(); | |||
_listener = null; | |||
} | |||
} | |||
public string TouchPACFile() | |||
{ | |||
@@ -79,50 +93,6 @@ namespace Shadowsocks.Controller | |||
} | |||
} | |||
// we don't even use it | |||
static byte[] requestBuf = new byte[2048]; | |||
public void AcceptCallback(IAsyncResult ar) | |||
{ | |||
Socket listener = (Socket)ar.AsyncState; | |||
try | |||
{ | |||
Socket conn = listener.EndAccept(ar); | |||
object[] state = new object[] { | |||
conn, | |||
requestBuf | |||
}; | |||
conn.BeginReceive(requestBuf, 0, requestBuf.Length, 0, | |||
new AsyncCallback(ReceiveCallback), state); | |||
} | |||
catch (ObjectDisposedException) | |||
{ | |||
} | |||
catch (Exception e) | |||
{ | |||
Console.WriteLine(e); | |||
} | |||
finally | |||
{ | |||
try | |||
{ | |||
listener.BeginAccept( | |||
new AsyncCallback(AcceptCallback), | |||
listener); | |||
} | |||
catch (ObjectDisposedException) | |||
{ | |||
// do nothing | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.LogUsefulException(e); | |||
} | |||
} | |||
} | |||
private string GetPACContent() | |||
{ | |||
if (File.Exists(PAC_FILE)) | |||
@@ -135,46 +105,33 @@ namespace Shadowsocks.Controller | |||
} | |||
} | |||
private void ReceiveCallback(IAsyncResult ar) | |||
public void SendResponse(byte[] firstPacket, int length, Socket socket, bool useSocks) | |||
{ | |||
object[] state = (object[])ar.AsyncState; | |||
Socket conn = (Socket)state[0]; | |||
byte[] requestBuf = (byte[])state[1]; | |||
try | |||
{ | |||
int bytesRead = conn.EndReceive(ar); | |||
string pac = GetPACContent(); | |||
IPEndPoint localEndPoint = (IPEndPoint)conn.LocalEndPoint; | |||
IPEndPoint localEndPoint = (IPEndPoint)socket.LocalEndPoint; | |||
string proxy = GetPACAddress(requestBuf, localEndPoint); | |||
string proxy = GetPACAddress(firstPacket, length, localEndPoint, useSocks); | |||
pac = pac.Replace("__PROXY__", proxy); | |||
if (bytesRead > 0) | |||
{ | |||
string text = String.Format(@"HTTP/1.1 200 OK | |||
string text = String.Format(@"HTTP/1.1 200 OK | |||
Server: Shadowsocks | |||
Content-Type: application/x-ns-proxy-autoconfig | |||
Content-Length: {0} | |||
Connection: Close | |||
", System.Text.Encoding.UTF8.GetBytes(pac).Length) + pac; | |||
byte[] response = System.Text.Encoding.UTF8.GetBytes(text); | |||
conn.BeginSend(response, 0, response.Length, 0, new AsyncCallback(SendCallback), conn); | |||
Util.Utils.ReleaseMemory(); | |||
} | |||
else | |||
{ | |||
conn.Close(); | |||
} | |||
byte[] response = System.Text.Encoding.UTF8.GetBytes(text); | |||
socket.BeginSend(response, 0, response.Length, 0, new AsyncCallback(SendCallback), socket); | |||
Util.Utils.ReleaseMemory(); | |||
} | |||
catch (Exception e) | |||
{ | |||
Console.WriteLine(e); | |||
conn.Close(); | |||
socket.Close(); | |||
} | |||
} | |||
@@ -213,9 +170,8 @@ Connection: Close | |||
} | |||
} | |||
private string GetPACAddress(byte[] requestBuf, IPEndPoint localEndPoint) | |||
private string GetPACAddress(byte[] requestBuf, int length, IPEndPoint localEndPoint, bool useSocks) | |||
{ | |||
string proxy = "PROXY " + localEndPoint.Address + ":8123;"; | |||
//try | |||
//{ | |||
// string requestString = Encoding.UTF8.GetString(requestBuf); | |||
@@ -229,7 +185,7 @@ Connection: Close | |||
//{ | |||
// Console.WriteLine(e); | |||
//} | |||
return proxy; | |||
return (useSocks ? "SOCKS5 " : "PROXY ") + localEndPoint.Address + ":" + this._config.localPort + ";"; | |||
} | |||
} | |||
} |
@@ -6,6 +6,8 @@ using System.Diagnostics; | |||
using System.IO; | |||
using System.IO.Compression; | |||
using System.Text; | |||
using System.Net.NetworkInformation; | |||
using System.Net; | |||
namespace Shadowsocks.Controller | |||
{ | |||
@@ -13,6 +15,7 @@ namespace Shadowsocks.Controller | |||
{ | |||
private Process _process; | |||
private static string temppath; | |||
private int _runningPort; | |||
static PolipoRunner() | |||
{ | |||
@@ -27,6 +30,14 @@ namespace Shadowsocks.Controller | |||
} | |||
} | |||
public int RunningPort | |||
{ | |||
get | |||
{ | |||
return _runningPort; | |||
} | |||
} | |||
public void Start(Configuration configuration) | |||
{ | |||
Server server = configuration.GetCurrentServer(); | |||
@@ -45,8 +56,10 @@ namespace Shadowsocks.Controller | |||
Console.WriteLine(e.ToString()); | |||
} | |||
} | |||
string polipoConfig = Resources.polipo_config; | |||
polipoConfig = polipoConfig.Replace("__SOCKS_PORT__", server.local_port.ToString()); | |||
string polipoConfig = Resources.polipo_config; | |||
_runningPort = this.GetFreePort(); | |||
polipoConfig = polipoConfig.Replace("__SOCKS_PORT__", configuration.localPort.ToString()); | |||
polipoConfig = polipoConfig.Replace("__POLIPO_BIND_PORT__", _runningPort.ToString()); | |||
polipoConfig = polipoConfig.Replace("__POLIPO_BIND_IP__", configuration.shareOverLan ? "0.0.0.0" : "127.0.0.1"); | |||
FileManager.ByteArrayToFile(temppath + "/polipo.conf", System.Text.Encoding.UTF8.GetBytes(polipoConfig)); | |||
@@ -79,5 +92,35 @@ namespace Shadowsocks.Controller | |||
_process = null; | |||
} | |||
} | |||
private int GetFreePort() | |||
{ | |||
int defaultPort = 8123; | |||
try | |||
{ | |||
IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties(); | |||
IPEndPoint[] tcpEndPoints = properties.GetActiveTcpListeners(); | |||
List<int> usedPorts = new List<int>(); | |||
foreach (IPEndPoint endPoint in IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners()) | |||
{ | |||
usedPorts.Add(endPoint.Port); | |||
} | |||
for (int port = defaultPort; port <= 65535; port++) | |||
{ | |||
if (!usedPorts.Contains(port)) | |||
{ | |||
return port; | |||
} | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
// in case access denied | |||
Logging.LogUsefulException(e); | |||
return defaultPort; | |||
} | |||
throw new Exception("No free port found."); | |||
} | |||
} | |||
} |
@@ -0,0 +1,264 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Net.Sockets; | |||
using System.Text; | |||
namespace Shadowsocks.Controller | |||
{ | |||
class PortForwarder : Listener.Service | |||
{ | |||
int _targetPort; | |||
public PortForwarder(int targetPort) | |||
{ | |||
this._targetPort = targetPort; | |||
} | |||
public bool Handle(byte[] firstPacket, int length, Socket socket) | |||
{ | |||
new Handler().Start(firstPacket, length, socket, this._targetPort); | |||
return true; | |||
} | |||
class Handler | |||
{ | |||
private byte[] _firstPacket; | |||
private int _firstPacketLength; | |||
private Socket _local; | |||
private Socket _remote; | |||
private bool _closed = false; | |||
private bool _localShutdown = false; | |||
private bool _remoteShutdown = false; | |||
public const int RecvSize = 16384; | |||
// remote receive buffer | |||
private byte[] remoteRecvBuffer = new byte[RecvSize]; | |||
// connection receive buffer | |||
private byte[] connetionRecvBuffer = new byte[RecvSize]; | |||
public void Start(byte[] firstPacket, int length, Socket socket, int targetPort) | |||
{ | |||
this._firstPacket = firstPacket; | |||
this._firstPacketLength = length; | |||
this._local = socket; | |||
try | |||
{ | |||
// TODO async resolving | |||
IPAddress ipAddress; | |||
bool parsed = IPAddress.TryParse("127.0.0.1", out ipAddress); | |||
IPEndPoint remoteEP = new IPEndPoint(ipAddress, targetPort); | |||
_remote = new Socket(ipAddress.AddressFamily, | |||
SocketType.Stream, ProtocolType.Tcp); | |||
_remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); | |||
// Connect to the remote endpoint. | |||
_remote.BeginConnect(remoteEP, | |||
new AsyncCallback(ConnectCallback), null); | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.LogUsefulException(e); | |||
this.Close(); | |||
} | |||
} | |||
private void ConnectCallback(IAsyncResult ar) | |||
{ | |||
if (_closed) | |||
{ | |||
return; | |||
} | |||
try | |||
{ | |||
_remote.EndConnect(ar); | |||
HandshakeReceive(); | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.LogUsefulException(e); | |||
this.Close(); | |||
} | |||
} | |||
private void HandshakeReceive() | |||
{ | |||
if (_closed) | |||
{ | |||
return; | |||
} | |||
try | |||
{ | |||
_remote.BeginSend(_firstPacket, 0, _firstPacketLength, 0, new AsyncCallback(StartPipe), null); | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.LogUsefulException(e); | |||
this.Close(); | |||
} | |||
} | |||
private void StartPipe(IAsyncResult ar) | |||
{ | |||
if (_closed) | |||
{ | |||
return; | |||
} | |||
try | |||
{ | |||
_remote.EndSend(ar); | |||
_remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0, | |||
new AsyncCallback(PipeRemoteReceiveCallback), null); | |||
_local.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, | |||
new AsyncCallback(PipeConnectionReceiveCallback), null); | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.LogUsefulException(e); | |||
this.Close(); | |||
} | |||
} | |||
private void PipeRemoteReceiveCallback(IAsyncResult ar) | |||
{ | |||
if (_closed) | |||
{ | |||
return; | |||
} | |||
try | |||
{ | |||
int bytesRead = _remote.EndReceive(ar); | |||
if (bytesRead > 0) | |||
{ | |||
_local.BeginSend(remoteRecvBuffer, 0, bytesRead, 0, new AsyncCallback(PipeConnectionSendCallback), null); | |||
} | |||
else | |||
{ | |||
//Console.WriteLine("bytesRead: " + bytesRead.ToString()); | |||
_local.Shutdown(SocketShutdown.Send); | |||
_localShutdown = true; | |||
CheckClose(); | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.LogUsefulException(e); | |||
this.Close(); | |||
} | |||
} | |||
private void PipeConnectionReceiveCallback(IAsyncResult ar) | |||
{ | |||
if (_closed) | |||
{ | |||
return; | |||
} | |||
try | |||
{ | |||
int bytesRead = _local.EndReceive(ar); | |||
if (bytesRead > 0) | |||
{ | |||
_remote.BeginSend(connetionRecvBuffer, 0, bytesRead, 0, new AsyncCallback(PipeRemoteSendCallback), null); | |||
} | |||
else | |||
{ | |||
_remote.Shutdown(SocketShutdown.Send); | |||
_remoteShutdown = true; | |||
CheckClose(); | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.LogUsefulException(e); | |||
this.Close(); | |||
} | |||
} | |||
private void PipeRemoteSendCallback(IAsyncResult ar) | |||
{ | |||
if (_closed) | |||
{ | |||
return; | |||
} | |||
try | |||
{ | |||
_remote.EndSend(ar); | |||
_local.BeginReceive(this.connetionRecvBuffer, 0, RecvSize, 0, | |||
new AsyncCallback(PipeConnectionReceiveCallback), null); | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.LogUsefulException(e); | |||
this.Close(); | |||
} | |||
} | |||
private void PipeConnectionSendCallback(IAsyncResult ar) | |||
{ | |||
if (_closed) | |||
{ | |||
return; | |||
} | |||
try | |||
{ | |||
_local.EndSend(ar); | |||
_remote.BeginReceive(this.remoteRecvBuffer, 0, RecvSize, 0, | |||
new AsyncCallback(PipeRemoteReceiveCallback), null); | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.LogUsefulException(e); | |||
this.Close(); | |||
} | |||
} | |||
private void CheckClose() | |||
{ | |||
if (_localShutdown && _remoteShutdown) | |||
{ | |||
this.Close(); | |||
} | |||
} | |||
public void Close() | |||
{ | |||
lock (this) | |||
{ | |||
if (_closed) | |||
{ | |||
return; | |||
} | |||
_closed = true; | |||
} | |||
if (_local != null) | |||
{ | |||
try | |||
{ | |||
_local.Shutdown(SocketShutdown.Both); | |||
_local.Close(); | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.LogUsefulException(e); | |||
} | |||
} | |||
if (_remote != null) | |||
{ | |||
try | |||
{ | |||
_remote.Shutdown(SocketShutdown.Both); | |||
_remote.Close(); | |||
} | |||
catch (SocketException e) | |||
{ | |||
Logging.LogUsefulException(e); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -17,8 +17,8 @@ namespace Shadowsocks.Controller | |||
private Thread _ramThread; | |||
private Local local; | |||
private PACServer pacServer; | |||
private Listener _listener; | |||
private PACServer _pacServer; | |||
private Configuration _config; | |||
private PolipoRunner polipoRunner; | |||
private GFWListUpdater gfwListUpdater; | |||
@@ -74,9 +74,10 @@ namespace Shadowsocks.Controller | |||
return Configuration.Load(); | |||
} | |||
public void SaveServers(List<Server> servers) | |||
public void SaveServers(List<Server> servers, int localPort) | |||
{ | |||
_config.configs = servers; | |||
_config.localPort = localPort; | |||
SaveConfig(_config); | |||
} | |||
@@ -142,9 +143,9 @@ namespace Shadowsocks.Controller | |||
return; | |||
} | |||
stopped = true; | |||
if (local != null) | |||
if (_listener != null) | |||
{ | |||
local.Stop(); | |||
_listener.Stop(); | |||
} | |||
if (polipoRunner != null) | |||
{ | |||
@@ -152,13 +153,13 @@ namespace Shadowsocks.Controller | |||
} | |||
if (_config.enabled) | |||
{ | |||
SystemProxy.Disable(); | |||
SystemProxy.Update(_config, true); | |||
} | |||
} | |||
public void TouchPACFile() | |||
{ | |||
string pacFilename = pacServer.TouchPACFile(); | |||
string pacFilename = _pacServer.TouchPACFile(); | |||
if (PACFileReadyToOpen != null) | |||
{ | |||
PACFileReadyToOpen(this, new PathEventArgs() { Path = pacFilename }); | |||
@@ -177,7 +178,7 @@ namespace Shadowsocks.Controller | |||
{ | |||
if (gfwListUpdater != null) | |||
{ | |||
gfwListUpdater.UpdatePACFromGFWList(); | |||
gfwListUpdater.UpdatePACFromGFWList(_config); | |||
} | |||
} | |||
@@ -190,11 +191,12 @@ namespace Shadowsocks.Controller | |||
{ | |||
polipoRunner = new PolipoRunner(); | |||
} | |||
if (pacServer == null) | |||
if (_pacServer == null) | |||
{ | |||
pacServer = new PACServer(); | |||
pacServer.PACFileChanged += pacServer_PACFileChanged; | |||
_pacServer = new PACServer(); | |||
_pacServer.PACFileChanged += pacServer_PACFileChanged; | |||
} | |||
_pacServer.UpdateConfiguration(_config); | |||
if (gfwListUpdater == null) | |||
{ | |||
gfwListUpdater = new GFWListUpdater(); | |||
@@ -202,11 +204,9 @@ namespace Shadowsocks.Controller | |||
gfwListUpdater.Error += pacServer_PACUpdateError; | |||
} | |||
pacServer.Stop(); | |||
if (local != null) | |||
if (_listener != null) | |||
{ | |||
local.Stop(); | |||
_listener.Stop(); | |||
} | |||
// don't put polipoRunner.Start() before pacServer.Stop() | |||
@@ -218,9 +218,13 @@ namespace Shadowsocks.Controller | |||
{ | |||
polipoRunner.Start(_config); | |||
local = new Local(_config); | |||
local.Start(); | |||
pacServer.Start(_config); | |||
Local local = new Local(_config); | |||
List<Listener.Service> services = new List<Listener.Service>(); | |||
services.Add(local); | |||
services.Add(_pacServer); | |||
services.Add(new PortForwarder(polipoRunner.RunningPort)); | |||
_listener = new Listener(services); | |||
_listener.Start(_config); | |||
} | |||
catch (Exception e) | |||
{ | |||
@@ -259,7 +263,7 @@ namespace Shadowsocks.Controller | |||
{ | |||
if (_config.enabled) | |||
{ | |||
SystemProxy.Enable(_config.global); | |||
SystemProxy.Update(_config, false); | |||
_systemProxyIsDirty = true; | |||
} | |||
else | |||
@@ -267,7 +271,7 @@ namespace Shadowsocks.Controller | |||
// only switch it off if we have switched it on | |||
if (_systemProxyIsDirty) | |||
{ | |||
SystemProxy.Disable(); | |||
SystemProxy.Update(_config, false); | |||
_systemProxyIsDirty = false; | |||
} | |||
} | |||
@@ -5,6 +5,7 @@ using System.Collections.Generic; | |||
using System.Runtime.InteropServices; | |||
using System.Text; | |||
using System.IO; | |||
using Shadowsocks.Model; | |||
namespace Shadowsocks.Controller | |||
{ | |||
@@ -25,24 +26,39 @@ namespace Shadowsocks.Controller | |||
_refreshReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0); | |||
} | |||
public static void Enable(bool global) | |||
public static void Update(Configuration config, bool forceDisable) | |||
{ | |||
bool global = config.global; | |||
bool enabled = config.enabled; | |||
if (forceDisable) | |||
{ | |||
enabled = false; | |||
} | |||
try | |||
{ | |||
RegistryKey registry = | |||
Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", | |||
true); | |||
if (global) | |||
if (enabled) | |||
{ | |||
registry.SetValue("ProxyEnable", 1); | |||
registry.SetValue("ProxyServer", "127.0.0.1:8123"); | |||
registry.SetValue("AutoConfigURL", ""); | |||
if (global) | |||
{ | |||
registry.SetValue("ProxyEnable", 1); | |||
registry.SetValue("ProxyServer", "127.0.0.1:" + config.localPort.ToString()); | |||
registry.SetValue("AutoConfigURL", ""); | |||
} | |||
else | |||
{ | |||
registry.SetValue("ProxyEnable", 0); | |||
registry.SetValue("ProxyServer", ""); | |||
registry.SetValue("AutoConfigURL", "http://127.0.0.1:" + config.localPort.ToString() + "/pac?t=" + GetTimestamp(DateTime.Now)); | |||
} | |||
} | |||
else | |||
{ | |||
registry.SetValue("ProxyEnable", 0); | |||
registry.SetValue("ProxyServer", ""); | |||
registry.SetValue("AutoConfigURL", "http://127.0.0.1:8093/pac?t=" + GetTimestamp(DateTime.Now)); | |||
registry.SetValue("AutoConfigURL", ""); | |||
} | |||
SystemProxy.NotifyIE(); | |||
//Must Notify IE first, or the connections do not chanage | |||
@@ -56,27 +72,6 @@ namespace Shadowsocks.Controller | |||
} | |||
} | |||
public static void Disable() | |||
{ | |||
try | |||
{ | |||
RegistryKey registry = | |||
Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", | |||
true); | |||
registry.SetValue("ProxyEnable", 0); | |||
registry.SetValue("ProxyServer", ""); | |||
registry.SetValue("AutoConfigURL", ""); | |||
SystemProxy.NotifyIE(); | |||
CopyProxySettingFromLan(); | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.LogUsefulException(e); | |||
// TODO this should be moved into views | |||
MessageBox.Show(I18N.GetString("Failed to update registry")); | |||
} | |||
} | |||
private static void CopyProxySettingFromLan() | |||
{ | |||
RegistryKey registry = | |||
@@ -1,4 +1,5 @@ | |||
using System; | |||
using Shadowsocks.Model; | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
@@ -17,13 +18,13 @@ namespace Shadowsocks.Controller | |||
public string LatestVersionURL; | |||
public event EventHandler NewVersionFound; | |||
public const string Version = "2.2"; | |||
public const string Version = "2.3"; | |||
public void CheckUpdate() | |||
public void CheckUpdate(Configuration config) | |||
{ | |||
// TODO test failures | |||
WebClient http = new WebClient(); | |||
http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), 8123); | |||
http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), config.localPort); | |||
http.DownloadStringCompleted += http_DownloadStringCompleted; | |||
http.DownloadStringAsync(new Uri(UpdateURL)); | |||
} | |||
@@ -74,6 +75,10 @@ namespace Shadowsocks.Controller | |||
private bool IsNewVersion(string url) | |||
{ | |||
if (url.IndexOf("prerelease") >= 0) | |||
{ | |||
return false; | |||
} | |||
// check dotnet 4.0 | |||
AssemblyName[] references = Assembly.GetExecutingAssembly().GetReferencedAssemblies(); | |||
Version dotNetVersion = Environment.Version; | |||
@@ -1,5 +1,5 @@ | |||
Shadowsocks=Shadowsocks | |||
Enable=启用代理 | |||
Enable System Proxy=启用系统代理 | |||
Mode=代理模式 | |||
PAC=PAC 模式 | |||
Global=全局模式 | |||
@@ -1,4 +1,5 @@ | |||
proxyAddress = "__POLIPO_BIND_IP__" | |||
proxyAddress = "__POLIPO_BIND_IP__" | |||
proxyPort = 8123 | |||
socksParentProxy = "127.0.0.1:__SOCKS_PORT__" | |||
socksProxyType = socks5 | |||
@@ -16,6 +16,7 @@ namespace Shadowsocks.Model | |||
public bool enabled; | |||
public bool shareOverLan; | |||
public bool isDefault; | |||
public int localPort; | |||
private static string CONFIG_FILE = "gui-config.json"; | |||
@@ -33,7 +34,6 @@ namespace Shadowsocks.Model | |||
public static void CheckServer(Server server) | |||
{ | |||
CheckPort(server.local_port); | |||
CheckPort(server.server_port); | |||
CheckPassword(server.password); | |||
CheckServer(server.server); | |||
@@ -46,6 +46,10 @@ namespace Shadowsocks.Model | |||
string configContent = File.ReadAllText(CONFIG_FILE); | |||
Configuration config = SimpleJson.SimpleJson.DeserializeObject<Configuration>(configContent, new JsonSerializerStrategy()); | |||
config.isDefault = false; | |||
if (config.localPort == 0) | |||
{ | |||
config.localPort = 1080; | |||
} | |||
return config; | |||
} | |||
catch (Exception e) | |||
@@ -58,6 +62,7 @@ namespace Shadowsocks.Model | |||
{ | |||
index = 0, | |||
isDefault = true, | |||
localPort = 1080, | |||
configs = new List<Server>() | |||
{ | |||
GetDefaultServer() | |||
@@ -105,7 +110,7 @@ namespace Shadowsocks.Model | |||
} | |||
} | |||
private static void CheckPort(int port) | |||
public static void CheckPort(int port) | |||
{ | |||
if (port <= 0 || port > 65535) | |||
{ | |||
@@ -1,4 +1,4 @@ | |||
using System; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using System.IO; | |||
@@ -14,7 +14,6 @@ namespace Shadowsocks.Model | |||
{ | |||
public string server; | |||
public int server_port; | |||
public int local_port; | |||
public string password; | |||
public string method; | |||
public string remarks; | |||
@@ -39,7 +38,6 @@ namespace Shadowsocks.Model | |||
{ | |||
this.server = ""; | |||
this.server_port = 8388; | |||
this.local_port = 1080; | |||
this.method = "aes-256-cfb"; | |||
this.password = ""; | |||
this.remarks = ""; | |||
@@ -50,7 +48,8 @@ namespace Shadowsocks.Model | |||
string[] r1 = Regex.Split(ssURL, "ss://", RegexOptions.IgnoreCase); | |||
string base64 = r1[1].ToString(); | |||
byte[] bytes = null; | |||
for (var i = 0; i < 3; i++) { | |||
for (var i = 0; i < 3; i++) | |||
{ | |||
try | |||
{ | |||
bytes = System.Convert.FromBase64String(base64); | |||
@@ -64,11 +63,25 @@ namespace Shadowsocks.Model | |||
{ | |||
throw new FormatException(); | |||
} | |||
string[] parts = Encoding.UTF8.GetString(bytes).Split(new char[2] { ':', '@' }); | |||
this.method = parts[0].ToString(); | |||
this.password = parts[1].ToString(); | |||
this.server = parts[2].ToString(); | |||
this.server_port = int.Parse(parts[3].ToString()); | |||
try | |||
{ | |||
string data = Encoding.UTF8.GetString(bytes); | |||
int indexLastAt = data.LastIndexOf('@'); | |||
string afterAt = data.Substring(indexLastAt + 1); | |||
int indexLastColon = afterAt.LastIndexOf(':'); | |||
this.server_port = int.Parse(afterAt.Substring(indexLastColon + 1)); | |||
this.server = afterAt.Substring(0, indexLastColon); | |||
string beforeAt = data.Substring(0, indexLastAt); | |||
string[] parts = beforeAt.Split(new[] { ':' }); | |||
this.method = parts[0]; | |||
this.password = parts[1]; | |||
} | |||
catch (IndexOutOfRangeException) | |||
{ | |||
throw new FormatException(); | |||
} | |||
} | |||
} | |||
} |
@@ -33,8 +33,6 @@ | |||
this.RemarksLabel = new System.Windows.Forms.Label(); | |||
this.IPLabel = new System.Windows.Forms.Label(); | |||
this.ServerPortLabel = new System.Windows.Forms.Label(); | |||
this.ProxyPortTextBox = new System.Windows.Forms.TextBox(); | |||
this.ProxyPortLabel = new System.Windows.Forms.Label(); | |||
this.PasswordLabel = new System.Windows.Forms.Label(); | |||
this.IPTextBox = new System.Windows.Forms.TextBox(); | |||
this.ServerPortTextBox = new System.Windows.Forms.TextBox(); | |||
@@ -49,11 +47,15 @@ | |||
this.ServerGroupBox = new System.Windows.Forms.GroupBox(); | |||
this.ServersListBox = new System.Windows.Forms.ListBox(); | |||
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); | |||
this.tableLayoutPanel5 = new System.Windows.Forms.TableLayoutPanel(); | |||
this.ProxyPortTextBox = new System.Windows.Forms.TextBox(); | |||
this.ProxyPortLabel = new System.Windows.Forms.Label(); | |||
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); | |||
this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); | |||
this.tableLayoutPanel1.SuspendLayout(); | |||
this.ServerGroupBox.SuspendLayout(); | |||
this.tableLayoutPanel2.SuspendLayout(); | |||
this.tableLayoutPanel5.SuspendLayout(); | |||
this.tableLayoutPanel3.SuspendLayout(); | |||
this.tableLayoutPanel4.SuspendLayout(); | |||
this.SuspendLayout(); | |||
@@ -69,8 +71,6 @@ | |||
this.tableLayoutPanel1.Controls.Add(this.RemarksLabel, 0, 5); | |||
this.tableLayoutPanel1.Controls.Add(this.IPLabel, 0, 0); | |||
this.tableLayoutPanel1.Controls.Add(this.ServerPortLabel, 0, 1); | |||
this.tableLayoutPanel1.Controls.Add(this.ProxyPortTextBox, 1, 4); | |||
this.tableLayoutPanel1.Controls.Add(this.ProxyPortLabel, 0, 4); | |||
this.tableLayoutPanel1.Controls.Add(this.PasswordLabel, 0, 2); | |||
this.tableLayoutPanel1.Controls.Add(this.IPTextBox, 1, 0); | |||
this.tableLayoutPanel1.Controls.Add(this.ServerPortTextBox, 1, 1); | |||
@@ -88,13 +88,13 @@ | |||
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.Size = new System.Drawing.Size(238, 163); | |||
this.tableLayoutPanel1.Size = new System.Drawing.Size(238, 137); | |||
this.tableLayoutPanel1.TabIndex = 0; | |||
// | |||
// RemarksTextBox | |||
// | |||
this.RemarksTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); | |||
this.RemarksTextBox.Location = new System.Drawing.Point(72, 137); | |||
this.RemarksTextBox.Location = new System.Drawing.Point(72, 111); | |||
this.RemarksTextBox.MaxLength = 32; | |||
this.RemarksTextBox.Name = "RemarksTextBox"; | |||
this.RemarksTextBox.Size = new System.Drawing.Size(160, 20); | |||
@@ -105,7 +105,7 @@ | |||
// | |||
this.RemarksLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.RemarksLabel.AutoSize = true; | |||
this.RemarksLabel.Location = new System.Drawing.Point(17, 140); | |||
this.RemarksLabel.Location = new System.Drawing.Point(17, 114); | |||
this.RemarksLabel.Name = "RemarksLabel"; | |||
this.RemarksLabel.Size = new System.Drawing.Size(49, 13); | |||
this.RemarksLabel.TabIndex = 9; | |||
@@ -131,26 +131,6 @@ | |||
this.ServerPortLabel.TabIndex = 1; | |||
this.ServerPortLabel.Text = "Server Port"; | |||
// | |||
// ProxyPortTextBox | |||
// | |||
this.ProxyPortTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); | |||
this.ProxyPortTextBox.Location = new System.Drawing.Point(72, 111); | |||
this.ProxyPortTextBox.MaxLength = 10; | |||
this.ProxyPortTextBox.Name = "ProxyPortTextBox"; | |||
this.ProxyPortTextBox.Size = new System.Drawing.Size(160, 20); | |||
this.ProxyPortTextBox.TabIndex = 4; | |||
this.ProxyPortTextBox.WordWrap = false; | |||
// | |||
// ProxyPortLabel | |||
// | |||
this.ProxyPortLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.ProxyPortLabel.AutoSize = true; | |||
this.ProxyPortLabel.Location = new System.Drawing.Point(11, 114); | |||
this.ProxyPortLabel.Name = "ProxyPortLabel"; | |||
this.ProxyPortLabel.Size = new System.Drawing.Size(55, 13); | |||
this.ProxyPortLabel.TabIndex = 3; | |||
this.ProxyPortLabel.Text = "Proxy Port"; | |||
// | |||
// PasswordLabel | |||
// | |||
this.PasswordLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
@@ -292,7 +272,7 @@ | |||
this.ServerGroupBox.Location = new System.Drawing.Point(178, 0); | |||
this.ServerGroupBox.Margin = new System.Windows.Forms.Padding(12, 0, 0, 0); | |||
this.ServerGroupBox.Name = "ServerGroupBox"; | |||
this.ServerGroupBox.Size = new System.Drawing.Size(249, 200); | |||
this.ServerGroupBox.Size = new System.Drawing.Size(249, 174); | |||
this.ServerGroupBox.TabIndex = 6; | |||
this.ServerGroupBox.TabStop = false; | |||
this.ServerGroupBox.Text = "Server"; | |||
@@ -315,6 +295,7 @@ | |||
this.tableLayoutPanel2.ColumnCount = 2; | |||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); | |||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); | |||
this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel5, 1, 1); | |||
this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel3, 1, 2); | |||
this.tableLayoutPanel2.Controls.Add(this.ServersListBox, 0, 0); | |||
this.tableLayoutPanel2.Controls.Add(this.ServerGroupBox, 1, 0); | |||
@@ -326,9 +307,53 @@ | |||
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()); | |||
this.tableLayoutPanel2.Size = new System.Drawing.Size(427, 264); | |||
this.tableLayoutPanel2.Size = new System.Drawing.Size(427, 238); | |||
this.tableLayoutPanel2.TabIndex = 7; | |||
// | |||
// tableLayoutPanel5 | |||
// | |||
this.tableLayoutPanel5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | |||
| System.Windows.Forms.AnchorStyles.Right))); | |||
this.tableLayoutPanel5.AutoSize = true; | |||
this.tableLayoutPanel5.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; | |||
this.tableLayoutPanel5.ColumnCount = 2; | |||
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); | |||
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); | |||
this.tableLayoutPanel5.Controls.Add(this.ProxyPortTextBox, 1, 0); | |||
this.tableLayoutPanel5.Controls.Add(this.ProxyPortLabel, 0, 0); | |||
this.tableLayoutPanel5.Location = new System.Drawing.Point(241, 174); | |||
this.tableLayoutPanel5.Margin = new System.Windows.Forms.Padding(0); | |||
this.tableLayoutPanel5.Name = "tableLayoutPanel5"; | |||
this.tableLayoutPanel5.Padding = new System.Windows.Forms.Padding(3); | |||
this.tableLayoutPanel5.RowCount = 1; | |||
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26F)); | |||
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26F)); | |||
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26F)); | |||
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26F)); | |||
this.tableLayoutPanel5.Size = new System.Drawing.Size(186, 32); | |||
this.tableLayoutPanel5.TabIndex = 9; | |||
// | |||
// ProxyPortTextBox | |||
// | |||
this.ProxyPortTextBox.Anchor = System.Windows.Forms.AnchorStyles.Left; | |||
this.ProxyPortTextBox.Location = new System.Drawing.Point(67, 6); | |||
this.ProxyPortTextBox.MaxLength = 10; | |||
this.ProxyPortTextBox.Name = "ProxyPortTextBox"; | |||
this.ProxyPortTextBox.Size = new System.Drawing.Size(113, 20); | |||
this.ProxyPortTextBox.TabIndex = 4; | |||
this.ProxyPortTextBox.WordWrap = false; | |||
// | |||
// ProxyPortLabel | |||
// | |||
this.ProxyPortLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.ProxyPortLabel.AutoSize = true; | |||
this.ProxyPortLabel.Location = new System.Drawing.Point(6, 9); | |||
this.ProxyPortLabel.Name = "ProxyPortLabel"; | |||
this.ProxyPortLabel.Size = new System.Drawing.Size(55, 13); | |||
this.ProxyPortLabel.TabIndex = 3; | |||
this.ProxyPortLabel.Text = "Proxy Port"; | |||
// | |||
// tableLayoutPanel3 | |||
// | |||
this.tableLayoutPanel3.AutoSize = true; | |||
@@ -340,7 +365,7 @@ | |||
this.tableLayoutPanel3.Controls.Add(this.MyCancelButton, 1, 0); | |||
this.tableLayoutPanel3.Controls.Add(this.OKButton, 0, 0); | |||
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Right; | |||
this.tableLayoutPanel3.Location = new System.Drawing.Point(268, 235); | |||
this.tableLayoutPanel3.Location = new System.Drawing.Point(268, 209); | |||
this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3); | |||
this.tableLayoutPanel3.Name = "tableLayoutPanel3"; | |||
this.tableLayoutPanel3.RowCount = 1; | |||
@@ -358,7 +383,7 @@ | |||
this.tableLayoutPanel4.Controls.Add(this.DeleteButton, 1, 0); | |||
this.tableLayoutPanel4.Controls.Add(this.AddButton, 0, 0); | |||
this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Top; | |||
this.tableLayoutPanel4.Location = new System.Drawing.Point(0, 200); | |||
this.tableLayoutPanel4.Location = new System.Drawing.Point(0, 174); | |||
this.tableLayoutPanel4.Margin = new System.Windows.Forms.Padding(0); | |||
this.tableLayoutPanel4.Name = "tableLayoutPanel4"; | |||
this.tableLayoutPanel4.RowCount = 1; | |||
@@ -393,6 +418,8 @@ | |||
this.ServerGroupBox.PerformLayout(); | |||
this.tableLayoutPanel2.ResumeLayout(false); | |||
this.tableLayoutPanel2.PerformLayout(); | |||
this.tableLayoutPanel5.ResumeLayout(false); | |||
this.tableLayoutPanel5.PerformLayout(); | |||
this.tableLayoutPanel3.ResumeLayout(false); | |||
this.tableLayoutPanel4.ResumeLayout(false); | |||
this.ResumeLayout(false); | |||
@@ -406,11 +433,9 @@ | |||
private System.Windows.Forms.Label IPLabel; | |||
private System.Windows.Forms.Label ServerPortLabel; | |||
private System.Windows.Forms.Label PasswordLabel; | |||
private System.Windows.Forms.Label ProxyPortLabel; | |||
private System.Windows.Forms.TextBox IPTextBox; | |||
private System.Windows.Forms.TextBox ServerPortTextBox; | |||
private System.Windows.Forms.TextBox PasswordTextBox; | |||
private System.Windows.Forms.TextBox ProxyPortTextBox; | |||
private System.Windows.Forms.Label EncryptionLabel; | |||
private System.Windows.Forms.ComboBox EncryptionSelect; | |||
private System.Windows.Forms.Panel panel2; | |||
@@ -425,6 +450,9 @@ | |||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; | |||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; | |||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4; | |||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel5; | |||
private System.Windows.Forms.TextBox ProxyPortTextBox; | |||
private System.Windows.Forms.Label ProxyPortLabel; | |||
} | |||
} | |||
@@ -79,12 +79,14 @@ namespace Shadowsocks.View | |||
server = IPTextBox.Text, | |||
server_port = int.Parse(ServerPortTextBox.Text), | |||
password = PasswordTextBox.Text, | |||
local_port = int.Parse(ProxyPortTextBox.Text), | |||
method = EncryptionSelect.Text, | |||
remarks = RemarksTextBox.Text | |||
}; | |||
int localPort = int.Parse(ProxyPortTextBox.Text); | |||
Configuration.CheckServer(server); | |||
Configuration.CheckPort(localPort); | |||
_modifiedConfiguration.configs[_oldSelectedIndex] = server; | |||
_modifiedConfiguration.localPort = localPort; | |||
return true; | |||
} | |||
@@ -108,7 +110,7 @@ namespace Shadowsocks.View | |||
IPTextBox.Text = server.server; | |||
ServerPortTextBox.Text = server.server_port.ToString(); | |||
PasswordTextBox.Text = server.password; | |||
ProxyPortTextBox.Text = server.local_port.ToString(); | |||
ProxyPortTextBox.Text = _modifiedConfiguration.localPort.ToString(); | |||
EncryptionSelect.Text = server.method ?? "aes-256-cfb"; | |||
RemarksTextBox.Text = server.remarks; | |||
ServerGroupBox.Visible = true; | |||
@@ -202,7 +204,7 @@ namespace Shadowsocks.View | |||
MessageBox.Show(I18N.GetString("Please add at least one server")); | |||
return; | |||
} | |||
controller.SaveServers(_modifiedConfiguration.configs); | |||
controller.SaveServers(_modifiedConfiguration.configs, _modifiedConfiguration.localPort); | |||
this.Close(); | |||
} | |||
@@ -63,7 +63,7 @@ namespace Shadowsocks.View | |||
LoadCurrentConfiguration(); | |||
updateChecker.CheckUpdate(); | |||
updateChecker.CheckUpdate(controller.GetConfiguration()); | |||
if (controller.GetConfiguration().isDefault) | |||
{ | |||
@@ -131,7 +131,7 @@ namespace Shadowsocks.View | |||
private void LoadMenu() | |||
{ | |||
this.contextMenu1 = new ContextMenu(new MenuItem[] { | |||
this.enableItem = CreateMenuItem("Enable", new EventHandler(this.EnableItem_Click)), | |||
this.enableItem = CreateMenuItem("Enable System Proxy", new EventHandler(this.EnableItem_Click)), | |||
CreateMenuGroup("Mode", new MenuItem[] { | |||
this.PACModeItem = CreateMenuItem("PAC", new EventHandler(this.PACModeItem_Click)), | |||
this.globalModeItem = CreateMenuItem("Global", new EventHandler(this.GlobalModeItem_Click)) | |||
@@ -127,7 +127,9 @@ | |||
<Compile Include="Controller\FileManager.cs" /> | |||
<Compile Include="Controller\GFWListUpdater.cs" /> | |||
<Compile Include="Controller\I18N.cs" /> | |||
<Compile Include="Controller\Listener.cs" /> | |||
<Compile Include="Controller\Logging.cs" /> | |||
<Compile Include="Controller\PortForwarder.cs" /> | |||
<Compile Include="Controller\UpdateChecker.cs" /> | |||
<Compile Include="Encryption\EncryptorBase.cs" /> | |||
<Compile Include="Encryption\EncryptorFactory.cs" /> | |||