Browse Source

Merge branch 'master' into v5/master

# Conflicts:
#	appveyor.yml
#	shadowsocks-csharp/Controller/Service/TCPRelay.cs
#	shadowsocks-csharp/Program.cs
#	shadowsocks-csharp/Properties/Resources.Designer.cs
#	shadowsocks-csharp/View/MenuViewController.cs
#	shadowsocks-csharp/packages.config
#	shadowsocks-csharp/shadowsocks-csharp.csproj
pull/2895/head
Student Main 4 years ago
parent
commit
13689dbd69
23 changed files with 6452 additions and 7734 deletions
  1. +39
    -0
      .github/ISSUE_TEMPLATE/bug_report_en.md
  2. +39
    -0
      .github/ISSUE_TEMPLATE/bug_report_zh.md
  3. +20
    -0
      .github/ISSUE_TEMPLATE/feature_request.md
  4. +0
    -29
      .github/issue_template.md
  5. +3
    -3
      README.md
  6. +2
    -16
      appveyor.yml
  7. +203
    -0
      shadowsocks-csharp/Controller/Service/GeositeUpdater.cs
  8. +0
    -137
      shadowsocks-csharp/Controller/Service/GfwListUpdater.cs
  9. +8
    -8
      shadowsocks-csharp/Controller/Service/PACDaemon.cs
  10. +204
    -120
      shadowsocks-csharp/Controller/Service/TCPRelay.cs
  11. +40
    -43
      shadowsocks-csharp/Controller/ShadowsocksController.cs
  12. +4
    -0
      shadowsocks-csharp/Data/abp.js
  13. +0
    -7250
      shadowsocks-csharp/Data/default-abp-rule.js
  14. +4983
    -0
      shadowsocks-csharp/Data/dlc.dat
  15. +34
    -34
      shadowsocks-csharp/Data/i18n.csv
  16. +32
    -28
      shadowsocks-csharp/Model/Configuration.cs
  17. +753
    -0
      shadowsocks-csharp/Model/Geosite/Geosite.cs
  18. +43
    -0
      shadowsocks-csharp/Model/Geosite/geosite.proto
  19. +17
    -39
      shadowsocks-csharp/Properties/Resources.Designer.cs
  20. +2
    -2
      shadowsocks-csharp/Properties/Resources.resx
  21. +23
    -23
      shadowsocks-csharp/View/MenuViewController.cs
  22. +1
    -0
      shadowsocks-csharp/packages.config
  23. +2
    -2
      shadowsocks-csharp/shadowsocks-csharp.csproj

+ 39
- 0
.github/ISSUE_TEMPLATE/bug_report_en.md View File

@@ -0,0 +1,39 @@
---
name: Bug report (English)
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

<!--
- Shadowsocks is a non-profit open source project. If you bought the service from a provider, please contact them.
- If you have questions rather than Shadowsocks Windows client, please go to https://github.com/shadowsocks
- Please read Wiki carefully, especially https://github.com/shadowsocks/shadowsocks-windows/wiki/Troubleshooting
- And search from Issue Board https://github.com/shadowsocks/shadowsocks-windows/issues?utf8=%E2%9C%93&q=is%3Aissue
- Please include the following information. Questions lacking details will be closed.
-->

### Describe the bug

### Environment

- Shadowsocks client version:
- OS version:
- .NET version:

### Steps you have tried


### What did you expect to see?


### What did you see instead?


### Config and error log in detail (with all sensitive info masked)

```
PASTE LOG HERE
```

+ 39
- 0
.github/ISSUE_TEMPLATE/bug_report_zh.md View File

@@ -0,0 +1,39 @@
---
name: Bug报告 (中文)
about: 反馈Bug
title: ''
labels: bug report
assignees: ''

---

<!--
- 影梭(Shadowsocks)是一个开源非盈利项目,不提供任何托管服务。如果你是从服务提供商购买的服务,请联系他们。
- 如果你有非影梭Windows客户端相关的问题,请去 https://github.com/shadowsocks
- 提问前请先阅读wiki https://github.com/shadowsocks/shadowsocks-windows/wiki/Troubleshooting.
- 并在Issue Board中搜索 https://github.com/shadowsocks/shadowsocks-windows/issues?utf8=%E2%9C%93&q=is%3Aissue
- 请按照以下格式描述你的问题,描述不清的问题将会被关闭。
-->

### 简要描述问题

### 环境

- Shadowsocks客户端版本:
- 操作系统版本:
- .NET版本:

### 操作步骤


### 期望的结果


### 实际结果


### 配置文件和日志文件(请隐去敏感信息)

```
在此粘贴日志
```

+ 20
- 0
.github/ISSUE_TEMPLATE/feature_request.md View File

@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.

+ 0
- 29
.github/issue_template.md View File

@@ -1,29 +0,0 @@
<!--
- Shadowsocks is a non-profit open source project. If you bought the service from a provider, please contact them.
影梭(Shadowsocks)是一个开源非盈利项目,不提供任何托管服务。如果你是从服务提供商购买的服务,请联系他们。
- If you have questions rather than Shadowsocks Windows client, please go to https://github.com/shadowsocks
如果你有非影梭Windows客户端相关的问题,请去 https://github.com/shadowsocks
- Please read Wiki carefully, especially https://github.com/shadowsocks/shadowsocks-windows/wiki/Troubleshooting
提问前请先阅读wiki https://github.com/shadowsocks/shadowsocks-windows/wiki/Troubleshooting.
- And search from Issue Board https://github.com/shadowsocks/shadowsocks-windows/issues?utf8=%E2%9C%93&q=is%3Aissue
并在Issue Board中搜索 https://github.com/shadowsocks/shadowsocks-windows/issues?utf8=%E2%9C%93&q=is%3Aissue
- Please include the following information. Questions lacking details will be closed.
请按照以下格式描述你的问题,描述不清的问题将会被关闭。
-->
### Shadowsocks version / 影梭版本
### Environment (Operating system, .NET Framework, etc) / 使用环境(操作系统,.NET Framework等)
### Steps you have tried / 操作步骤
### What did you expect to see? / 期望的结果
### What did you see instead? / 实际结果
### Config and error log in detail (with all sensitive info masked) / 配置文件和日志文件(请隐去敏感信息)

+ 3
- 3
README.md View File

@@ -9,7 +9,7 @@
1. System proxy configuration
2. PAC mode and global mode
3. [GFWList] and user rules
3. [GeoSite] and user rules
4. Supports HTTP proxy
5. Supports server auto switching
6. Supports UDP relay (see Usage)
@@ -37,7 +37,7 @@ port in `Servers -> Edit Servers`
1. You can change PAC rules by editing the PAC file. When you save the PAC file
with any editor, Shadowsocks will notify browsers about the change automatically
2. You can also update PAC file from [GFWList] \(maintained by 3rd party)
2. You can also update PAC file from [GeoSite] \(maintained by 3rd party)
3. You can also use online PAC URL
For Windows10 Store and related applications, please execute the following command under Admin privilege:
@@ -144,7 +144,7 @@ Sysproxy () https://github.com/Noisyfox/sysproxy
[Appveyor]: https://ci.appveyor.com/project/celeron533/shadowsocks-windows
[Build Status]: https://ci.appveyor.com/api/projects/status/tfw57q6eecippsl5/branch/master?svg=true
[release page]: https://github.com/shadowsocks/shadowsocks-csharp/releases
[GFWList]: https://github.com/gfwlist/gfwlist
[GeoSite]: https://github.com/v2ray/domain-list-community
[Servers]: https://github.com/shadowsocks/shadowsocks/wiki/Ports-and-Clients#linux--server-side
[中文说明]: https://github.com/shadowsocks/shadowsocks-windows/wiki/Shadowsocks-Windows-%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E
[Visual Studio 2017]: https://www.visualstudio.com/downloads/


+ 2
- 16
appveyor.yml View File

@@ -102,7 +102,7 @@ before_build:
# scripts to run after build (working directory and environment changes are persisted from the previous steps)
after_build:
ps: |
- ps: |+
function CalculateHash($file)
{
$newLine = "`r`n"
@@ -162,21 +162,7 @@ after_build:
# providers: Local, FTP, WebDeploy, AzureCS, AzureBlob, S3, NuGet, Environment
# provider names are case-sensitive!
deploy:
# Deploy to GitHub Releases
- provider: GitHub
auth_token:
secure: ZrRlVe3eWp1ccIVZcmFrI7vaCxwz5ewIMSmaPUTjMGyC1rVRlYm7nWWi6Pzkpe0A
description: '%APPVEYOR_BUILD_VERSION%'
artifact: Shadowsocks-%APPVEYOR_BUILD_VERSION%.zip, Shadowsocks-%APPVEYOR_BUILD_VERSION%.zip.hash
draft: true
prerelease: true
on:
branch: master # release from master branch only
configuration: Release
APPVEYOR_REPO_TAG: true # deploy on tag push only
# deploy:
# # scripts to run before deployment
# before_deploy:


+ 203
- 0
shadowsocks-csharp/Controller/Service/GeositeUpdater.cs View File

@@ -0,0 +1,203 @@
using NLog;
using Shadowsocks.Properties;
using Shadowsocks.Util;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using Shadowsocks.Model;
using System.Net;

namespace Shadowsocks.Controller
{
public class GeositeResultEventArgs : EventArgs
{
public bool Success;

public GeositeResultEventArgs(bool success)
{
this.Success = success;
}
}

public static class GeositeUpdater
{
private static Logger logger = LogManager.GetCurrentClassLogger();

public static event EventHandler<GeositeResultEventArgs> UpdateCompleted;

public static event ErrorEventHandler Error;

private static readonly string DATABASE_PATH = Utils.GetTempPath("dlc.dat");

private static readonly string GEOSITE_URL = "https://github.com/v2ray/domain-list-community/raw/release/dlc.dat";

public static readonly Dictionary<string, IList<DomainObject>> Geosites = new Dictionary<string, IList<DomainObject>>();

static GeositeUpdater()
{
if (!File.Exists(DATABASE_PATH))
{
File.WriteAllBytes(DATABASE_PATH, Resources.dlc_dat);
}
LoadGeositeList();
}

static void LoadGeositeList(byte[] data = null)
{
data = data ?? File.ReadAllBytes(DATABASE_PATH);
var list = GeositeList.Parser.ParseFrom(data);
foreach (var item in list.Entries)
{
Geosites[item.GroupName.ToLower()] = item.Domains;
}
}

public static void ResetEvent()
{
UpdateCompleted = null;
Error = null;
}

public static void UpdatePACFromGeosite(Configuration config)
{
string geositeUrl = GEOSITE_URL;
string group = config.geositeGroup;
bool blacklist = config.geositeBlacklistMode;
if (!string.IsNullOrWhiteSpace(config.geositeUrl))
{
logger.Info("Found custom Geosite URL in config file");
geositeUrl = config.geositeUrl;
}
logger.Info($"Checking Geosite from {geositeUrl}");
WebClient http = new WebClient();
if (config.enabled)
{
http.Proxy = new WebProxy(
config.isIPv6Enabled
? $"[{IPAddress.IPv6Loopback}]"
: IPAddress.Loopback.ToString(),
config.localPort);
}
http.DownloadDataCompleted += (o, e) =>
{
try
{
File.WriteAllBytes(DATABASE_PATH, e.Result);
LoadGeositeList();

bool pacFileChanged = MergeAndWritePACFile(group, blacklist);
UpdateCompleted?.Invoke(null, new GeositeResultEventArgs(pacFileChanged));
}
catch (Exception ex)
{
Error?.Invoke(null, new ErrorEventArgs(ex));
}
};
http.DownloadDataAsync(new Uri(geositeUrl));
}

public static bool MergeAndWritePACFile(string group, bool blacklist)
{
IList<DomainObject> domains = Geosites[group];
string abpContent = MergePACFile(domains, blacklist);
if (File.Exists(PACDaemon.PAC_FILE))
{
string original = FileManager.NonExclusiveReadAllText(PACDaemon.PAC_FILE, Encoding.UTF8);
if (original == abpContent)
{
return false;
}
}
File.WriteAllText(PACDaemon.PAC_FILE, abpContent, Encoding.UTF8);
return true;
}

private static string MergePACFile(IList<DomainObject> domains, bool blacklist)
{
string abpContent;
if (File.Exists(PACDaemon.USER_ABP_FILE))
{
abpContent = FileManager.NonExclusiveReadAllText(PACDaemon.USER_ABP_FILE, Encoding.UTF8);
}
else
{
abpContent = Resources.abp_js;
}

List<string> userruleLines = new List<string>();
if (File.Exists(PACDaemon.USER_RULE_FILE))
{
string userrulesString = FileManager.NonExclusiveReadAllText(PACDaemon.USER_RULE_FILE, Encoding.UTF8);
userruleLines = PreProcessGFWList(userrulesString);
}

List<string> gfwLines = GeositeToGFWList(domains, blacklist);
abpContent =
$@"var __USERRULES__ = {JsonConvert.SerializeObject(userruleLines, Formatting.Indented)};
var __RULES__ = {JsonConvert.SerializeObject(gfwLines, Formatting.Indented)};
{abpContent}";
return abpContent;
}

private static readonly IEnumerable<char> IgnoredLineBegins = new[] { '!', '[' };

private static List<string> PreProcessGFWList(string content)
{
List<string> valid_lines = new List<string>();
using (var sr = new StringReader(content))
{
foreach (var line in sr.NonWhiteSpaceLines())
{
if (line.BeginWithAny(IgnoredLineBegins))
continue;
valid_lines.Add(line);
}
}
return valid_lines;
}

private static List<string> GeositeToGFWList(IList<DomainObject> domains, bool blacklist)
{
return blacklist ? GeositeToGFWListBlack(domains) : GeositeToGFWListWhite(domains);
}

private static List<string> GeositeToGFWListBlack(IList<DomainObject> domains)
{
List<string> ret = new List<string>(domains.Count + 100);// 100 overhead
foreach (var d in domains)
{
string domain = d.Value;

switch (d.Type)
{
case DomainObject.Types.Type.Plain:
ret.Add(domain);
break;
case DomainObject.Types.Type.Regex:
ret.Add($"/{domain}/");
break;
case DomainObject.Types.Type.Domain:
ret.Add($"||{domain}");
break;
case DomainObject.Types.Type.Full:
ret.Add($"|http://{domain}");
ret.Add($"|https://{domain}");
break;
}
}
return ret;
}

private static List<string> GeositeToGFWListWhite(IList<DomainObject> domains)
{
return GeositeToGFWListBlack(domains)
.Select(r => $"@@{r}") // convert to whitelist
.Prepend("/.*/") // blacklist all other site
.ToList();
}
}
}

+ 0
- 137
shadowsocks-csharp/Controller/Service/GfwListUpdater.cs View File

@@ -1,137 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;

using Newtonsoft.Json;
using NLog;
using Shadowsocks.Model;
using Shadowsocks.Properties;
using Shadowsocks.Util;

namespace Shadowsocks.Controller
{
public class GFWListUpdater
{
private static Logger logger = LogManager.GetCurrentClassLogger();

private const string GFWLIST_URL = "https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt";

public event EventHandler<ResultEventArgs> UpdateCompleted;

public event ErrorEventHandler Error;

public class ResultEventArgs : EventArgs
{
public bool Success;

public ResultEventArgs(bool success)
{
this.Success = success;
}
}

private static readonly IEnumerable<char> IgnoredLineBegins = new[] { '!', '[' };
private void http_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
try
{
File.WriteAllText(Utils.GetTempPath("gfwlist.txt"), e.Result, Encoding.UTF8);
bool pacFileChanged = MergeAndWritePACFile(e.Result);
UpdateCompleted?.Invoke(this, new ResultEventArgs(pacFileChanged));
}
catch (Exception ex)
{
Error?.Invoke(this, new ErrorEventArgs(ex));
}
}

public static bool MergeAndWritePACFile(string gfwListResult)
{
string abpContent = MergePACFile(gfwListResult);
if (File.Exists(PACDaemon.PAC_FILE))
{
string original = FileManager.NonExclusiveReadAllText(PACDaemon.PAC_FILE, Encoding.UTF8);
if (original == abpContent)
{
return false;
}
}
File.WriteAllText(PACDaemon.PAC_FILE, abpContent, Encoding.UTF8);
return true;
}

private static string MergePACFile(string gfwListResult)
{
string abpContent;
if (File.Exists(PACDaemon.USER_ABP_FILE))
{
abpContent = FileManager.NonExclusiveReadAllText(PACDaemon.USER_ABP_FILE, Encoding.UTF8);
}
else
{
abpContent = Resources.abp_js;
}

List<string> userruleLines = new List<string>();
if (File.Exists(PACDaemon.USER_RULE_FILE))
{
string userrulesString = FileManager.NonExclusiveReadAllText(PACDaemon.USER_RULE_FILE, Encoding.UTF8);
userruleLines = ParseToValidList(userrulesString);
}

List<string> gfwLines = new List<string>();
gfwLines = ParseBase64ToValidList(gfwListResult);
abpContent =
$@"var __USERRULES__ = {JsonConvert.SerializeObject(userruleLines, Formatting.Indented)};
var __RULES__ = {JsonConvert.SerializeObject(gfwLines, Formatting.Indented)};
{abpContent}";
return abpContent;
}

public void UpdatePACFromGFWList(Configuration config)
{
string gfwListUrl = GFWLIST_URL;
if (!string.IsNullOrWhiteSpace(config.gfwListUrl))
{
logger.Info("Found custom GFWListURL in config file");
gfwListUrl = config.gfwListUrl;
}
logger.Info($"Checking GFWList from {gfwListUrl}");
WebClient http = new WebClient();
if (config.enabled)
{
http.Proxy = new WebProxy(
config.isIPv6Enabled
? $"[{IPAddress.IPv6Loopback.ToString()}]"
: IPAddress.Loopback.ToString(),
config.localPort);
}
http.DownloadStringCompleted += http_DownloadStringCompleted;
http.DownloadStringAsync(new Uri(gfwListUrl));
}

public static List<string> ParseBase64ToValidList(string response)
{
byte[] bytes = Convert.FromBase64String(response);
string content = Encoding.ASCII.GetString(bytes);
return ParseToValidList(content);
}

private static List<string> ParseToValidList(string content)
{
List<string> valid_lines = new List<string>();
using (var sr = new StringReader(content))
{
foreach (var line in sr.NonWhiteSpaceLines())
{
if (line.BeginWithAny(IgnoredLineBegins))
continue;
valid_lines.Add(line);
}
}
return valid_lines;
}
}
}

