2c15276
from v5/master to master
- Compared to 2c15276: changed socketsHttpHandler to HttpClientHandler due to legacy .NET Framework - Use System.Net.Http.HttpClient for GeositeUpdater - New update check mechanism: first download checksum and compare, only download GeoSite DB on different checksum - Verifiy downloaded GeoSite DB by comparing sha256sum before committing the changetags/4.2.0.0
@@ -9,6 +9,9 @@ using System.Text; | |||
using Newtonsoft.Json; | |||
using Shadowsocks.Model; | |||
using System.Net; | |||
using System.Net.Http; | |||
using System.Threading.Tasks; | |||
using System.Security.Cryptography; | |||
namespace Shadowsocks.Controller | |||
{ | |||
@@ -32,23 +35,37 @@ namespace Shadowsocks.Controller | |||
private static readonly string DATABASE_PATH = Utils.GetTempPath("dlc.dat"); | |||
private static HttpClientHandler httpClientHandler; | |||
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_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>>(); | |||
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); | |||
} | |||
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) | |||
{ | |||
Geosites[item.GroupName.ToLower()] = item.Domains; | |||
@@ -61,9 +78,12 @@ namespace Shadowsocks.Controller | |||
Error = null; | |||
} | |||
public static void UpdatePACFromGeosite(Configuration config) | |||
public static async Task UpdatePACFromGeosite() | |||
{ | |||
string geositeUrl = GEOSITE_URL; | |||
string geositeSha256sumUrl = GEOSITE_SHA256SUM_URL; | |||
SHA256 mySHA256 = SHA256.Create(); | |||
var config = Program.MainController.GetCurrentConfiguration(); | |||
string group = config.geositeGroup; | |||
bool blacklist = config.geositeBlacklistMode; | |||
@@ -73,31 +93,82 @@ namespace Shadowsocks.Controller | |||
geositeUrl = config.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 | |||
httpClientHandler = new HttpClientHandler(); | |||
httpClient = new HttpClient(httpClientHandler); | |||
if (config.enabled) | |||
{ | |||
http.Proxy = new WebProxy( | |||
httpClientHandler.Proxy = new WebProxy( | |||
config.isIPv6Enabled | |||
? $"[{IPAddress.IPv6Loopback}]" | |||
: IPAddress.Loopback.ToString(), | |||
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 already the latest."); | |||
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 mismatch. Updating aborted."); | |||
throw new Exception("Sha256sum mismatch"); | |||
} | |||
else | |||
{ | |||
logger.Info("Sha256sum verification successful."); | |||
} | |||
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 (httpClientHandler != null) | |||
{ | |||
httpClientHandler.Dispose(); | |||
httpClientHandler = 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) | |||
@@ -415,11 +415,6 @@ namespace Shadowsocks.Controller | |||
return $"ss://{url}{tag}"; | |||
} | |||
public void UpdatePACFromGeosite() | |||
{ | |||
GeositeUpdater.UpdatePACFromGeosite(_config); | |||
} | |||
public void UpdateStatisticsConfiguration(bool enabled) | |||
{ | |||
if (availabilityStatistics != null) | |||
@@ -685,9 +685,9 @@ namespace Shadowsocks.View | |||
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) | |||
@@ -9,8 +9,15 @@ | |||
<package id="NLog" version="4.6.8" targetFramework="net472" /> | |||
<package id="StringEx.CS" version="0.3.1" targetFramework="net472" developmentDependency="true" /> | |||
<package id="System.Buffers" version="4.4.0" targetFramework="net472" /> | |||
<package id="System.IO" version="4.3.0" targetFramework="net472" /> | |||
<package id="System.Memory" version="4.5.2" targetFramework="net472" /> | |||
<package id="System.Net.Http" version="4.3.4" targetFramework="net472" /> | |||
<package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net472" /> | |||
<package id="System.Runtime" version="4.3.0" targetFramework="net472" /> | |||
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net472" /> | |||
<package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net472" /> | |||
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net472" /> | |||
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net472" /> | |||
<package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net472" /> | |||
<package id="ZXing.Net" version="0.16.5" targetFramework="net472" /> | |||
</packages> |
@@ -93,24 +93,60 @@ | |||
<Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath> | |||
</Reference> | |||
<Reference Include="System.ComponentModel.Composition" /> | |||
<Reference Include="System.Configuration" /> | |||
<Reference Include="System.Data" /> | |||
<Reference Include="System.Data.DataSetExtensions" /> | |||
<Reference Include="System.Drawing" /> | |||
<Reference Include="System.IO, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\System.IO.4.3.0\lib\net462\System.IO.dll</HintPath> | |||
<Private>True</Private> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System.IO.Compression" /> | |||
<Reference Include="System.Management" /> | |||
<Reference Include="System.Memory, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\System.Memory.4.5.2\lib\netstandard2.0\System.Memory.dll</HintPath> | |||
</Reference> | |||
<Reference Include="System.Net" /> | |||
<Reference Include="System.Net.Http, Version=4.1.1.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll</HintPath> | |||
<Private>True</Private> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System.Numerics" /> | |||
<Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath> | |||
</Reference> | |||
<Reference Include="System.Runtime, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll</HintPath> | |||
<Private>True</Private> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath> | |||
</Reference> | |||
<Reference Include="System.Runtime.Serialization" /> | |||
<Reference Include="System.Security.Cryptography.Algorithms, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll</HintPath> | |||
<Private>True</Private> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll</HintPath> | |||
<Private>True</Private> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll</HintPath> | |||
<Private>True</Private> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System.Security.Cryptography.X509Certificates, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll</HintPath> | |||
<Private>True</Private> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System.ServiceModel" /> | |||
<Reference Include="System.Transactions" /> | |||
<Reference Include="System.Web" /> | |||