🔐 Add Sha256sum verification for GeoSite db + other fixes and cleanup
pull/2937/head
@@ -1,15 +0,0 @@ | |||||
OpenSSL library guide for VS2017 | |||||
# Read NOTES.WIN and NOTES.PERL | |||||
# use Visual Studio native tools command prompt | |||||
# use activeperl, install NASM assembler | |||||
ppm install dmake | |||||
# Win32 x86 | |||||
set PATH=D:\NASM-32;%PATH% | |||||
perl Configure VC-WIN32 --release --prefix=C:\Users\home\Downloads\openssl-1.1.0g\x86-build --openssldir=C:\Users\home\Downloads\openssl-1.1.0g\x86-install | |||||
nmake | |||||
nmake test | |||||
# to rebuild | |||||
nmake distclean |
@@ -114,7 +114,7 @@ after_build: | |||||
$text += 'SHA-256' + $newLine | $text += 'SHA-256' + $newLine | ||||
$text += (Get-FileHash $file -Algorithm SHA256).Hash + $newLine | $text += (Get-FileHash $file -Algorithm SHA256).Hash + $newLine | ||||
$text += 'SHA-512' + $newLine | $text += 'SHA-512' + $newLine | ||||
$text += (Get-FileHash $file -Algorithm SHA512).Hash | |||||
$text += (Get-FileHash $file -Algorithm SHA512).Hash + $newLine | |||||
return $text | return $text | ||||
} | } | ||||
@@ -9,6 +9,9 @@ using System.Text; | |||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
using Shadowsocks.Model; | using Shadowsocks.Model; | ||||
using System.Net; | using System.Net; | ||||
using System.Net.Http; | |||||
using System.Threading.Tasks; | |||||
using System.Security.Cryptography; | |||||
namespace Shadowsocks.Controller | namespace Shadowsocks.Controller | ||||
{ | { | ||||
@@ -32,23 +35,37 @@ namespace Shadowsocks.Controller | |||||
private static readonly string DATABASE_PATH = Utils.GetTempPath("dlc.dat"); | private static readonly string DATABASE_PATH = Utils.GetTempPath("dlc.dat"); | ||||
private static SocketsHttpHandler socketsHttpHandler; | |||||
private static HttpClient httpClient; | |||||
private static readonly string GEOSITE_URL = "https://github.com/v2ray/domain-list-community/raw/release/dlc.dat"; | private static readonly string GEOSITE_URL = "https://github.com/v2ray/domain-list-community/raw/release/dlc.dat"; | ||||
private static readonly string GEOSITE_SHA256SUM_URL = "https://github.com/v2ray/domain-list-community/raw/release/dlc.dat.sha256sum"; | |||||
private static byte[] geositeDB; | |||||
public static readonly Dictionary<string, IList<DomainObject>> Geosites = new Dictionary<string, IList<DomainObject>>(); | public static readonly Dictionary<string, IList<DomainObject>> Geosites = new Dictionary<string, IList<DomainObject>>(); | ||||
static GeositeUpdater() | static GeositeUpdater() | ||||
{ | { | ||||
if (!File.Exists(DATABASE_PATH)) | |||||
//socketsHttpHandler = new SocketsHttpHandler(); | |||||
//httpClient = new HttpClient(socketsHttpHandler); | |||||
if (File.Exists(DATABASE_PATH) && new FileInfo(DATABASE_PATH).Length > 0) | |||||
{ | { | ||||
geositeDB = File.ReadAllBytes(DATABASE_PATH); | |||||
} | |||||
else | |||||
{ | |||||
geositeDB = Resources.dlc_dat; | |||||
File.WriteAllBytes(DATABASE_PATH, Resources.dlc_dat); | File.WriteAllBytes(DATABASE_PATH, Resources.dlc_dat); | ||||
} | } | ||||
LoadGeositeList(); | LoadGeositeList(); | ||||
} | } | ||||
static void LoadGeositeList(byte[] data = null) | |||||
/// <summary> | |||||
/// load new GeoSite data from geositeDB | |||||
/// </summary> | |||||
static void LoadGeositeList() | |||||
{ | { | ||||
data = data ?? File.ReadAllBytes(DATABASE_PATH); | |||||
var list = GeositeList.Parser.ParseFrom(data); | |||||
var list = GeositeList.Parser.ParseFrom(geositeDB); | |||||
foreach (var item in list.Entries) | foreach (var item in list.Entries) | ||||
{ | { | ||||
Geosites[item.GroupName.ToLower()] = item.Domains; | Geosites[item.GroupName.ToLower()] = item.Domains; | ||||
@@ -61,9 +78,12 @@ namespace Shadowsocks.Controller | |||||
Error = null; | Error = null; | ||||
} | } | ||||
public static void UpdatePACFromGeosite(Configuration config) | |||||
public static async Task UpdatePACFromGeosite() | |||||
{ | { | ||||
string geositeUrl = GEOSITE_URL; | string geositeUrl = GEOSITE_URL; | ||||
string geositeSha256sumUrl = GEOSITE_SHA256SUM_URL; | |||||
SHA256 mySHA256 = SHA256.Create(); | |||||
var config = Program.MainController.GetCurrentConfiguration(); | |||||
string group = config.geositeGroup; | string group = config.geositeGroup; | ||||
bool blacklist = config.geositeBlacklistMode; | bool blacklist = config.geositeBlacklistMode; | ||||
@@ -73,31 +93,83 @@ namespace Shadowsocks.Controller | |||||
geositeUrl = config.geositeUrl; | geositeUrl = config.geositeUrl; | ||||
} | } | ||||
logger.Info($"Checking Geosite from {geositeUrl}"); | logger.Info($"Checking Geosite from {geositeUrl}"); | ||||
WebClient http = new WebClient(); | |||||
// use System.Net.Http.HttpClient to download GeoSite db. | |||||
// NASTY workaround: new HttpClient every update | |||||
// because we can't change proxy on existing socketsHttpHandler instance | |||||
socketsHttpHandler = new SocketsHttpHandler(); | |||||
httpClient = new HttpClient(socketsHttpHandler); | |||||
if (config.enabled) | if (config.enabled) | ||||
{ | { | ||||
http.Proxy = new WebProxy( | |||||
socketsHttpHandler.UseProxy = true; | |||||
socketsHttpHandler.Proxy = new WebProxy( | |||||
config.isIPv6Enabled | config.isIPv6Enabled | ||||
? $"[{IPAddress.IPv6Loopback}]" | ? $"[{IPAddress.IPv6Loopback}]" | ||||
: IPAddress.Loopback.ToString(), | : IPAddress.Loopback.ToString(), | ||||
config.localPort); | config.localPort); | ||||
} | } | ||||
http.DownloadDataCompleted += (o, e) => | |||||
try | |||||
{ | { | ||||
try | |||||
// download checksum first | |||||
var geositeSha256sum = await httpClient.GetStringAsync(geositeSha256sumUrl); | |||||
geositeSha256sum = geositeSha256sum.Substring(0, 64).ToUpper(); | |||||
logger.Info($"Got Sha256sum: {geositeSha256sum}"); | |||||
// compare downloaded checksum with local geositeDB | |||||
byte[] localDBHashBytes = mySHA256.ComputeHash(geositeDB); | |||||
string localDBHash = BitConverter.ToString(localDBHashBytes).Replace("-", String.Empty); | |||||
logger.Info($"Local Sha256sum: {localDBHash}"); | |||||
// if already latest | |||||
if (geositeSha256sum == localDBHash) | |||||
{ | |||||
logger.Info("Local GeoSite DB is up to date."); | |||||
return; | |||||
} | |||||
// not latest. download new DB | |||||
var downloadedBytes = await httpClient.GetByteArrayAsync(geositeUrl); | |||||
// verify sha256sum | |||||
byte[] downloadedDBHashBytes = mySHA256.ComputeHash(downloadedBytes); | |||||
string downloadedDBHash = BitConverter.ToString(downloadedDBHashBytes).Replace("-", String.Empty); | |||||
logger.Info($"Actual Sha256sum: {downloadedDBHash}"); | |||||
if (geositeSha256sum != downloadedDBHash) | |||||
{ | { | ||||
File.WriteAllBytes(DATABASE_PATH, e.Result); | |||||
LoadGeositeList(); | |||||
logger.Info("Sha256sum Verification: FAILED. Downloaded GeoSite DB is corrupted. Aborting the update."); | |||||
throw new Exception("Sha256sum mismatch"); | |||||
} | |||||
else | |||||
{ | |||||
logger.Info("Sha256sum Verification: PASSED. Applying to local GeoSite DB."); | |||||
} | |||||
bool pacFileChanged = MergeAndWritePACFile(group, blacklist); | |||||
UpdateCompleted?.Invoke(null, new GeositeResultEventArgs(pacFileChanged)); | |||||
// write to geosite file | |||||
using (FileStream geositeFileStream = File.Create(DATABASE_PATH)) | |||||
await geositeFileStream.WriteAsync(downloadedBytes, 0, downloadedBytes.Length); | |||||
// update stuff | |||||
geositeDB = downloadedBytes; | |||||
LoadGeositeList(); | |||||
bool pacFileChanged = MergeAndWritePACFile(group, blacklist); | |||||
UpdateCompleted?.Invoke(null, new GeositeResultEventArgs(pacFileChanged)); | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
Error?.Invoke(null, new ErrorEventArgs(ex)); | |||||
} | |||||
finally | |||||
{ | |||||
if (socketsHttpHandler != null) | |||||
{ | |||||
socketsHttpHandler.Dispose(); | |||||
socketsHttpHandler = null; | |||||
} | } | ||||
catch (Exception ex) | |||||
if (httpClient != null) | |||||
{ | { | ||||
Error?.Invoke(null, new ErrorEventArgs(ex)); | |||||
httpClient.Dispose(); | |||||
httpClient = null; | |||||
} | } | ||||
}; | |||||
http.DownloadDataAsync(new Uri(geositeUrl)); | |||||
} | |||||
} | } | ||||
public static bool MergeAndWritePACFile(string group, bool blacklist) | public static bool MergeAndWritePACFile(string group, bool blacklist) | ||||
@@ -411,11 +411,6 @@ namespace Shadowsocks.Controller | |||||
return $"ss://{url}{tag}"; | return $"ss://{url}{tag}"; | ||||
} | } | ||||
public void UpdatePACFromGeosite() | |||||
{ | |||||
GeositeUpdater.UpdatePACFromGeosite(_config); | |||||
} | |||||
public void UpdateStatisticsConfiguration(bool enabled) | public void UpdateStatisticsConfiguration(bool enabled) | ||||
{ | { | ||||
if (availabilityStatistics != null) | if (availabilityStatistics != null) | ||||
@@ -20,7 +20,6 @@ namespace Shadowsocks.Controller | |||||
// see https://stackoverflow.com/questions/12945805/odd-c-sharp-path-issue | // see https://stackoverflow.com/questions/12945805/odd-c-sharp-path-issue | ||||
private static readonly string ExecutablePath = Assembly.GetEntryAssembly().Location; | private static readonly string ExecutablePath = Assembly.GetEntryAssembly().Location; | ||||
// TODO: Elevate when necessary | |||||
public static bool Set(bool enabled) | public static bool Set(bool enabled) | ||||
{ | { | ||||
RegistryKey ssURLAssociation = null; | RegistryKey ssURLAssociation = null; | ||||
@@ -26,32 +26,17 @@ namespace Shadowsocks | |||||
public static MenuViewController MenuController { get; private set; } | public static MenuViewController MenuController { get; private set; } | ||||
public static string[] Args { get; private set; } | public static string[] Args { get; private set; } | ||||
[System.Runtime.InteropServices.DllImport("user32.dll")] | |||||
private static extern bool SetProcessDPIAware(); | |||||
/// <summary> | /// <summary> | ||||
/// 应用程序的主入口点。 | /// 应用程序的主入口点。 | ||||
/// </summary> | /// </summary> | ||||
/// </summary> | |||||
[STAThread] | [STAThread] | ||||
static void Main(string[] args) | static void Main(string[] args) | ||||
{ | { | ||||
// todo: initialize the NLog configuartion | // todo: initialize the NLog configuartion | ||||
Model.NLogConfig.TouchAndApplyNLogConfig(); | Model.NLogConfig.TouchAndApplyNLogConfig(); | ||||
// .NET Framework 4.7.2 on Win7 compatibility | |||||
System.Net.ServicePointManager.SecurityProtocol |= | |||||
System.Net.SecurityProtocolType.Tls | System.Net.SecurityProtocolType.Tls11 | System.Net.SecurityProtocolType.Tls12; | |||||
// store args for further use | // store args for further use | ||||
Args = args; | Args = args; | ||||
// Check OS since we are using dual-mode socket | |||||
if (!Utils.IsWinVistaOrHigher()) | |||||
{ | |||||
MessageBox.Show(I18N.GetString("Unsupported operating system, use Windows Vista at least."), | |||||
"Shadowsocks Error", MessageBoxButtons.OK, MessageBoxIcon.Error); | |||||
return; | |||||
} | |||||
string pipename = $"Shadowsocks\\{Application.StartupPath.GetHashCode()}"; | string pipename = $"Shadowsocks\\{Application.StartupPath.GetHashCode()}"; | ||||
string addedUrl = null; | string addedUrl = null; | ||||
@@ -125,7 +110,9 @@ namespace Shadowsocks | |||||
Application.SetCompatibleTextRenderingDefault(false); | Application.SetCompatibleTextRenderingDefault(false); | ||||
AutoStartup.RegisterForRestart(true); | AutoStartup.RegisterForRestart(true); | ||||
Directory.SetCurrentDirectory(Application.StartupPath); | |||||
// See https://github.com/dotnet/runtime/issues/13051 | |||||
// we have to do this for self-contained executables | |||||
Directory.SetCurrentDirectory(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)); | |||||
#if DEBUG | #if DEBUG | ||||
// truncate privoxy log file while debugging | // truncate privoxy log file while debugging | ||||
@@ -0,0 +1,18 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<!-- | |||||
https://go.microsoft.com/fwlink/?LinkID=208121. | |||||
--> | |||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<PropertyGroup> | |||||
<Configuration>Release</Configuration> | |||||
<Platform>Any CPU</Platform> | |||||
<PublishDir>bin\Release\netcoreapp3.1\win-x64\publish\</PublishDir> | |||||
<PublishProtocol>FileSystem</PublishProtocol> | |||||
<TargetFramework>netcoreapp3.1</TargetFramework> | |||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier> | |||||
<SelfContained>true</SelfContained> | |||||
<PublishSingleFile>True</PublishSingleFile> | |||||
<PublishReadyToRun>False</PublishReadyToRun> | |||||
<PublishTrimmed>True</PublishTrimmed> | |||||
</PropertyGroup> | |||||
</Project> |
@@ -0,0 +1,6 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<!-- | |||||
https://go.microsoft.com/fwlink/?LinkID=208121. | |||||
--> | |||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
</Project> |
@@ -0,0 +1,18 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<!-- | |||||
https://go.microsoft.com/fwlink/?LinkID=208121. | |||||
--> | |||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<PropertyGroup> | |||||
<Configuration>Release</Configuration> | |||||
<Platform>Any CPU</Platform> | |||||
<PublishDir>bin\Release\netcoreapp3.1\win-x86\publish\</PublishDir> | |||||
<PublishProtocol>FileSystem</PublishProtocol> | |||||
<TargetFramework>netcoreapp3.1</TargetFramework> | |||||
<RuntimeIdentifier>win-x86</RuntimeIdentifier> | |||||
<SelfContained>true</SelfContained> | |||||
<PublishSingleFile>True</PublishSingleFile> | |||||
<PublishReadyToRun>False</PublishReadyToRun> | |||||
<PublishTrimmed>True</PublishTrimmed> | |||||
</PropertyGroup> | |||||
</Project> |
@@ -0,0 +1,6 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<!-- | |||||
https://go.microsoft.com/fwlink/?LinkID=208121. | |||||
--> | |||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
</Project> |
@@ -705,9 +705,9 @@ namespace Shadowsocks.View | |||||
controller.TouchPACFile(); | controller.TouchPACFile(); | ||||
} | } | ||||
private void UpdatePACFromGeositeItem_Click(object sender, EventArgs e) | |||||
private async void UpdatePACFromGeositeItem_Click(object sender, EventArgs e) | |||||
{ | { | ||||
controller.UpdatePACFromGeosite(); | |||||
await GeositeUpdater.UpdatePACFromGeosite(); | |||||
} | } | ||||
private void EditUserRuleFileForGeositeItem_Click(object sender, EventArgs e) | private void EditUserRuleFileForGeositeItem_Click(object sender, EventArgs e) | ||||
@@ -71,20 +71,20 @@ | |||||
<PackageReference Include="GlobalHotKeyCore" Version="1.2.0" /> | <PackageReference Include="GlobalHotKeyCore" Version="1.2.0" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<PackageReference Include="BouncyCastle.NetCore" Version="1.8.5" /> | |||||
<PackageReference Include="BouncyCastle.NetCore" Version="1.8.6" /> | |||||
<!--TODO: Remove Fody related stuff, as they're either not actually used or has NET Core built-in alternate--> | <!--TODO: Remove Fody related stuff, as they're either not actually used or has NET Core built-in alternate--> | ||||
<PackageReference Include="Caseless.Fody" Version="1.9.0" /> | <PackageReference Include="Caseless.Fody" Version="1.9.0" /> | ||||
<PackageReference Include="Costura.Fody" Version="4.1.0" /> | <PackageReference Include="Costura.Fody" Version="4.1.0" /> | ||||
<PackageReference Include="Fody" Version="6.1.1"> | |||||
<PackageReference Include="Fody" Version="6.2.0"> | |||||
<PrivateAssets>all</PrivateAssets> | <PrivateAssets>all</PrivateAssets> | ||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||||
</PackageReference> | </PackageReference> | ||||
<PackageReference Include="Google.Protobuf" Version="3.11.4" /> | |||||
<PackageReference Include="Google.Protobuf" Version="3.12.3" /> | |||||
<PackageReference Include="Microsoft.VisualBasic" Version="10.3.0" /> | <PackageReference Include="Microsoft.VisualBasic" Version="10.3.0" /> | ||||
<PackageReference Include="NaCl.Core" Version="1.2.0" /> | <PackageReference Include="NaCl.Core" Version="1.2.0" /> | ||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> | <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> | ||||
<PackageReference Include="NLog" Version="4.6.8" /> | |||||
<PackageReference Include="NLog" Version="4.7.2" /> | |||||
<PackageReference Include="System.Data.SqlClient" Version="4.8.1" /> | <PackageReference Include="System.Data.SqlClient" Version="4.8.1" /> | ||||
<PackageReference Include="ZXing.Net" Version="0.16.5" /> | <PackageReference Include="ZXing.Net" Version="0.16.5" /> | ||||
<PackageReference Include="StringEx.CS" Version="0.3.1"> | <PackageReference Include="StringEx.CS" Version="0.3.1"> | ||||