+ 8
- 8
shadowsocks-csharp/Controller/Service/PACDaemon.cs View File

@@ -1,4 +1,5 @@
using NLog;
using Shadowsocks.Model;
using Shadowsocks.Properties;
using Shadowsocks.Util;
using System;
@@ -21,6 +22,7 @@ namespace Shadowsocks.Controller
public const string PAC_FILE = "pac.txt";
public const string USER_RULE_FILE = "user-rule.txt";
public const string USER_ABP_FILE = "abp.txt";
private Configuration config;
FileSystemWatcher PACFileWatcher;
FileSystemWatcher UserRuleFileWatcher;
@@ -28,8 +30,9 @@ namespace Shadowsocks.Controller
public event EventHandler PACFileChanged;
public event EventHandler UserRuleFileChanged;
public PACDaemon()
public PACDaemon(Configuration config)
{
this.config = config;
TouchPACFile();
TouchUserRuleFile();
@@ -42,7 +45,7 @@ namespace Shadowsocks.Controller
{
if (!File.Exists(PAC_FILE))
{
File.WriteAllText(PAC_FILE, Resources.default_abp_rule + Resources.abp_js);
GeositeUpdater.MergeAndWritePACFile(config.geositeGroup, config.geositeBlacklistMode);
}
return PAC_FILE;
}
@@ -58,14 +61,11 @@ namespace Shadowsocks.Controller
internal string GetPACContent()
{
if (File.Exists(PAC_FILE))
{
return File.ReadAllText(PAC_FILE, Encoding.UTF8);
}
else
if (!File.Exists(PAC_FILE))
{
return Resources.default_abp_rule + Resources.abp_js;
GeositeUpdater.MergeAndWritePACFile(config.geositeGroup, config.geositeBlacklistMode);
}
return File.ReadAllText(PAC_FILE, Encoding.UTF8);
}


+ 204
- 120
shadowsocks-csharp/Controller/Service/TCPRelay.cs View File

@@ -1,10 +1,12 @@
using NLog;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Timers;
using NLog;
using Shadowsocks.Controller.Strategy;
using Shadowsocks.Encryption;
using Shadowsocks.Encryption.AEAD;
@@ -12,16 +14,22 @@ using Shadowsocks.Encryption.Exception;
using Shadowsocks.Model;
using Shadowsocks.Proxy;
using Shadowsocks.Util.Sockets;
using static Shadowsocks.Encryption.EncryptorBase;
namespace Shadowsocks.Controller
{
class TCPRelay : StreamService
{
private static Logger logger = LogManager.GetCurrentClassLogger();
private ShadowsocksController _controller;
public event EventHandler<SSTCPConnectedEventArgs> OnConnected;
public event EventHandler<SSTransmitEventArgs> OnInbound;
public event EventHandler<SSTransmitEventArgs> OnOutbound;
public event EventHandler<SSRelayEventArgs> OnFailed;
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
private readonly ShadowsocksController _controller;
private DateTime _lastSweepTime;
private Configuration _config;
private readonly Configuration _config;
public ISet<TCPHandler> Handlers { get; set; }
@@ -47,7 +55,7 @@ namespace Shadowsocks.Controller
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
TCPHandler handler = new TCPHandler(_controller, _config, this, socket);
TCPHandler handler = new TCPHandler(_controller, _config, socket);
IList<TCPHandler> handlersToClose = new List<TCPHandler>();
lock (Handlers)
@@ -85,9 +93,24 @@ namespace Shadowsocks.Controller
{
if (socket.ProtocolType != ProtocolType.Tcp
|| (length < 2 || firstPacket[0] != 5))
{
return false;
}
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
TCPHandler handler = new TCPHandler(_controller, _config, this, socket);
TCPHandler handler = new TCPHandler(_controller, _config, socket);
handler.OnConnected += OnConnected;
handler.OnInbound += OnInbound;
handler.OnOutbound += OnOutbound;
handler.OnFailed += OnFailed;
handler.OnClosed += (h, arg) =>
{
lock (Handlers)
{
Handlers.Remove(handler);
}
};
IList<TCPHandler> handlersToClose = new List<TCPHandler>();
lock (Handlers)
@@ -98,8 +121,12 @@ namespace Shadowsocks.Controller
{
_lastSweepTime = now;
foreach (TCPHandler handler1 in Handlers)
{
if (now - handler1.lastActivity > TimeSpan.FromSeconds(900))
{
handlersToClose.Add(handler1);
}
}
}
}
foreach (TCPHandler handler1 in handlersToClose)
@@ -128,26 +155,46 @@ namespace Shadowsocks.Controller
}
handlersToClose.ForEach(h => h.Close());
}
}
public void UpdateInboundCounter(Server server, long n)
public class SSRelayEventArgs : EventArgs
{
public readonly Server server;
public SSRelayEventArgs(Server server)
{
_controller.UpdateInboundCounter(server, n);
this.server = server;
}
}
public void UpdateOutboundCounter(Server server, long n)
public class SSTransmitEventArgs : SSRelayEventArgs
{
public readonly long length;
public SSTransmitEventArgs(Server server, long length) : base(server)
{
_controller.UpdateOutboundCounter(server, n);
this.length = length;
}
}
public class SSTCPConnectedEventArgs : SSRelayEventArgs
{
public readonly TimeSpan latency;
public void UpdateLatency(Server server, TimeSpan latency)
public SSTCPConnectedEventArgs(Server server, TimeSpan latency) : base(server)
{
_controller.UpdateLatency(server, latency);
this.latency = latency;
}
}
internal class TCPHandler
{
class AsyncSession
public event EventHandler<SSTCPConnectedEventArgs> OnConnected;
public event EventHandler<SSTransmitEventArgs> OnInbound;
public event EventHandler<SSTransmitEventArgs> OnOutbound;
public event EventHandler<SSRelayEventArgs> OnClosed;
public event EventHandler<SSRelayEventArgs> OnFailed;
private class AsyncSession
{
public IProxy Remote { get; }
@@ -157,7 +204,7 @@ namespace Shadowsocks.Controller
}
}
class AsyncSession<T> : AsyncSession
private class AsyncSession<T> : AsyncSession
{
public T State { get; set; }
@@ -172,7 +219,7 @@ namespace Shadowsocks.Controller
}
}
private static Logger Logger = LogManager.GetCurrentClassLogger();
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly int _serverTimeout;
private readonly int _proxyTimeout;
@@ -191,10 +238,9 @@ namespace Shadowsocks.Controller
public DateTime lastActivity;
private ShadowsocksController _controller;
private Configuration _config;
private TCPRelay _tcprelay;
private Socket _connection;
private readonly ShadowsocksController _controller;
private readonly ProxyConfig _config;
private readonly Socket _connection;
private IEncryptor encryptor;
// workaround
@@ -220,16 +266,16 @@ namespace Shadowsocks.Controller
private int _totalWrite = 0;
// remote -> local proxy (ciphertext, before decrypt)
private byte[] _remoteRecvBuffer = new byte[BufferSize];
private readonly byte[] _remoteRecvBuffer = new byte[BufferSize];
// client -> local proxy (plaintext, before encrypt)
private byte[] _connetionRecvBuffer = new byte[BufferSize];
private readonly byte[] _connetionRecvBuffer = new byte[BufferSize];
// local proxy -> remote (plaintext, after decrypt)
private byte[] _remoteSendBuffer = new byte[BufferSize];
private readonly byte[] _remoteSendBuffer = new byte[BufferSize];
// local proxy -> client (ciphertext, before decrypt)
private byte[] _connetionSendBuffer = new byte[BufferSize];
private readonly byte[] _connetionSendBuffer = new byte[BufferSize];
private bool _connectionShutdown = false;
private bool _remoteShutdown = false;
@@ -247,11 +293,11 @@ namespace Shadowsocks.Controller
private EndPoint _destEndPoint = null;
public TCPHandler(ShadowsocksController controller, Configuration config, TCPRelay tcprelay, Socket socket)
// TODO: decouple controller
public TCPHandler(ShadowsocksController controller, Configuration config, Socket socket)
{
_controller = controller;
_config = config;
_tcprelay = tcprelay;
_config = config.proxy;
_connection = socket;
_proxyTimeout = config.proxy.proxyTimeout * 1000;
_serverTimeout = config.GetCurrentServer().timeout * 1000;
@@ -264,7 +310,9 @@ namespace Shadowsocks.Controller
Server server = _controller.GetAServer(IStrategyCallerType.TCP, (IPEndPoint)_connection.RemoteEndPoint,
_destEndPoint);
if (server == null || server.server == "")
{
throw new ArgumentException("No server configured");
}
encryptor = EncryptorFactory.GetEncryptor(server.method, server.password);
decryptor = EncryptorFactory.GetEncryptor(server.method, server.password);
@@ -286,20 +334,31 @@ namespace Shadowsocks.Controller
private void CheckClose()
{
if (_connectionShutdown && _remoteShutdown)
{
Close();
}
}
private void ErrorClose(Exception e)
{
Logger.LogUsefulException(e);
Close();
}
public void Close()
{
lock (_closeConnLock)
{
if (_closed) return;
if (_closed)
{
return;
}
_closed = true;
}
lock (_tcprelay.Handlers)
{
_tcprelay.Handlers.Remove(this);
}
OnClosed?.Invoke(this, new SSRelayEventArgs(_server));
try
{
_connection.Shutdown(SocketShutdown.Both);
@@ -314,7 +373,7 @@ namespace Shadowsocks.Controller
{
try
{
var remote = _currentRemoteSession.Remote;
IProxy remote = _currentRemoteSession.Remote;
remote.Shutdown(SocketShutdown.Both);
remote.Close();
}
@@ -327,7 +386,11 @@ namespace Shadowsocks.Controller
private void HandshakeReceive()
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
int bytesRead = _firstPacketLength;
@@ -344,18 +407,23 @@ namespace Shadowsocks.Controller
HandshakeSendCallback, null);
}
else
{
Close();
}
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
private void HandshakeSendCallback(IAsyncResult ar)
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
_connection.EndSend(ar);
@@ -367,20 +435,23 @@ namespace Shadowsocks.Controller
// +-----+-----+-------+------+----------+----------+
// Skip first 3 bytes, and read 2 more bytes to analysis the address.
// 2 more bytes is designed if address is domain then we don't need to read once more to get the addr length.
// TODO validate
// validate is unnecessary, we did it in first packet, but we can do it in future version
_connection.BeginReceive(_connetionRecvBuffer, 0, 3 + ADDR_ATYP_LEN + 1, SocketFlags.None,
HandshakeReceive2Callback, null);
AddressReceiveCallback, null);
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
private void HandshakeReceive2Callback(IAsyncResult ar)
private void AddressReceiveCallback(IAsyncResult ar)
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
int bytesRead = _connection.EndReceive(ar);
@@ -398,7 +469,7 @@ namespace Shadowsocks.Controller
// +----+-----+-------+------+----------+----------+
byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 };
_connection.BeginSend(response, 0, response.Length, SocketFlags.None,
ResponseCallback, null);
ConnectResponseCallback, null);
break;
case CMD_UDP_ASSOC:
ReadAddress(HandleUDPAssociate);
@@ -419,12 +490,11 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
private void ResponseCallback(IAsyncResult ar)
private void ConnectResponseCallback(IAsyncResult ar)
{
try
{
@@ -434,8 +504,7 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
@@ -474,15 +543,19 @@ namespace Shadowsocks.Controller
private void OnAddressFullyRead(IAsyncResult ar)
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
int bytesRead = _connection.EndReceive(ar);
var states = (object[])ar.AsyncState;
object[] states = (object[])ar.AsyncState;
int bytesRemain = (int)states[0];
var onSuccess = (Action)states[1];
Action onSuccess = (Action)states[1];
if (bytesRead >= bytesRemain)
{
@@ -529,8 +602,7 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
@@ -558,7 +630,11 @@ namespace Shadowsocks.Controller
private void ReadAll(IAsyncResult ar)
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
if (ar.AsyncState != null)
@@ -576,13 +652,14 @@ namespace Shadowsocks.Controller
ReadAll, null);
}
else
{
Close();
}
}
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
@@ -627,9 +704,9 @@ namespace Shadowsocks.Controller
serverEP = pluginEP;
remote = new DirectConnect();
}
else if (_config.proxy.useProxy)
else if (_config.useProxy)
{
switch (_config.proxy.proxyType)
switch (_config.proxyType)
{
case ProxyConfig.PROXY_SOCKS5:
remote = new Socks5Proxy();
@@ -640,14 +717,14 @@ namespace Shadowsocks.Controller
default:
throw new NotSupportedException("Unknown forward proxy.");
}
proxyEP = SocketUtil.GetEndPoint(_config.proxy.proxyServer, _config.proxy.proxyPort);
proxyEP = SocketUtil.GetEndPoint(_config.proxyServer, _config.proxyPort);
}
else
{
remote = new DirectConnect();
}
var session = new AsyncSession(remote);
AsyncSession session = new AsyncSession(remote);
lock (_closeConnLock)
{
if (_closed)
@@ -675,14 +752,13 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
private void ProxyConnectTimer_Elapsed(object sender, ElapsedEventArgs e)
{
var timer = (ProxyTimer)sender;
ProxyTimer timer = (ProxyTimer)sender;
timer.Elapsed -= ProxyConnectTimer_Elapsed;
timer.Enabled = false;
timer.Dispose();
@@ -692,7 +768,7 @@ namespace Shadowsocks.Controller
{
return;
}
var proxy = timer.Session.Remote;
IProxy proxy = timer.Session.Remote;
Logger.Info($"Proxy {proxy.ProxyEndPoint} timed out");
proxy.Close();
@@ -707,15 +783,15 @@ namespace Shadowsocks.Controller
}
try
{
var session = (AsyncSession<ProxyTimer>)ar.AsyncState;
AsyncSession<ProxyTimer> session = (AsyncSession<ProxyTimer>)ar.AsyncState;
ProxyTimer timer = session.State;
var destEndPoint = timer.DestEndPoint;
var server = timer.Server;
EndPoint destEndPoint = timer.DestEndPoint;
Server server = timer.Server;
timer.Elapsed -= ProxyConnectTimer_Elapsed;
timer.Enabled = false;
timer.Dispose();
var remote = session.Remote;
IProxy remote = session.Remote;
// Complete the connection.
remote.EndConnectProxy(ar);
@@ -737,9 +813,9 @@ namespace Shadowsocks.Controller
_destConnected = false;
NetworkCredential auth = null;
if (_config.proxy.useAuth)
if (_config.useAuth)
{
auth = new NetworkCredential(_config.proxy.authUser, _config.proxy.authPwd);
auth = new NetworkCredential(_config.authUser, _config.authPwd);
}
// Connect to the remote endpoint.
@@ -751,14 +827,13 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
private void DestConnectTimer_Elapsed(object sender, ElapsedEventArgs e)
{
var timer = (ServerTimer)sender;
ServerTimer timer = (ServerTimer)sender;
timer.Elapsed -= DestConnectTimer_Elapsed;
timer.Enabled = false;
timer.Dispose();
@@ -768,10 +843,9 @@ namespace Shadowsocks.Controller
return;
}
var session = timer.Session;
AsyncSession session = timer.Session;
Server server = timer.Server;
IStrategy strategy = _controller.GetCurrentStrategy();
strategy?.SetFailure(server);
OnFailed?.Invoke(this, new SSRelayEventArgs(_server));
Logger.Info($"{server.FriendlyName()} timed out");
session.Remote.Close();
Close();
@@ -779,17 +853,21 @@ namespace Shadowsocks.Controller
private void ConnectCallback(IAsyncResult ar)
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
var session = (AsyncSession<ServerTimer>)ar.AsyncState;
AsyncSession<ServerTimer> session = (AsyncSession<ServerTimer>)ar.AsyncState;
ServerTimer timer = session.State;
_server = timer.Server;
timer.Elapsed -= DestConnectTimer_Elapsed;
timer.Enabled = false;
timer.Dispose();
var remote = session.Remote;
IProxy remote = session.Remote;
// Complete the connection.
remote.EndConnectDest(ar);
@@ -797,10 +875,9 @@ namespace Shadowsocks.Controller
Logger.Debug($"Socket connected to ss server: {_server.FriendlyName()}");
var latency = DateTime.Now - _startConnectTime;
IStrategy strategy = _controller.GetCurrentStrategy();
strategy?.UpdateLatency(_server, latency);
_tcprelay.UpdateLatency(_server, latency);
TimeSpan latency = DateTime.Now - _startConnectTime;
OnConnected?.Invoke(this, new SSTCPConnectedEventArgs(_server, latency));
StartPipe(session);
}
@@ -811,11 +888,9 @@ namespace Shadowsocks.Controller
{
if (_server != null)
{
IStrategy strategy = _controller.GetCurrentStrategy();
strategy?.SetFailure(_server);
OnFailed?.Invoke(this, new SSRelayEventArgs(_server));
}
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
@@ -824,7 +899,7 @@ namespace Shadowsocks.Controller
int available = Math.Min(_connection.Available, RecvSize - _firstPacketLength);
if (available > 0)
{
var size = _connection.Receive(_connetionRecvBuffer, _firstPacketLength, available,
int size = _connection.Receive(_connetionRecvBuffer, _firstPacketLength, available,
SocketFlags.None);
_firstPacketLength += size;
@@ -833,7 +908,11 @@ namespace Shadowsocks.Controller
private void StartPipe(AsyncSession session)
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
_startReceivingTime = DateTime.Now;
@@ -846,20 +925,24 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
private void PipeRemoteReceiveCallback(IAsyncResult ar)
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
var session = (AsyncSession)ar.AsyncState;
AsyncSession session = (AsyncSession)ar.AsyncState;
int bytesRead = session.Remote.EndReceive(ar);
_totalRead += bytesRead;
_tcprelay.UpdateInboundCounter(_server, bytesRead);
OnInbound?.Invoke(this, new SSTransmitEventArgs(_server, bytesRead));
if (bytesRead > 0)
{
lastActivity = DateTime.Now;
@@ -889,8 +972,6 @@ namespace Shadowsocks.Controller
Logger.Debug($"start sending {bytesToSend}");
_connection.BeginSend(_remoteSendBuffer, 0, bytesToSend, SocketFlags.None,
PipeConnectionSendCallback, new object[] { session, bytesToSend });
IStrategy strategy = _controller.GetCurrentStrategy();
strategy?.UpdateLastRead(_server);
}
else
{
@@ -901,20 +982,23 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
private void PipeConnectionReceiveCallback(IAsyncResult ar)
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
int bytesRead = _connection.EndReceive(ar);
var session = (AsyncSession)ar.AsyncState;
var remote = session.Remote;
AsyncSession session = (AsyncSession)ar.AsyncState;
IProxy remote = session.Remote;
if (bytesRead > 0)
{
@@ -929,8 +1013,7 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
@@ -952,22 +1035,25 @@ namespace Shadowsocks.Controller
return;
}
}
_tcprelay.UpdateOutboundCounter(_server, bytesToSend);
OnOutbound?.Invoke(this, new SSTransmitEventArgs(_server, bytesToSend));
_startSendingTime = DateTime.Now;
session.Remote.BeginSend(_connetionSendBuffer, 0, bytesToSend, SocketFlags.None,
PipeRemoteSendCallback, new object[] { session, bytesToSend });
IStrategy strategy = _controller.GetCurrentStrategy();
strategy?.UpdateLastWrite(_server);
}
private void PipeRemoteSendCallback(IAsyncResult ar)
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
var container = (object[])ar.AsyncState;
var session = (AsyncSession)container[0];
var bytesShouldSend = (int)container[1];
object[] container = (object[])ar.AsyncState;
AsyncSession session = (AsyncSession)container[0];
int bytesShouldSend = (int)container[1];
int bytesSent = session.Remote.EndSend(ar);
int bytesRemaining = bytesShouldSend - bytesSent;
if (bytesRemaining > 0)
@@ -983,8 +1069,7 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
@@ -993,11 +1078,11 @@ namespace Shadowsocks.Controller
{
try
{
var container = (object[])ar.AsyncState;
var session = (AsyncSession)container[0];
var bytesShouldSend = (int)container[1];
var bytesSent = _connection.EndSend(ar);
var bytesRemaining = bytesShouldSend - bytesSent;
object[] container = (object[])ar.AsyncState;
AsyncSession session = (AsyncSession)container[0];
int bytesShouldSend = (int)container[1];
int bytesSent = _connection.EndSend(ar);
int bytesRemaining = bytesShouldSend - bytesSent;
if (bytesRemaining > 0)
{
Logger.Info("reconstruct _remoteSendBuffer to re-send");
@@ -1011,8 +1096,7 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
}

+ 40
- 43
shadowsocks-csharp/Controller/ShadowsocksController.cs View File

@@ -35,7 +35,6 @@ namespace Shadowsocks.Controller
private Configuration _config;
private StrategyManager _strategyManager;
private PrivoxyRunner privoxyRunner;
private GFWListUpdater gfwListUpdater;
private readonly ConcurrentDictionary<Server, Sip003Plugin> _pluginsByServer;
public AvailabilityStatistics availabilityStatistics = AvailabilityStatistics.Instance;
@@ -80,9 +79,9 @@ namespace Shadowsocks.Controller
public event EventHandler<PathEventArgs> PACFileReadyToOpen;
public event EventHandler<PathEventArgs> UserRuleFileReadyToOpen;
public event EventHandler<GFWListUpdater.ResultEventArgs> UpdatePACFromGFWListCompleted;
public event EventHandler<GeositeResultEventArgs> UpdatePACFromGeositeCompleted;
public event ErrorEventHandler UpdatePACFromGFWListError;
public event ErrorEventHandler UpdatePACFromGeositeError;
public event ErrorEventHandler Errored;
@@ -217,25 +216,25 @@ namespace Shadowsocks.Controller
StatisticsStrategyConfiguration.Save(configuration);
}
public bool AskAddServerBySSURL(string ssURL)
{
var dr = MessageBox.Show(I18N.GetString("Import from URL: {0} ?", ssURL), I18N.GetString("Shadowsocks"), MessageBoxButtons.YesNo);
if (dr == DialogResult.Yes)
{
public bool AskAddServerBySSURL(string ssURL)
{
var dr = MessageBox.Show(I18N.GetString("Import from URL: {0} ?", ssURL), I18N.GetString("Shadowsocks"), MessageBoxButtons.YesNo);
if (dr == DialogResult.Yes)
{
if (AddServerBySSURL(ssURL))
{
MessageBox.Show(I18N.GetString("Successfully imported from {0}", ssURL));
return true;
}
}
else
{
MessageBox.Show(I18N.GetString("Failed to import. Please check if the link is valid."));
}
}
return false;
}
}
}
return false;
}
public bool AddServerBySSURL(string ssURL)
{
try
@@ -412,12 +411,9 @@ namespace Shadowsocks.Controller
return $"ss://{url}{tag}";
}
public void UpdatePACFromGFWList()
public void UpdatePACFromGeosite()
{
if (gfwListUpdater != null)
{
gfwListUpdater.UpdatePACFromGFWList(_config);
}
GeositeUpdater.UpdatePACFromGeosite(_config);
}
public void UpdateStatisticsConfiguration(bool enabled)
@@ -486,29 +482,32 @@ namespace Shadowsocks.Controller
ConfigChanged?.Invoke(this, new EventArgs());
}
public void UpdateLatency(Server server, TimeSpan latency)
public void UpdateLatency(object sender, SSTCPConnectedEventArgs args)
{
GetCurrentStrategy()?.UpdateLatency(args.server, args.latency);
if (_config.availabilityStatistics)
{
availabilityStatistics.UpdateLatency(server, (int)latency.TotalMilliseconds);
availabilityStatistics.UpdateLatency(args.server, (int)args.latency.TotalMilliseconds);
}
}
public void UpdateInboundCounter(Server server, long n)
public void UpdateInboundCounter(object sender, SSTransmitEventArgs args)
{
Interlocked.Add(ref _inboundCounter, n);
GetCurrentStrategy()?.UpdateLastRead(args.server);
Interlocked.Add(ref _inboundCounter, args.length);
if (_config.availabilityStatistics)
{
availabilityStatistics.UpdateInboundCounter(server, n);
availabilityStatistics.UpdateInboundCounter(args.server, args.length);
}
}
public void UpdateOutboundCounter(Server server, long n)
public void UpdateOutboundCounter(object sender, SSTransmitEventArgs args)
{
Interlocked.Add(ref _outboundCounter, n);
GetCurrentStrategy()?.UpdateLastWrite(args.server);
Interlocked.Add(ref _outboundCounter, args.length);
if (_config.availabilityStatistics)
{
availabilityStatistics.UpdateOutboundCounter(server, n);
availabilityStatistics.UpdateOutboundCounter(args.server, args.length);
}
}
@@ -524,15 +523,15 @@ namespace Shadowsocks.Controller
privoxyRunner = privoxyRunner ?? new PrivoxyRunner();
_pacDaemon = _pacDaemon ?? new PACDaemon();
_pacDaemon = _pacDaemon ?? new PACDaemon(_config);
_pacDaemon.PACFileChanged += PacDaemon_PACFileChanged;
_pacDaemon.UserRuleFileChanged += PacDaemon_UserRuleFileChanged;
_pacServer = _pacServer ?? new PACServer(_pacDaemon);
_pacServer.UpdatePACURL(_config); // So PACServer works when system proxy disabled.
gfwListUpdater = gfwListUpdater ?? new GFWListUpdater();
gfwListUpdater.UpdateCompleted += PacServer_PACUpdateCompleted;
gfwListUpdater.Error += PacServer_PACUpdateError;
GeositeUpdater.ResetEvent();
GeositeUpdater.UpdateCompleted += PacServer_PACUpdateCompleted;
GeositeUpdater.Error += PacServer_PACUpdateError;
availabilityStatistics.UpdateConfiguration(this);
_tcpListener?.Stop();
@@ -553,6 +552,11 @@ namespace Shadowsocks.Controller
privoxyRunner.Start(_config);
TCPRelay tcpRelay = new TCPRelay(this, _config);
tcpRelay.OnConnected += UpdateLatency;
tcpRelay.OnInbound += UpdateInboundCounter;
tcpRelay.OnOutbound += UpdateOutboundCounter;
tcpRelay.OnFailed += (o, e) => GetCurrentStrategy()?.SetFailure(e.server);
UDPRelay udpRelay = new UDPRelay(this);
_tcpListener = new TCPListener(_config, new List<IStreamService>
{
@@ -612,27 +616,20 @@ namespace Shadowsocks.Controller
UpdateSystemProxy();
}
private void PacServer_PACUpdateCompleted(object sender, GFWListUpdater.ResultEventArgs e)
private void PacServer_PACUpdateCompleted(object sender, GeositeResultEventArgs e)
{
UpdatePACFromGFWListCompleted?.Invoke(this, e);
UpdatePACFromGeositeCompleted?.Invoke(this, e);
}
private void PacServer_PACUpdateError(object sender, ErrorEventArgs e)
{
UpdatePACFromGFWListError?.Invoke(this, e);
UpdatePACFromGeositeError?.Invoke(this, e);
}
private static readonly IEnumerable<char> IgnoredLineBegins = new[] { '!', '[' };
private void PacDaemon_UserRuleFileChanged(object sender, EventArgs e)
{
if (!File.Exists(Utils.GetTempPath("gfwlist.txt")))
{
UpdatePACFromGFWList();
}
else
{
GFWListUpdater.MergeAndWritePACFile(FileManager.NonExclusiveReadAllText(Utils.GetTempPath("gfwlist.txt")));
}
GeositeUpdater.MergeAndWritePACFile(_config.geositeGroup, _config.geositeBlacklistMode);
UpdateSystemProxy();
}


+ 4
- 0
shadowsocks-csharp/Data/abp.js View File

@@ -786,6 +786,10 @@ function FindProxyForURL(url, host) {
if (userrulesMatcher.matchesAny(url, host) instanceof WhitelistFilter) {
return direct;
}
// Hack for Geosite, it provides a whitelist...
if (defaultMatcher.matchesAny(url, host) instanceof WhitelistFilter) {
return direct;
}
if (defaultMatcher.matchesAny(url, host) instanceof BlockingFilter) {
return proxy;
}


+ 0
- 7250
shadowsocks-csharp/Data/default-abp-rule.js
File diff suppressed because it is too large
View File


+ 4983
- 0
shadowsocks-csharp/Data/dlc.dat
File diff suppressed because it is too large
View File


+ 34
- 34
shadowsocks-csharp/Data/i18n.csv View File

@@ -12,22 +12,22 @@ Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks,Shadowso
,,,,,,
System Proxy,Системный прокси-сервер,系统代理,系統代理,システムプロキシ,시스템 프록시,Proxy système
Disable,Отключен,禁用,禁用,無効,비활성화,Désactiver
PAC,Сценарий настройки (PAC),PAC 模式,PAC 模式,PAC,PAC,PAC
PAC,Сценарий настройки (PAC),PAC 模式,PAC 模式,PAC,프록시 자동 구성 (PAC),PAC
Global,Для всей системы,全局模式,全局模式,全般,전역,Global
Servers,Серверы,服务器,伺服器,サーバー,서버,Serveurs
Edit Servers...,Редактировать серверы…,编辑服务器...,編輯伺服器...,サーバーの編集...,서버 수정…,Éditer serveurs…
Statistics Config...,Настройки статистики…,统计配置...,統計設定檔...,統計情報の設定...,통계 설정,Configuration des statistiques…
Start on Boot,Автозагрузка,开机启动,開機啟動,システムと同時に起動,시스템 시작 시에 시작하기,Démarrage automatique
Associate ss:// Links,Ассоциированный ss:// Ссылки,关联 ss:// 链接,關聯 ss:// 鏈接,,,
Associate ss:// Links,Ассоциированный ss:// Ссылки,关联 ss:// 链接,關聯 ss:// 鏈接,,ss:// 링크 연결,
Forward Proxy...,Прямой прокси…,正向代理设置...,正向 Proxy 設定...,フォワードプロキシの設定...,포워드 프록시,Forward-proxy…
Allow other Devices to connect,Общий доступ к подключению,允许其他设备连入,允許其他裝置連入,他のデバイスからの接続を許可する,다른 기기에서 연결 허용,Autoriser d'autres appareils à se connecter
Local PAC,Локальный PAC,使用本地 PAC,使用本機 PAC,ローカル PAC,로컬 PAC,PAC local
Online PAC,Удаленный PAC,使用在线 PAC,使用線上 PAC,オンライン PAC,온라인 PAC,PAC en ligne
Edit Local PAC File...,Редактировать локальный PAC…,编辑本地 PAC 文件...,編輯本機 PAC 檔案...,ローカル PAC ファイルの編集...,로컬 PAC 파일 수정,Modifier le fichier PAC local ...
Update Local PAC from GFWList,Обновить локальный PAC из GFWList,从 GFWList 更新本地 PAC,從 GFWList 更新本機 PAC,GFWList からローカル PAC を更新,GFWList에서 로컬 PAC 파일 업데이트,Mettre à jour le PAC local à partir de GFWList
Edit User Rule for GFWList...,Редактировать свои правила для GFWList,编辑 GFWList 的用户规则...,編輯 GFWList 的使用者規則...,ユーザールールの編集...,GFWList 사용자 수정,Modifier la règle utilisateur pour GFWList ...
Secure Local PAC,Безопасный URL локального PAC,保护本地 PAC,安全本機 PAC,ローカル PAC を保護,로컬 PAC 암호화,Sécuriser PAC local
Copy Local PAC URL,Копировать URL локального PAC,复制本地 PAC 网址,複製本機 PAC 網址,ローカル PAC URL をコピー,로컬 PAC 파일 URL 복사,Copier l'URL du PAC local
Local PAC,Локальный PAC,使用本地 PAC,使用本機 PAC,ローカル PAC,로컬 프록시 자동 구성,PAC local
Online PAC,Удаленный PAC,使用在线 PAC,使用線上 PAC,オンライン PAC,온라인 프록시 자동 구성,PAC en ligne
Edit Local PAC File...,Редактировать локальный PAC…,编辑本地 PAC 文件...,編輯本機 PAC 檔案...,ローカル PAC ファイルの編集...,로컬 프록시 자동 구성 파일 수정,Modifier le fichier PAC local ...
Update Local PAC from Geosite,Обновить локальный PAC из Geosite,从 Geosite 更新本地 PAC,從 Geosite 更新本機 PAC,Geosite からローカル PAC を更新,Geosite에서 로컬 프록시 자동 구성 파일 업데이트,Mettre à jour le PAC local à partir de Geosite
Edit User Rule for Geosite...,Редактировать свои правила для Geosite,编辑 Geosite 的用户规则...,編輯 Geosite 的使用者規則...,ユーザールールの編集...,Geosite 사용자 수정,Modifier la règle utilisateur pour Geosite ...
Secure Local PAC,Безопасный URL локального PAC,保护本地 PAC,安全本機 PAC,ローカル PAC を保護,로컬 프록시 자동 구성 파일 암호화,Sécuriser PAC local
Copy Local PAC URL,Копировать URL локального PAC,复制本地 PAC 网址,複製本機 PAC 網址,ローカル PAC URL をコピー,로컬 프록시 자동 구성 파일 URL 복사,Copier l'URL du PAC local
Share Server Config...,Поделиться конфигурацией сервера…,分享服务器配置...,分享伺服器設定檔...,サーバーの設定を共有...,서버 설정 공유,Partager la configuration du serveur ...
Scan QRCode from Screen...,Сканировать QRCode с экрана…,扫描屏幕上的二维码...,掃描螢幕上的 QR 碼...,画面から QR コードをスキャン...,화면에서 QR코드 스캔,Scanner le QRCode à partir de l'écran ...
Import URL from Clipboard...,Импорт адреса из буфера обмена…,从剪贴板导入URL...,從剪貼簿匯入 URL...,クリップボードから URL をインポート...,클립보드에서 URL 가져오기…,Importer l'URL du presse-papiers ...
@@ -66,17 +66,17 @@ Plugin Options,Опции плагина,插件选项,外掛程式選項,プラ
Need Plugin Argument,Требуются аргументы,需要命令行参数,,,플러그인 인자가 필요함,Besoin d'un argument de plugin
Plugin Arguments,Аргументы,插件参数,外掛程式參數,プラグインの引数,플러그인 인자,Arguments du plugin
Proxy Port,Порт прокси,代理端口,Proxy 連接埠,プロキシポート,프록시 포트,Port proxy
Portable Mode,Переносимый режим,便携模式,便攜模式,ポータブルモード,포터블(Portable) 모드,Mode portable
Restart required,Требуется перезапуск программы,需要重新启动SS,需要重新啟動SS,再起動SSが必要,재시작 필요함,Redémarrage nécessaire
Portable Mode,Переносимый режим,便携模式,便攜模式,ポータブルモード,포터블 모드,Mode portable
Restart required,Требуется перезапуск программы,需要重新启动SS,需要重新啟動SS,再起動SSが必要,재시작이 필요합니다,Redémarrage nécessaire
Remarks,Примечания,备注,註解,付記,알림,Remarques
Timeout(Sec),Таймаут(сек),超时(秒),逾時 (秒),タイムアウト (秒),시간초과(Timeout) (초),Délai d'attente(sec)
Timeout(Sec),Таймаут(сек),超时(秒),逾時 (秒),タイムアウト (秒),시간 초과 (초),Délai d'attente(sec)
OK,ОК,确定,確定,OK,확인,OK
Cancel,Отмена,取消,取消,キャンセル,취소,Annuler
Apply,Применить,应用,應用,適用,적용,Appliquer
New server,Новый сервер,未配置的服务器,新伺服器,新規サーバー,새 서버,Nouveau serveur
Move &Up,Выше,上移(&U),上移 (&U),上に移動 (&U),위로 (&U),Monter
Move D&own,Ниже,下移(&O),下移 (&O),下に移動 (&O),아래로 (&O),Descendre
deprecated,Устаревшее,不推荐,不推薦,非推奨,폐기됨(deprecated),Obsolète
deprecated,Устаревшее,不推荐,不推薦,非推奨,더 이상 사용되지 않음,Obsolète
"Encryption method {0} not exist, will replace with {1}",,加密方法{0}不存在,将使用{1}代替,,,{0} 암호화 방식이 존재하지 않으므로 {1}로 대체될 것입니다.,"Méthode de chiffrement {0} n'existe pas, sera remplacée par {1}"
,,,,,,
#Statistics Config,,,,,,
@@ -116,8 +116,8 @@ Use Proxy,Использовать прокси,使用代理,使用 Proxy,プロ
Proxy Type,Тип прокси,代理类型,Proxy 類型,プロキシの種類,프록시 종류,Type de proxy
Proxy Addr,Адрес прокси,代理地址,Proxy 位址,プロキシアドレス,프록시 주소,Adresse de proxy
Proxy Port,Порт прокси,代理端口,Proxy 連接埠,プロキシポート,프록시 포트,Port de proxy
"If server has a plugin, proxy will not be used","Если сервер использует плагины, прокси НЕ будет использоваться",若服务器含有插件,代理将不被使用,若伺服器含有外掛程式,Proxy 將不被使用,サーバーにプラグインがある場合、プロキシは利用されません,"만약 서버가 플러그인이 있다면, 프록시는용되지 않을 것입니다.","Si le serveur a un plugin, le proxy ne sera pas utilisé"
Use Auth,Требуется авторизация,使用认证,使用認證,認証を利用する,서버 증명(Auth) 사용,Utiliser l'authentification
"If server has a plugin, proxy will not be used","Если сервер использует плагины, прокси НЕ будет использоваться",若服务器含有插件,代理将不被使用,若伺服器含有外掛程式,Proxy 將不被使用,サーバーにプラグインがある場合、プロキシは利用されません,서버에 플러그인이 설치 되어 있는 경우 프록시를 사용할 수 없습니다.,"Si le serveur a un plugin, le proxy ne sera pas utilisé"
Use Auth,Требуется авторизация,使用认证,使用認證,認証を利用する,서버 증 사용,Utiliser l'authentification
User Name,Пользователь,用户名,認證用戶,認証ユーザ,사용자 이름,Nom d'utilisateur
Auth Pwd,Пароль,认证密码,認證口令,認証パスワード,비밀번호,Mot de passe d'authentification
,,,,,,
@@ -142,9 +142,9 @@ QRCode and URL,QRCode и URL,二维码与 URL,QR 碼與 URL,QR コードと URL,
,,,,,,
# PAC Url Form,,,,,,
,,,,,,
Edit Online PAC URL,Изменение URL удаленного PAC,编辑在线 PAC 网址,編輯線上 PAC 網址,オンライン PAC URL の編集,온라인 PAC URL 수정,Modifier l'URL du PAC en ligne
Edit Online PAC URL...,Редактировать URL удаленного PAC…,编辑在线 PAC 网址...,編輯線上 PAC 網址...,オンライン PAC URL の編集...,온라인 PAC URL 수정…,Modifier l'URL du PAC en ligne ...
Please input PAC Url,Введите URL адрес для PAC-файла,请输入 PAC 网址,請輸入 PAC 網址,PAC URLを入力して下さい,PAC URL을 입력하세요,Veuillez saisir l'URL PAC
Edit Online PAC URL,Изменение URL удаленного PAC,编辑在线 PAC 网址,編輯線上 PAC 網址,オンライン PAC URL の編集,온라인 프록시 자동 구성 URL 수정,Modifier l'URL du PAC en ligne
Edit Online PAC URL...,Редактировать URL удаленного PAC…,编辑在线 PAC 网址...,編輯線上 PAC 網址...,オンライン PAC URL の編集...,온라인 프록시 자동 구성 URL 수정…,Modifier l'URL du PAC en ligne ...
Please input PAC Url,Введите URL адрес для PAC-файла,请输入 PAC 网址,請輸入 PAC 網址,PAC URLを入力して下さい,프록시 자동 구성 URL을 입력하세요,Veuillez saisir l'URL PAC
,,,,,,
# HotkeySettings Form,,,,,,
,,,,,,
@@ -164,7 +164,7 @@ Port {0} already in use,Порт {0} уже используется,端口 {0}
Port {0} is reserved by system,Порт {0} зарезервирован системой,端口 {0} 是系统保留端口,連接埠號碼 {0} 由系統保留, ポート番号 {0} はシステムによって予約されています,{0}번 포트는 시스템에서 사용 중입니다.,Port {0} réservé par le système
Invalid server address,Неверный адрес сервера,非法服务器地址,無效伺服器位址,サーバーアドレスが無効です。,올바르지 않은 서버 주소입니다.,Adresse de serveur non valide
Illegal port number format,Неверный числовой формат порта,非法端口格式,無效連接埠號碼格式,ポート番号のフォーマットが無効です。,올바르지 않은 포트 번호 형식입니다.,Format de numéro de port illégal
Illegal timeout format,Неверный формат таймаута,非法超时格式,無效逾時格式,タイムアウト値のフォーマットが無効です。,올바르지 않은 시간초과(Timeout) 형식입니다.,Format de délai d'attente illégal
Illegal timeout format,Неверный формат таймаута,非法超时格式,無效逾時格式,タイムアウト値のフォーマットが無効です。,올바르지 않은 시간 초과 형식입니다.,Format de délai d'attente illégal
Server IP can not be blank,IP-адрес сервера не может быть пустым,服务器 IP 不能为空,伺服器 IP 不能為空,サーバー IP が指定されていません。,서버 IP는 비어있으면 안됩니다.,L'adresse IP du serveur ne peut pas être vide
Password can not be blank,Пароль не может быть пустым,密码不能为空,密碼不能為空,パスワードが指定されていません。,비밀번호는 비어있으면 안됩니다.,Le mot de passe ne peut pas être vide
Port out of range,Порт выходит за допустимый диапазон,端口超出范围,連接埠號碼超出範圍,ポート番号は範囲外です。,올바른 포트 범위가 아닙니다.,Port hors de portée
@@ -176,9 +176,9 @@ Shadowsocks is here,Shadowsocks находится здесь,Shadowsocks 在这
You can turn on/off Shadowsocks in the context menu,Вы можете управлять Shadowsocks из контекстного меню,可以在右键菜单中开关 Shadowsocks,可以在右鍵選項單中開關 Shadowsocks,コンテキストメニューを使って、Shadowsocks を有効または無効にすることができます。,프로그램 메뉴에서 Shadowsocks를 끄고 켤 수 있습니다.,Vous pouvez activer / désactiver Shadowsocks dans le menu contextuel
System Proxy Enabled,Системный прокси включен,系统代理已启用,系統 Proxy 已啟用,システム プロキシが有効です。,시스템 프록시가 활성화되었습니다.,Proxy système activé
System Proxy Disabled,Системный прокси отключен,系统代理未启用,系統 Proxy 未啟用,システム プロキシが無効です。,시스템 프록시가 비활성화되었습니다.,Proxy système désactivé
Failed to update PAC file ,Не удалось обновить PAC файл,更新 PAC 文件失败,更新 PAC 檔案失敗,PAC の更新に失敗しました。,PAC 파일을 업데이트하는데 실패했습니다.,Impossible de mettre à jour le fichier PAC
PAC updated,PAC файл обновлен,更新 PAC 成功,更新 PAC 成功,PAC を更新しました。,PAC 파일이 업데이트되었습니다.,PAC mis à jour
No updates found. Please report to GFWList if you have problems with it.,Обновлений не найдено. Сообщите авторам GFWList если у вас возникли проблемы.,未发现更新。如有问题请提交给 GFWList。,未發現更新。如有問題請報告至 GFWList。,お使いのバージョンは最新です。問題がある場合は、GFWList に報告して下さい。,사용 가능한 업데이트를 찾지 못했습니다. 문제가 있다면 GFWList로 전송해주세요.,Aucune mise à jour trouvée. Veuillez signaler à GFWList si vous avez des problèmes concernant.
Failed to update PAC file ,Не удалось обновить PAC файл,更新 PAC 文件失败,更新 PAC 檔案失敗,PAC の更新に失敗しました。,프록시 자동 구성 파일을 업데이트하는데 실패했습니다.,Impossible de mettre à jour le fichier PAC
PAC updated,PAC файл обновлен,更新 PAC 成功,更新 PAC 成功,PAC を更新しました。,프록시 자동 구성 파일이 업데이트되었습니다.,PAC mis à jour
No updates found. Please report to Geosite if you have problems with it.,Обновлений не найдено. Сообщите авторам Geosite если у вас возникли проблемы.,未发现更新。如有问题请提交给 Geosite。,未發現更新。如有問題請報告至 Geosite。,お使いのバージョンは最新です。問題がある場合は、Geosite に報告して下さい。,사용 가능한 업데이트를 찾지 못했습니다. 문제가 있다면 Geosite로 전송해주세요.,Aucune mise à jour trouvée. Veuillez signaler à Geosite si vous avez des problèmes concernant.
No QRCode found. Try to zoom in or move it to the center of the screen.,QRCode не обнаружен. Попробуйте увеличить изображение или переместить его в центр экрана.,未发现二维码,尝试把它放大或移动到靠近屏幕中间的位置,未發現 QR 碼,嘗試把它放大或移動到靠近熒幕中間的位置,QR コードが見つかりませんでした。コードを大きくするか、画面の中央に移動して下さい。,QR코드를 찾을 수 없습니다. 가운데로 화면을 이동시키거나 확대해보세요.,Aucun QRCode trouvé. Essayez de zoomer ou de le déplacer vers le centre de l'écran.
Shadowsocks is already running.,Shadowsocks уже запущен.,Shadowsocks 已经在运行。,Shadowsocks 已經在執行。,Shadowsocks 実行中,Shadowsocks가 이미 실행 중입니다.,Shadowsocks est déjà en cours d'exécution.
Find Shadowsocks icon in your notify tray.,Значок Shadowsocks можно найти в области уведомлений.,请在任务栏里寻找 Shadowsocks 图标。,請在工作列裡尋找 Shadowsocks 圖示。,通知領域には Shadowsocks のアイコンがあります。,트레이에서 Shadowsocks를 찾아주세요.,Trouvez l'icône Shadowsocks dans votre barre de notification.
@@ -190,25 +190,25 @@ Successfully imported from {0},Успешно импортировано из {0
Failed to import. Please check if the link is valid.,,导入失败,请检查链接是否有效。,導入失敗,請檢查鏈接是否有效。,,,
System Proxy On: ,Системный прокси:,系统代理已启用:,系統 Proxy 已啟用:,システム プロキシが有効:,시스템 프록시 활성화됨: ,Proxy système activé:
Running: Port {0},Запущен на порту {0},正在运行:端口 {0},正在執行:連接埠號碼 {0},実行中:ポート {0},실행 중: 포트 {0}번,En cours d'exécution: port {0}
"Unexpected error, shadowsocks will exit. Please report to","Непредвиденная ошибка, пожалуйста сообщите на",非预期错误,Shadowsocks将退出。请提交此错误到,非預期錯誤,Shadowsocks 將結束。請報告此錯誤至,予想外のエラーが発生したため、Shadowsocks を終了します。詳しくは下記までお問い合わせ下さい:,알 수 없는 오류로 Shadowsocks가 종료될 것입니다. 오류를 제보해주세요:,Shadowsocks va quitter en présence d/érreur inattendue. Veuillez signaler à
"Unsupported operating system, use Windows Vista at least.","Операционная система не поддерживается, минимальные системные требования: Windows Vista или выше.",不支持的操作系统版本,最低需求为Windows Vista。,不支援的作業系統版本,最低需求為 Windows Vista。,お使いの OS はサポートされていません。Windows Vista 以降の OS で実行して下さい。,"지원하지 않는 운영체제입니다, 최소한 Windows Vista가 필요합니다.","Système d'exploitation incompatible, veuillez utiliser Windows Vista ou ultérieure."
"Unsupported .NET Framework, please update to {0} or later.","Версия .NET Framework не поддерживается, минимальные системные требования: {0} или выше.",当前 .NET Framework 版本过低,请升级至{0}或更新版本。,目前 .NET Framework 版本過低,最低需求為{0}。,お使いの .NET Framework はサポートされていません。{0} 以降のバンジョーをインストールして下さい。,"지원하지 않는 .NET 프레임워크입니다, {0} 또는 상위 버전으로 업데이트해주세요.",".NET Framework incompatible, veuillez mettre à jour vers {0} ou ultérieure."
"Unexpected error, shadowsocks will exit. Please report to","Непредвиденная ошибка, пожалуйста сообщите на",非预期错误,Shadowsocks将退出。请提交此错误到,非預期錯誤,Shadowsocks 將結束。請報告此錯誤至,予想外のエラーが発生したため、Shadowsocks を終了します。詳しくは下記までお問い合わせ下さい:,알 수 없는 오류로 Shadowsocks가 종료될 것입니다. 오류를 여기로 제보해주세요:,Shadowsocks va quitter en présence d/érreur inattendue. Veuillez signaler à
"Unsupported operating system, use Windows Vista at least.","Операционная система не поддерживается, минимальные системные требования: Windows Vista или выше.",不支持的操作系统版本,最低需求为Windows Vista。,不支援的作業系統版本,最低需求為 Windows Vista。,お使いの OS はサポートされていません。Windows Vista 以降の OS で実行して下さい。,지원하지 않는 운영체제입니다. 최소 Windows Vista가 필요합니다.,"Système d'exploitation incompatible, veuillez utiliser Windows Vista ou ultérieure."
"Unsupported .NET Framework, please update to {0} or later.","Версия .NET Framework не поддерживается, минимальные системные требования: {0} или выше.",当前 .NET Framework 版本过低,请升级至{0}或更新版本。,目前 .NET Framework 版本過低,最低需求為{0}。,お使いの .NET Framework はサポートされていません。{0} 以降のバンジョーをインストールして下さい。,지원하지 않는 .NET 프레임워크입니다. {0} 또는 상위 버전으로 업데이트해주세요.,".NET Framework incompatible, veuillez mettre à jour vers {0} ou ultérieure."
Proxy request failed,Не удалось выполнить запрос,代理请求失败,Proxy 要求失敗,プロキシ要求が失敗しました。,프록시 요청에 실패했습니다.,Échec de la demande de proxy
Proxy handshake failed,Не удалось выполнить хэндшейк,代理握手失败,Proxy 交握失敗,プロキシ ハンドシェイクに失敗しました。,프록시 핸드쉐이크에 실패했습니다.,Échec de la prise de contact par proxy
Register hotkey failed,Не удалось применить настройки горячих клавиш,注册快捷键失败,註冊快速鍵失敗,ホットキーの登錄に失敗しました。,단축키 등록에 실패했습니다.,Échec de l'enregistrement du raccourci clavier
Cannot parse hotkey: {0},Не удалось распознать следующие горячие клавиши: {0},解析快捷键失败: {0},剖析快速鍵失敗: {0},ホットキーを解析できません: {0},단축키를 해석할 수 없습니다: {0},Impossible d'analyser le raccourci clavier: {0}
"Timeout is invalid, it should not exceed {0}",Таймаут не может превышать значение {0},超时无效,不应超过 {0},逾時無效,不應超過 {0},タイムアウト値が無効です。{0} 以下の値を指定して下さい。,"올바르지 않은 시간초과(Timeout) 설정입니다, {0}을 초과하지 않아야 합니다.","Le délai d'attente invalide, il ne doit pas dépasser {0}"
"Timeout is invalid, it should not exceed {0}",Таймаут не может превышать значение {0},超时无效,不应超过 {0},逾時無效,不應超過 {0},タイムアウト値が無効です。{0} 以下の値を指定して下さい。,올바르지 않은 시간 초과 설정입니다. {0}을 초과하지 않아야 합니다.,"Le délai d'attente invalide, il ne doit pas dépasser {0}"
Cannot find the plugin program file,Файл плагина не найден,找不到插件程序文件,找不到外掛程式文件,,플러그인 프로그램 파일을 찾을 수 없습니다.,Impossible de trouver le fichier du programme du plugin
,,,,,,
Operation failure,Операция завершилась неудачей,操作失败,,,작업에 실패했습니다.,Operation failure
Auto save failed,Автоматическое сохранение не удалось,自动保存失败,,,자동 저장에 실패했습니다.,Échec de l'enregistrement automatique
Whether to discard unconfigured servers,Внесенные изменения будут утеряны,是否丢弃未配置的服务器,,,완전하지 않은 서버 설정 변경 사항을 폐기하시겠습니까?,Eliminer les serveurs non configurés ou non
"Invalid server address, Cannot automatically save or discard changes",Неверный адрес сервера. Невозможно сохранить или отменить изменения,非法服务器地址,无法自动保存,是否丢弃修改,,,"서버 주소가 올바르지 않아 자동저장할 수 없습니다, 변경 사항을 폐기하시겠습니까?","Adresse de serveur invalide, impossible d'enregistrer ou d'annuler automatiquement les modifications"
"Illegal port number format, Cannot automatically save or discard changes",Неверный числовой адрес порта. Невозможно сохранить или отменить изменения,非法端口格式,无法自动保存,是否丢弃修改,,,"포트 번호가 올바르지 않아 자동저장할 수 없습니다, 변경 사항을 폐기하시겠습니까?","Format de numéro de port illégal, impossible d'enregistrer ou d'annuler automatiquement les modifications"
"Password can not be blank, Cannot automatically save or discard changes",Пароль не может быть пустым. Невозможно сохранить или отменить изменения,密码不能为空,无法自动保存,是否丢弃修改,,,"비밀번호가 비어있어 자동저장할 수 없습니다, 변경 사항을 폐기하시겠습니까?","Le mot de passe ne peut pas être vide, impossible d'enregistrer ou d'annuler automatiquement les modifications"
"Illegal timeout format, Cannot automatically save or discard changes",Неверный формат таймаута. Невозможно сохранить или отменить изменения,非法超时格式,无法自动保存,是否丢弃修改,,,"시간초과(Timeout) 형식이 올바르지 않아 자동저장할 수 없습니다, 변경 사항을 폐기하시겠습니까?","Format de délai d'attente illégal, impossible d'enregistrer ou d'annuler automatiquement les modifications"
Whether to discard unconfigured servers,Внесенные изменения будут утеряны,是否丢弃未配置的服务器,,,구성되지 않은 서버 설정 변경 사항을 폐기하시겠습니까?,Eliminer les serveurs non configurés ou non
"Invalid server address, Cannot automatically save or discard changes",Неверный адрес сервера. Невозможно сохранить или отменить изменения,非法服务器地址,无法自动保存,是否丢弃修改,,,"서버 주소가 올바르지 않아 자동 저장 할 수 없습니다, 변경 사항을 폐기하시겠습니까?","Adresse de serveur invalide, impossible d'enregistrer ou d'annuler automatiquement les modifications"
"Illegal port number format, Cannot automatically save or discard changes",Неверный числовой адрес порта. Невозможно сохранить или отменить изменения,非法端口格式,无法自动保存,是否丢弃修改,,,"포트 번호가 올바르지 않아 자동 저장 할 수 없습니다, 변경 사항을 폐기하시겠습니까?","Format de numéro de port illégal, impossible d'enregistrer ou d'annuler automatiquement les modifications"
"Password can not be blank, Cannot automatically save or discard changes",Пароль не может быть пустым. Невозможно сохранить или отменить изменения,密码不能为空,无法自动保存,是否丢弃修改,,,"비밀번호를 입력하지 않아 자동 저장 할 수 없습니다, 변경 사항을 폐기하시겠습니까?","Le mot de passe ne peut pas être vide, impossible d'enregistrer ou d'annuler automatiquement les modifications"
"Illegal timeout format, Cannot automatically save or discard changes",Неверный формат таймаута. Невозможно сохранить или отменить изменения,非法超时格式,无法自动保存,是否丢弃修改,,,시간 초과 형식이 올바르지 않아 자동 저장 할 수 없습니다. 변경 사항을 폐기하시겠습니까?,"Format de délai d'attente illégal, impossible d'enregistrer ou d'annuler automatiquement les modifications"
,,,,,,
"Error occured when process proxy setting, do you want reset current setting and retry?",Произошла ошибка при обработке настроек. Хотите сбросить текущие настройки и попробовать снова?,处理代理设置时发生错误,是否重置当前代理设置并重试?,,,프록시 설정을 처리하는데에 오류가 발생했습니다. 현재 설정을 폐기하고 다시시도하시겠습니까?,Une erreur s'est produite lors du processus de configuration du proxy. Voulez-vous réinitialiser le paramètre actuel et réessayer?
"Error occured when process proxy setting, do you want reset current setting and retry?",Произошла ошибка при обработке настроек. Хотите сбросить текущие настройки и попробовать снова?,处理代理设置时发生错误,是否重置当前代理设置并重试?,,,프록시 설정을 처리하는데에 오류가 발생했습니다. 현재 설정을 폐기하고 다시 시도하시겠습니까?,Une erreur s'est produite lors du processus de configuration du proxy. Voulez-vous réinitialiser le paramètre actuel et réessayer?
"Unrecoverable proxy setting error occured, see log for detail","Произошла серьезная ошибка, подробности можно узнать в журналах",发生不可恢复的代理设置错误,查看日志以取得详情,,,복구 불가능한 프록시 설정 오류가 발생했습니다. 자세한 정보는 로그를 참조하세요.,"Une erreur de paramètre de proxy irrécupérable s'est produite, consultez le journal pour plus de détails"
Auth user can not be blank,Пользователь не может быть пустым,认证用户不能为空,認證用戶不能為空,認証ユーザが指定されていません。,증 정보의 사용자 이름은 비어있을 수 없습니다.,L'utilisateur d'authentification ne peut pas être vide
Auth pwd can not be blank,Пароль не может быть пустым,认证密码不能为空,認證口令不能為空,認証パスワードが指定されていません。,증 정보의 비밀번호는 비어있을 수 없습니다.,Le mot de passe d'authentification ne peut pas être vide
Auth user can not be blank,Пользователь не может быть пустым,认证用户不能为空,認證用戶不能為空,認証ユーザが指定されていません。,증 정보의 사용자 이름은 비어있을 수 없습니다.,L'utilisateur d'authentification ne peut pas être vide
Auth pwd can not be blank,Пароль не может быть пустым,认证密码不能为空,認證口令不能為空,認証パスワードが指定されていません。,증 정보의 비밀번호는 비어있을 수 없습니다.,Le mot de passe d'authentification ne peut pas être vide

+ 32
- 28
shadowsocks-csharp/Model/Configuration.cs View File

@@ -29,7 +29,10 @@ namespace Shadowsocks.Model
public bool portableMode = true;
public bool showPluginOutput;
public string pacUrl;
public string gfwListUrl;
public string geositeUrl;
public string geositeGroup = "geolocation-!cn";
public bool geositeBlacklistMode = true;
public bool useOnlinePac;
public bool secureLocalPac = true;
public bool availabilityStatistics;
@@ -93,10 +96,11 @@ namespace Shadowsocks.Model
public static Configuration Load()
{
Configuration config;
try
{
string configContent = File.ReadAllText(CONFIG_FILE);
Configuration config = JsonConvert.DeserializeObject<Configuration>(configContent);
config = JsonConvert.DeserializeObject<Configuration>(configContent);
config.isDefault = false;
if (UpdateChecker.Asset.CompareVersion(UpdateChecker.Version, config.version ?? "0") > 0)
{
@@ -124,37 +128,12 @@ namespace Shadowsocks.Model
//TODO if remote host(server) do not support IPv6 (or DNS resolve AAAA TYPE record) disable IPv6?
config.proxy.CheckConfig();
try
{
config.nLogConfig = NLogConfig.LoadXML();
switch (config.nLogConfig.GetLogLevel())
{
case NLogConfig.LogLevel.Fatal:
case NLogConfig.LogLevel.Error:
case NLogConfig.LogLevel.Warn:
case NLogConfig.LogLevel.Info:
config.isVerboseLogging = false;
break;
case NLogConfig.LogLevel.Debug:
case NLogConfig.LogLevel.Trace:
config.isVerboseLogging = true;
break;
}
}
catch (Exception e)
{
// todo: route the error to UI since there is no log file in this scenario
logger.Error(e, "Cannot get the log level from NLog config file. Please check if the nlog config file exists with corresponding XML nodes.");
}
return config;
}
catch (Exception e)
{
if (!(e is FileNotFoundException))
logger.LogUsefulException(e);
return new Configuration
config = new Configuration
{
index = 0,
isDefault = true,
@@ -169,6 +148,31 @@ namespace Shadowsocks.Model
hotkey = new HotkeyConfig(),
};
}
try
{
config.nLogConfig = NLogConfig.LoadXML();
switch (config.nLogConfig.GetLogLevel())
{
case NLogConfig.LogLevel.Fatal:
case NLogConfig.LogLevel.Error:
case NLogConfig.LogLevel.Warn:
case NLogConfig.LogLevel.Info:
config.isVerboseLogging = false;
break;
case NLogConfig.LogLevel.Debug:
case NLogConfig.LogLevel.Trace:
config.isVerboseLogging = true;
break;
}
}
catch (Exception e)
{
// todo: route the error to UI since there is no log file in this scenario
logger.Error(e, "Cannot get the log level from NLog config file. Please check if the nlog config file exists with corresponding XML nodes.");
}
return config;
}
public static void Save(Configuration config)


+ 753
- 0
shadowsocks-csharp/Model/Geosite/Geosite.cs View File

@@ -0,0 +1,753 @@
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: geosite.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code

using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
/// <summary>Holder for reflection information generated from geosite.proto</summary>
public static partial class GeositeReflection {

#region Descriptor
/// <summary>File descriptor for geosite.proto</summary>
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
private static pbr::FileDescriptor descriptor;

static GeositeReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"Cg1nZW9zaXRlLnByb3RvIvMBCgxEb21haW5PYmplY3QSIAoEdHlwZRgBIAEo",
"DjISLkRvbWFpbk9iamVjdC5UeXBlEg0KBXZhbHVlGAIgASgJEioKCWF0dHJp",
"YnV0ZRgDIAMoCzIXLkRvbWFpbk9iamVjdC5BdHRyaWJ1dGUaUgoJQXR0cmli",
"dXRlEgsKA2tleRgBIAEoCRIUCgpib29sX3ZhbHVlGAIgASgISAASEwoJaW50",
"X3ZhbHVlGAMgASgDSABCDQoLdHlwZWRfdmFsdWUiMgoEVHlwZRIJCgVQbGFp",
"bhAAEgkKBVJlZ2V4EAESCgoGRG9tYWluEAISCAoERnVsbBADIj0KB0dlb3Np",
"dGUSEgoKZ3JvdXBfbmFtZRgBIAEoCRIeCgdkb21haW5zGAIgAygLMg0uRG9t",
"YWluT2JqZWN0IigKC0dlb3NpdGVMaXN0EhkKB2VudHJpZXMYASADKAsyCC5H",
"ZW9zaXRlYgZwcm90bzM="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::DomainObject), global::DomainObject.Parser, new[]{ "Type", "Value", "Attribute" }, null, new[]{ typeof(global::DomainObject.Types.Type) }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::DomainObject.Types.Attribute), global::DomainObject.Types.Attribute.Parser, new[]{ "Key", "BoolValue", "IntValue" }, new[]{ "TypedValue" }, null, null, null)}),
new pbr::GeneratedClrTypeInfo(typeof(global::Geosite), global::Geosite.Parser, new[]{ "GroupName", "Domains" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::GeositeList), global::GeositeList.Parser, new[]{ "Entries" }, null, null, null, null)
}));
}
#endregion

}
#region Messages
/// <summary>
/// DomainObject for routing decision.
/// </summary>
public sealed partial class DomainObject : pb::IMessage<DomainObject> {
private static readonly pb::MessageParser<DomainObject> _parser = new pb::MessageParser<DomainObject>(() => new DomainObject());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<DomainObject> Parser { get { return _parser; } }

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::GeositeReflection.Descriptor.MessageTypes[0]; }
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DomainObject() {
OnConstruction();
}

