9
9
using Newtonsoft . Json ;
10
10
using Shadowsocks . Model ;
11
11
using System . Net ;
12
+ using System . Net . Http ;
13
+ using System . Threading . Tasks ;
14
+ using System . Security . Cryptography ;
12
15
13
16
namespace Shadowsocks . Controller
14
17
{
@@ -32,23 +35,37 @@ public static class GeositeUpdater
32
35
33
36
private static readonly string DATABASE_PATH = Utils . GetTempPath ( "dlc.dat" ) ;
34
37
38
+ private static HttpClientHandler httpClientHandler ;
39
+ private static HttpClient httpClient ;
35
40
private static readonly string GEOSITE_URL = "https://github.com/v2ray/domain-list-community/raw/release/dlc.dat" ;
41
+ private static readonly string GEOSITE_SHA256SUM_URL = "https://github.com/v2ray/domain-list-community/raw/release/dlc.dat.sha256sum" ;
42
+ private static byte [ ] geositeDB ;
36
43
37
44
public static readonly Dictionary < string , IList < DomainObject > > Geosites = new Dictionary < string , IList < DomainObject > > ( ) ;
38
45
39
46
static GeositeUpdater ( )
40
47
{
41
- if ( ! File . Exists ( DATABASE_PATH ) )
48
+ //socketsHttpHandler = new SocketsHttpHandler();
49
+ //httpClient = new HttpClient(socketsHttpHandler);
50
+
51
+ if ( File . Exists ( DATABASE_PATH ) && new FileInfo ( DATABASE_PATH ) . Length > 0 )
42
52
{
53
+ geositeDB = File . ReadAllBytes ( DATABASE_PATH ) ;
54
+ }
55
+ else
56
+ {
57
+ geositeDB = Resources . dlc_dat ;
43
58
File . WriteAllBytes ( DATABASE_PATH , Resources . dlc_dat ) ;
44
59
}
45
60
LoadGeositeList ( ) ;
46
61
}
47
62
48
- static void LoadGeositeList ( byte [ ] data = null )
63
+ /// <summary>
64
+ /// load new GeoSite data from geositeDB
65
+ /// </summary>
66
+ static void LoadGeositeList ( )
49
67
{
50
- data = data ?? File . ReadAllBytes ( DATABASE_PATH ) ;
51
- var list = GeositeList . Parser . ParseFrom ( data ) ;
68
+ var list = GeositeList . Parser . ParseFrom ( geositeDB ) ;
52
69
foreach ( var item in list . Entries )
53
70
{
54
71
Geosites [ item . GroupName . ToLower ( ) ] = item . Domains ;
@@ -61,9 +78,12 @@ public static void ResetEvent()
61
78
Error = null ;
62
79
}
63
80
64
- public static void UpdatePACFromGeosite ( Configuration config )
81
+ public static async Task UpdatePACFromGeosite ( )
65
82
{
66
83
string geositeUrl = GEOSITE_URL ;
84
+ string geositeSha256sumUrl = GEOSITE_SHA256SUM_URL ;
85
+ SHA256 mySHA256 = SHA256 . Create ( ) ;
86
+ var config = Program . MainController . GetCurrentConfiguration ( ) ;
67
87
string group = config . geositeGroup ;
68
88
bool blacklist = config . geositeBlacklistMode ;
69
89
@@ -73,31 +93,82 @@ public static void UpdatePACFromGeosite(Configuration config)
73
93
geositeUrl = config . geositeUrl ;
74
94
}
75
95
logger . Info ( $ "Checking Geosite from { geositeUrl } ") ;
76
- WebClient http = new WebClient ( ) ;
96
+
97
+ // use System.Net.Http.HttpClient to download GeoSite db.
98
+ // NASTY workaround: new HttpClient every update
99
+ // because we can't change proxy on existing socketsHttpHandler instance
100
+ httpClientHandler = new HttpClientHandler ( ) ;
101
+ httpClient = new HttpClient ( httpClientHandler ) ;
77
102
if ( config . enabled )
78
103
{
79
- http . Proxy = new WebProxy (
104
+ httpClientHandler . Proxy = new WebProxy (
80
105
config . isIPv6Enabled
81
106
? $ "[{ IPAddress . IPv6Loopback } ]"
82
107
: IPAddress . Loopback . ToString ( ) ,
83
108
config . localPort ) ;
84
109
}
85
- http . DownloadDataCompleted += ( o , e ) =>
110
+
111
+ try
86
112
{
87
- try
113
+ // download checksum first
114
+ var geositeSha256sum = await httpClient . GetStringAsync ( geositeSha256sumUrl ) ;
115
+ geositeSha256sum = geositeSha256sum . Substring ( 0 , 64 ) . ToUpper ( ) ;
116
+ logger . Info ( $ "Got Sha256sum: { geositeSha256sum } ") ;
117
+ // compare downloaded checksum with local geositeDB
118
+ byte [ ] localDBHashBytes = mySHA256 . ComputeHash ( geositeDB ) ;
119
+ string localDBHash = BitConverter . ToString ( localDBHashBytes ) . Replace ( "-" , String . Empty ) ;
120
+ logger . Info ( $ "Local Sha256sum: { localDBHash } ") ;
121
+ // if already latest
122
+ if ( geositeSha256sum == localDBHash )
123
+ {
124
+ logger . Info ( "Local GeoSite DB is up to date." ) ;
125
+ return ;
126
+ }
127
+
128
+ // not latest. download new DB
129
+ var downloadedBytes = await httpClient . GetByteArrayAsync ( geositeUrl ) ;
130
+
131
+ // verify sha256sum
132
+ byte [ ] downloadedDBHashBytes = mySHA256 . ComputeHash ( downloadedBytes ) ;
133
+ string downloadedDBHash = BitConverter . ToString ( downloadedDBHashBytes ) . Replace ( "-" , String . Empty ) ;
134
+ logger . Info ( $ "Actual Sha256sum: { downloadedDBHash } ") ;
135
+ if ( geositeSha256sum != downloadedDBHash )
88
136
{
89
- File . WriteAllBytes ( DATABASE_PATH , e . Result ) ;
90
- LoadGeositeList ( ) ;
137
+ logger . Info ( "Sha256sum Verification: FAILED. Downloaded GeoSite DB is corrupted. Aborting the update." ) ;
138
+ throw new Exception ( "Sha256sum mismatch" ) ;
139
+ }
140
+ else
141
+ {
142
+ logger . Info ( "Sha256sum Verification: PASSED. Applying to local GeoSite DB." ) ;
143
+ }
91
144
92
- bool pacFileChanged = MergeAndWritePACFile ( group , blacklist ) ;
93
- UpdateCompleted ? . Invoke ( null , new GeositeResultEventArgs ( pacFileChanged ) ) ;
145
+ // write to geosite file
146
+ using ( FileStream geositeFileStream = File . Create ( DATABASE_PATH ) )
147
+ await geositeFileStream . WriteAsync ( downloadedBytes , 0 , downloadedBytes . Length ) ;
148
+
149
+ // update stuff
150
+ geositeDB = downloadedBytes ;
151
+ LoadGeositeList ( ) ;
152
+ bool pacFileChanged = MergeAndWritePACFile ( group , blacklist ) ;
153
+ UpdateCompleted ? . Invoke ( null , new GeositeResultEventArgs ( pacFileChanged ) ) ;
154
+ }
155
+ catch ( Exception ex )
156
+ {
157
+ Error ? . Invoke ( null , new ErrorEventArgs ( ex ) ) ;
158
+ }
159
+ finally
160
+ {
161
+ if ( httpClientHandler != null )
162
+ {
163
+ httpClientHandler . Dispose ( ) ;
164
+ httpClientHandler = null ;
94
165
}
95
- catch ( Exception ex )
166
+ if ( httpClient != null )
96
167
{
97
- Error ? . Invoke ( null , new ErrorEventArgs ( ex ) ) ;
168
+ httpClient . Dispose ( ) ;
169
+ httpClient = null ;
98
170
}
99
- } ;
100
- http . DownloadDataAsync ( new Uri ( geositeUrl ) ) ;
171
+ }
101
172
}
102
173
103
174
public static bool MergeAndWritePACFile ( string group , bool blacklist )
0 commit comments