partial void OnConstruction();

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DomainObject(DomainObject other) : this() {
type_ = other.type_;
value_ = other.value_;
attribute_ = other.attribute_.Clone();
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DomainObject Clone() {
return new DomainObject(this);
}

/// <summary>Field number for the "type" field.</summary>
public const int TypeFieldNumber = 1;
private global::DomainObject.Types.Type type_ = global::DomainObject.Types.Type.Plain;
/// <summary>
/// DomainObject matching type.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::DomainObject.Types.Type Type {
get { return type_; }
set {
type_ = value;
}
}

/// <summary>Field number for the "value" field.</summary>
public const int ValueFieldNumber = 2;
private string value_ = "";
/// <summary>
/// DomainObject value.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string Value {
get { return value_; }
set {
value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}

/// <summary>Field number for the "attribute" field.</summary>
public const int AttributeFieldNumber = 3;
private static readonly pb::FieldCodec<global::DomainObject.Types.Attribute> _repeated_attribute_codec
= pb::FieldCodec.ForMessage(26, global::DomainObject.Types.Attribute.Parser);
private readonly pbc::RepeatedField<global::DomainObject.Types.Attribute> attribute_ = new pbc::RepeatedField<global::DomainObject.Types.Attribute>();
/// <summary>
/// Attributes of this domain. May be used for filtering.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField<global::DomainObject.Types.Attribute> Attribute {
get { return attribute_; }
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as DomainObject);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(DomainObject other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (Type != other.Type) return false;
if (Value != other.Value) return false;
if(!attribute_.Equals(other.attribute_)) return false;
return Equals(_unknownFields, other._unknownFields);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (Type != global::DomainObject.Types.Type.Plain) hash ^= Type.GetHashCode();
if (Value.Length != 0) hash ^= Value.GetHashCode();
hash ^= attribute_.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (Type != global::DomainObject.Types.Type.Plain) {
output.WriteRawTag(8);
output.WriteEnum((int) Type);
}
if (Value.Length != 0) {
output.WriteRawTag(18);
output.WriteString(Value);
}
attribute_.WriteTo(output, _repeated_attribute_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (Type != global::DomainObject.Types.Type.Plain) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type);
}
if (Value.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Value);
}
size += attribute_.CalculateSize(_repeated_attribute_codec);
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(DomainObject other) {
if (other == null) {
return;
}
if (other.Type != global::DomainObject.Types.Type.Plain) {
Type = other.Type;
}
if (other.Value.Length != 0) {
Value = other.Value;
}
attribute_.Add(other.attribute_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 8: {
Type = (global::DomainObject.Types.Type) input.ReadEnum();
break;
}
case 18: {
Value = input.ReadString();
break;
}
case 26: {
attribute_.AddEntriesFrom(input, _repeated_attribute_codec);
break;
}
}
}
}

#region Nested types
/// <summary>Container for nested types declared in the DomainObject message type.</summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static partial class Types {
/// <summary>
/// Type of domain value.
/// </summary>
public enum Type {
/// <summary>
/// The value is used as is.
/// </summary>
[pbr::OriginalName("Plain")] Plain = 0,
/// <summary>
/// The value is used as a regular expression.
/// </summary>
[pbr::OriginalName("Regex")] Regex = 1,
/// <summary>
/// The value is a root domain.
/// </summary>
[pbr::OriginalName("Domain")] Domain = 2,
/// <summary>
/// The value is a domain.
/// </summary>
[pbr::OriginalName("Full")] Full = 3,
}

public sealed partial class Attribute : pb::IMessage<Attribute> {
private static readonly pb::MessageParser<Attribute> _parser = new pb::MessageParser<Attribute>(() => new Attribute());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<Attribute> Parser { get { return _parser; } }

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::DomainObject.Descriptor.NestedTypes[0]; }
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Attribute() {
OnConstruction();
}

partial void OnConstruction();

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Attribute(Attribute other) : this() {
key_ = other.key_;
switch (other.TypedValueCase) {
case TypedValueOneofCase.BoolValue:
BoolValue = other.BoolValue;
break;
case TypedValueOneofCase.IntValue:
IntValue = other.IntValue;
break;
}

_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Attribute Clone() {
return new Attribute(this);
}

/// <summary>Field number for the "key" field.</summary>
public const int KeyFieldNumber = 1;
private string key_ = "";
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string Key {
get { return key_; }
set {
key_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}

/// <summary>Field number for the "bool_value" field.</summary>
public const int BoolValueFieldNumber = 2;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool BoolValue {
get { return typedValueCase_ == TypedValueOneofCase.BoolValue ? (bool) typedValue_ : false; }
set {
typedValue_ = value;
typedValueCase_ = TypedValueOneofCase.BoolValue;
}
}

/// <summary>Field number for the "int_value" field.</summary>
public const int IntValueFieldNumber = 3;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public long IntValue {
get { return typedValueCase_ == TypedValueOneofCase.IntValue ? (long) typedValue_ : 0L; }
set {
typedValue_ = value;
typedValueCase_ = TypedValueOneofCase.IntValue;
}
}

private object typedValue_;
/// <summary>Enum of possible cases for the "typed_value" oneof.</summary>
public enum TypedValueOneofCase {
None = 0,
BoolValue = 2,
IntValue = 3,
}
private TypedValueOneofCase typedValueCase_ = TypedValueOneofCase.None;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public TypedValueOneofCase TypedValueCase {
get { return typedValueCase_; }
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void ClearTypedValue() {
typedValueCase_ = TypedValueOneofCase.None;
typedValue_ = null;
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as Attribute);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(Attribute other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (Key != other.Key) return false;
if (BoolValue != other.BoolValue) return false;
if (IntValue != other.IntValue) return false;
if (TypedValueCase != other.TypedValueCase) return false;
return Equals(_unknownFields, other._unknownFields);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (Key.Length != 0) hash ^= Key.GetHashCode();
if (typedValueCase_ == TypedValueOneofCase.BoolValue) hash ^= BoolValue.GetHashCode();
if (typedValueCase_ == TypedValueOneofCase.IntValue) hash ^= IntValue.GetHashCode();
hash ^= (int) typedValueCase_;
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (Key.Length != 0) {
output.WriteRawTag(10);
output.WriteString(Key);
}
if (typedValueCase_ == TypedValueOneofCase.BoolValue) {
output.WriteRawTag(16);
output.WriteBool(BoolValue);
}
if (typedValueCase_ == TypedValueOneofCase.IntValue) {
output.WriteRawTag(24);
output.WriteInt64(IntValue);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (Key.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Key);
}
if (typedValueCase_ == TypedValueOneofCase.BoolValue) {
size += 1 + 1;
}
if (typedValueCase_ == TypedValueOneofCase.IntValue) {
size += 1 + pb::CodedOutputStream.ComputeInt64Size(IntValue);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(Attribute other) {
if (other == null) {
return;
}
if (other.Key.Length != 0) {
Key = other.Key;
}
switch (other.TypedValueCase) {
case TypedValueOneofCase.BoolValue:
BoolValue = other.BoolValue;
break;
case TypedValueOneofCase.IntValue:
IntValue = other.IntValue;
break;
}

_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
Key = input.ReadString();
break;
}
case 16: {
BoolValue = input.ReadBool();
break;
}
case 24: {
IntValue = input.ReadInt64();
break;
}
}
}
}

}

}
#endregion

}

public sealed partial class Geosite : pb::IMessage<Geosite> {
private static readonly pb::MessageParser<Geosite> _parser = new pb::MessageParser<Geosite>(() => new Geosite());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<Geosite> Parser { get { return _parser; } }

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::GeositeReflection.Descriptor.MessageTypes[1]; }
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Geosite() {
OnConstruction();
}

partial void OnConstruction();

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Geosite(Geosite other) : this() {
groupName_ = other.groupName_;
domains_ = other.domains_.Clone();
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public Geosite Clone() {
return new Geosite(this);
}

/// <summary>Field number for the "group_name" field.</summary>
public const int GroupNameFieldNumber = 1;
private string groupName_ = "";
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string GroupName {
get { return groupName_; }
set {
groupName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}

/// <summary>Field number for the "domains" field.</summary>
public const int DomainsFieldNumber = 2;
private static readonly pb::FieldCodec<global::DomainObject> _repeated_domains_codec
= pb::FieldCodec.ForMessage(18, global::DomainObject.Parser);
private readonly pbc::RepeatedField<global::DomainObject> domains_ = new pbc::RepeatedField<global::DomainObject>();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField<global::DomainObject> Domains {
get { return domains_; }
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as Geosite);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(Geosite other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (GroupName != other.GroupName) return false;
if(!domains_.Equals(other.domains_)) return false;
return Equals(_unknownFields, other._unknownFields);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (GroupName.Length != 0) hash ^= GroupName.GetHashCode();
hash ^= domains_.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (GroupName.Length != 0) {
output.WriteRawTag(10);
output.WriteString(GroupName);
}
domains_.WriteTo(output, _repeated_domains_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (GroupName.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(GroupName);
}
size += domains_.CalculateSize(_repeated_domains_codec);
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(Geosite other) {
if (other == null) {
return;
}
if (other.GroupName.Length != 0) {
GroupName = other.GroupName;
}
domains_.Add(other.domains_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
GroupName = input.ReadString();
break;
}
case 18: {
domains_.AddEntriesFrom(input, _repeated_domains_codec);
break;
}
}
}
}

}

public sealed partial class GeositeList : pb::IMessage<GeositeList> {
private static readonly pb::MessageParser<GeositeList> _parser = new pb::MessageParser<GeositeList>(() => new GeositeList());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<GeositeList> Parser { get { return _parser; } }

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::GeositeReflection.Descriptor.MessageTypes[2]; }
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GeositeList() {
OnConstruction();
}

partial void OnConstruction();

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GeositeList(GeositeList other) : this() {
entries_ = other.entries_.Clone();
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GeositeList Clone() {
return new GeositeList(this);
}

/// <summary>Field number for the "entries" field.</summary>
public const int EntriesFieldNumber = 1;
private static readonly pb::FieldCodec<global::Geosite> _repeated_entries_codec
= pb::FieldCodec.ForMessage(10, global::Geosite.Parser);
private readonly pbc::RepeatedField<global::Geosite> entries_ = new pbc::RepeatedField<global::Geosite>();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField<global::Geosite> Entries {
get { return entries_; }
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as GeositeList);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(GeositeList other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if(!entries_.Equals(other.entries_)) return false;
return Equals(_unknownFields, other._unknownFields);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
hash ^= entries_.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
entries_.WriteTo(output, _repeated_entries_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
size += entries_.CalculateSize(_repeated_entries_codec);
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(GeositeList other) {
if (other == null) {
return;
}
entries_.Add(other.entries_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
entries_.AddEntriesFrom(input, _repeated_entries_codec);
break;
}
}
}
}

}

#endregion


#endregion Designer generated code

+ 43
- 0
shadowsocks-csharp/Model/Geosite/geosite.proto View File

@@ -0,0 +1,43 @@
syntax = "proto3";

// DomainObject for routing decision.
message DomainObject {
// Type of domain value.
enum Type {
// The value is used as is.
Plain = 0;
// The value is used as a regular expression.
Regex = 1;
// The value is a root domain.
Domain = 2;
// The value is a domain.
Full = 3;
}

// DomainObject matching type.
Type type = 1;

// DomainObject value.
string value = 2;

message Attribute {
string key = 1;

oneof typed_value {
bool bool_value = 2;
int64 int_value = 3;
}
}

// Attributes of this domain. May be used for filtering.
repeated Attribute attribute = 3;
}

message Geosite {
string group_name = 1;
repeated DomainObject domains = 2;
}

message GeositeList{
repeated Geosite entries = 1;
}

+ 17
- 39
shadowsocks-csharp/Properties/Resources.Designer.cs View File

@@ -85,51 +85,29 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// 查找类似 var __USERRULES__ = [];
///var __RULES__ = [
/// &quot;|http://85.17.73.31/&quot;,
/// &quot;||agnesb.fr&quot;,
/// &quot;||akiba-web.com&quot;,
/// &quot;||altrec.com&quot;,
/// &quot;||angela-merkel.de&quot;,
/// &quot;||angola.org&quot;,
/// &quot;||apartmentratings.com&quot;,
/// &quot;||apartments.com&quot;,
/// &quot;||arena.taipei&quot;,
/// &quot;||asianspiss.com&quot;,
/// &quot;||assimp.org&quot;,
/// &quot;||athenaeizou.com&quot;,
/// &quot;||azubu.tv&quot;,
/// &quot;||bankmobilevibe.com&quot;,
/// &quot;||banorte.com&quot;,
/// &quot;||bash-hackers.org&quot;,
/// &quot;||beeg.com&quot;,
/// &quot;||global.bing.com&quot;,
/// &quot;||bloombergview.com&quot;,
/// &quot; [字符串的其余部分被截断]&quot;; 的本地化字符串。
/// 查找 System.Byte[] 类型的本地化资源。
/// </summary>
internal static string default_abp_rule {
internal static byte[] dlc_dat {
get {
return ResourceManager.GetString("default_abp_rule", resourceCulture);
object obj = ResourceManager.GetObject("dlc_dat", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// 查找类似 en,ru-RU,zh-CN,zh-TW,ja
///#Restart program to apply translation,,,,
///#This is comment line,,,,
///#Always keep language name at head of file,,,,
///#Language name is output in log,,,,
///&quot;#You can find it by search &quot;&quot;Current language is:&quot;&quot;&quot;,,,,
///#Please use UTF-8 with BOM encoding so we can edit it in Excel,,,,
///,,,,
///Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks
///,,,,
///#Menu,,,,
///,,,,
///System Proxy,Системный прокси-сервер,系统代理,系統代理,システムプロキシ
///Disable,Отключен,禁用,禁用,無効
///PAC,Сценарий настройки (PAC),PA [字符串的其余部分被截断]&quot;; 的本地化字符串。
/// 查找类似 en,ru-RU,zh-CN,zh-TW,ja,ko,fr
///#Restart program to apply translation,,,,,,
///#This is comment line,,,,,,
///#Always keep language name at head of file,,,,,,
///#Language name is output in log,,,,,,
///&quot;#You can find it by search &quot;&quot;Current language is:&quot;&quot;&quot;,,,,,,
///#Please use UTF-8 with BOM encoding so we can edit it in Excel,,,,,,
///,,,,,,
///Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks
///,,,,,,
///#Menu,,,,,,
///,,,,,,
///System Proxy,Системный прокси-сервер,系统代理,系統代理,システムプロキシ,시스템 프록시,P [字符串的其余部分被截断]&quot;; 的本地化字符串。
/// </summary>
internal static string i18n_csv {
get {


+ 2
- 2
shadowsocks-csharp/Properties/Resources.resx View File

@@ -121,8 +121,8 @@
<data name="abp_js" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Data\abp.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312</value>
</data>
<data name="default_abp_rule" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Data\default-abp-rule.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<data name="dlc_dat" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\data\dlc.dat;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="i18n_csv" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Data\i18n.csv;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>


+ 23
- 23
shadowsocks-csharp/View/MenuViewController.cs View File

@@ -48,7 +48,7 @@ namespace Shadowsocks.View
private ToolStripMenuItem localPACItem;
private ToolStripMenuItem onlinePACItem;
private ToolStripMenuItem editLocalPACItem;
private ToolStripMenuItem updateFromGFWListItem;
private ToolStripMenuItem updateFromGeositeItem;
private ToolStripMenuItem editGFWUserRuleItem;
private ToolStripMenuItem editOnlinePACItem;
private ToolStripMenuItem secureLocalPacUrlToggleItem;
@@ -88,8 +88,8 @@ namespace Shadowsocks.View
controller.ShowPluginOutputChanged += controller_ShowPluginOutputChanged;
controller.EnableGlobalChanged += controller_EnableGlobalChanged;
controller.Errored += controller_Errored;
controller.UpdatePACFromGFWListCompleted += controller_UpdatePACFromGFWListCompleted;
controller.UpdatePACFromGFWListError += controller_UpdatePACFromGFWListError;
controller.UpdatePACFromGeositeCompleted += controller_UpdatePACFromGeositeCompleted;
controller.UpdatePACFromGeositeError += controller_UpdatePACFromGeositeError;
_notifyIcon = new NotifyIcon();
UpdateTrayIconAndNotifyText();
@@ -310,8 +310,8 @@ namespace Shadowsocks.View
this.onlinePACItem = CreateToolStripMenuItem("Online PAC", new EventHandler(this.OnlinePACItem_Click)),
new ToolStripSeparator(),
this.editLocalPACItem = CreateToolStripMenuItem("Edit Local PAC File...", new EventHandler(this.EditPACFileItem_Click)),
this.updateFromGFWListItem = CreateToolStripMenuItem("Update Local PAC from GFWList", new EventHandler(this.UpdatePACFromGFWListItem_Click)),
this.editGFWUserRuleItem = CreateToolStripMenuItem("Edit User Rule for GFWList...", new EventHandler(this.EditUserRuleFileForGFWListItem_Click)),
this.updateFromGeositeItem = CreateToolStripMenuItem("Update Local PAC from Geosite", new EventHandler(this.UpdatePACFromGeositeItem_Click)),
this.editGFWUserRuleItem = CreateToolStripMenuItem("Edit User Rule for Geosite...", new EventHandler(this.EditUserRuleFileForGeositeItem_Click)),
this.secureLocalPacUrlToggleItem = CreateToolStripMenuItem("Secure Local PAC", new EventHandler(this.SecureLocalPacUrlToggleItem_Click)),
CreateToolStripMenuItem("Copy Local PAC URL", new EventHandler(this.CopyLocalPacUrlItem_Click)),
this.editOnlinePACItem = CreateToolStripMenuItem("Edit Online PAC URL...", new EventHandler(this.UpdateOnlinePACURLItem_Click)),
@@ -390,17 +390,17 @@ namespace Shadowsocks.View
_notifyIcon.ShowBalloonTip(timeout);
}
void controller_UpdatePACFromGFWListError(object sender, System.IO.ErrorEventArgs e)
void controller_UpdatePACFromGeositeError(object sender, System.IO.ErrorEventArgs e)
{
ShowBalloonTip(I18N.GetString("Failed to update PAC file"), e.GetException().Message, ToolTipIcon.Error, 5000);
logger.LogUsefulException(e.GetException());
}
void controller_UpdatePACFromGFWListCompleted(object sender, GFWListUpdater.ResultEventArgs e)
void controller_UpdatePACFromGeositeCompleted(object sender, GeositeResultEventArgs e)
{
string result = e.Success
? I18N.GetString("PAC updated")
: I18N.GetString("No updates found. Please report to GFWList if you have problems with it.");
: I18N.GetString("No updates found. Please report to Geosite if you have problems with it.");
ShowBalloonTip(I18N.GetString("Shadowsocks"), result, ToolTipIcon.Info, 1000);
}
@@ -447,7 +447,7 @@ namespace Shadowsocks.View
VerboseLoggingToggleItem.Checked = config.isVerboseLogging;
ShowPluginOutputToggleItem.Checked = config.showPluginOutput;
AutoStartupItem.Checked = AutoStartup.Check();
ProtocolHandlerItem.Checked = ProtocolHandler.Check();
ProtocolHandlerItem.Checked = ProtocolHandler.Check();
onlinePACItem.Checked = onlinePACItem.Enabled && config.useOnlinePac;
localPACItem.Checked = !onlinePACItem.Checked;
secureLocalPacUrlToggleItem.Checked = config.secureLocalPac;
@@ -705,12 +705,12 @@ namespace Shadowsocks.View
controller.TouchPACFile();
}
private void UpdatePACFromGFWListItem_Click(object sender, EventArgs e)
private void UpdatePACFromGeositeItem_Click(object sender, EventArgs e)
{
controller.UpdatePACFromGFWList();
controller.UpdatePACFromGeosite();
}
private void EditUserRuleFileForGFWListItem_Click(object sender, EventArgs e)
private void EditUserRuleFileForGeositeItem_Click(object sender, EventArgs e)
{
controller.TouchUserRuleFile();
}
@@ -867,16 +867,16 @@ namespace Shadowsocks.View
{
MessageBox.Show(I18N.GetString("Failed to update registry"));
}
LoadCurrentConfiguration();
LoadCurrentConfiguration();
}
private void ProtocolHandlerItem_Click(object sender, EventArgs e)
{
ProtocolHandlerItem.Checked = !ProtocolHandlerItem.Checked;
if (!ProtocolHandler.Set(ProtocolHandlerItem.Checked))
{
MessageBox.Show(I18N.GetString("Failed to update registry"));
}
LoadCurrentConfiguration();
private void ProtocolHandlerItem_Click(object sender, EventArgs e)
{
ProtocolHandlerItem.Checked = !ProtocolHandlerItem.Checked;
if (!ProtocolHandler.Set(ProtocolHandlerItem.Checked))
{
MessageBox.Show(I18N.GetString("Failed to update registry"));
}
LoadCurrentConfiguration();
}
private void LocalPACItem_Click(object sender, EventArgs e)
@@ -944,14 +944,14 @@ namespace Shadowsocks.View
if (this.localPACItem.Checked)
{
this.editLocalPACItem.Enabled = true;
this.updateFromGFWListItem.Enabled = true;
this.updateFromGeositeItem.Enabled = true;
this.editGFWUserRuleItem.Enabled = true;
this.editOnlinePACItem.Enabled = false;
}
else
{
this.editLocalPACItem.Enabled = false;
this.updateFromGFWListItem.Enabled = false;
this.updateFromGeositeItem.Enabled = false;
this.editGFWUserRuleItem.Enabled = false;
this.editOnlinePACItem.Enabled = true;
}


+ 1
- 0
shadowsocks-csharp/packages.config View File

@@ -5,6 +5,7 @@
<package id="Costura.Fody" version="3.3.3" targetFramework="net472" />
<package id="Fody" version="4.2.1" targetFramework="net472" developmentDependency="true" />
<package id="GlobalHotKey" version="1.1.0" targetFramework="net472" />
<package id="Google.Protobuf" version="3.11.4" targetFramework="net472" />
<package id="NaCl.Core" version="1.2.0" targetFramework="net472" />
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net472" />
<package id="NLog" version="4.6.8" targetFramework="net472" />


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

@@ -79,7 +79,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Google.Protobuf" Version="3.11.4" />
<PackageReference Include="Microsoft.VisualBasic" Version="10.3.0" />
<PackageReference Include="NaCl.Core" Version="1.2.0" />
@@ -96,7 +96,7 @@
<ItemGroup>
<Resource Include="Data\abp.js" />
<Resource Include="Data\default-abp-rule.js" />
<Resource Include="Data\dlc.dat" />
<Resource Include="Data\i18n.csv" />
<Resource Include="Data\NLog.config" />
<Resource Include="Data\privoxy.exe.gz" />


Loading…
Cancel
Save