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 SocketsHttpHandler socketsHttpHandler ;
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,83 @@ 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
+ socketsHttpHandler = new SocketsHttpHandler ( ) ;
101
+ httpClient = new HttpClient ( socketsHttpHandler ) ;
77
102
if ( config . enabled )
78
103
{
79
- http . Proxy = new WebProxy (
104
+ socketsHttpHandler . UseProxy = true ;
105
+ socketsHttpHandler . Proxy = new WebProxy (
80
106
config . isIPv6Enabled
81
107
? $ "[{ IPAddress . IPv6Loopback } ]"
82
108
: IPAddress . Loopback . ToString ( ) ,
83
109
config . localPort ) ;
84
110
}
85
- http . DownloadDataCompleted += ( o , e ) =>
111
+
112
+ try
86
113
{
87
- try
114
+ // download checksum first
115
+ var geositeSha256sum = await httpClient . GetStringAsync ( geositeSha256sumUrl ) ;
116
+ geositeSha256sum = geositeSha256sum . Substring ( 0 , 64 ) . ToUpper ( ) ;
117
+ logger . Info ( $ "Got Sha256sum: { geositeSha256sum } ") ;
118
+ // compare downloaded checksum with local geositeDB
119
+ byte [ ] localDBHashBytes = mySHA256 . ComputeHash ( geositeDB ) ;
120
+ string localDBHash = BitConverter . ToString ( localDBHashBytes ) . Replace ( "-" , String . Empty ) ;
121
+ logger . Info ( $ "Local Sha256sum: { localDBHash } ") ;
122
+ // if already latest
123
+ if ( geositeSha256sum == localDBHash )
124
+ {
125
+ logger . Info ( "Local GeoSite DB is already the latest." ) ;
126
+ return ;
127
+ }
128
+
129
+ // not latest. download new DB
130
+ var downloadedBytes = await httpClient . GetByteArrayAsync ( geositeUrl ) ;
131
+
132
+ // verify sha256sum
133
+ byte [ ] downloadedDBHashBytes = mySHA256 . ComputeHash ( downloadedBytes ) ;
134
+ string downloadedDBHash = BitConverter . ToString ( downloadedDBHashBytes ) . Replace ( "-" , String . Empty ) ;
135
+ logger . Info ( $ "Actual Sha256sum: { downloadedDBHash } ") ;
136
+ if ( geositeSha256sum != downloadedDBHash )
88
137
{
89
- File . WriteAllBytes ( DATABASE_PATH , e . Result ) ;
90
- LoadGeositeList ( ) ;
138
+ logger . Info ( "Sha256sum mismatch. Updating aborted." ) ;
139
+ throw new Exception ( "Sha256sum mismatch" ) ;
140
+ }
141
+ else
142
+ {
143
+ logger . Info ( "Sha256sum verification successful." ) ;
144
+ }
91
145
92
- bool pacFileChanged = MergeAndWritePACFile ( group , blacklist ) ;
93
- UpdateCompleted ? . Invoke ( null , new GeositeResultEventArgs ( pacFileChanged ) ) ;
146
+ // write to geosite file
147
+ using ( FileStream geositeFileStream = File . Create ( DATABASE_PATH ) )
148
+ await geositeFileStream . WriteAsync ( downloadedBytes , 0 , downloadedBytes . Length ) ;
149
+
150
+ // update stuff
151
+ geositeDB = downloadedBytes ;
152
+ LoadGeositeList ( ) ;
153
+ bool pacFileChanged = MergeAndWritePACFile ( group , blacklist ) ;
154
+ UpdateCompleted ? . Invoke ( null , new GeositeResultEventArgs ( pacFileChanged ) ) ;
155
+ }
156
+ catch ( Exception ex )
157
+ {
158
+ Error ? . Invoke ( null , new ErrorEventArgs ( ex ) ) ;
159
+ }
160
+ finally
161
+ {
162
+ if ( socketsHttpHandler != null )
163
+ {
164
+ socketsHttpHandler . Dispose ( ) ;
165
+ socketsHttpHandler = null ;
94
166
}
95
- catch ( Exception ex )
167
+ if ( httpClient != null )
96
168
{
97
- Error ? . Invoke ( null , new ErrorEventArgs ( ex ) ) ;
169
+ httpClient . Dispose ( ) ;
170
+ httpClient = null ;
98
171
}
99
- } ;
100
- http . DownloadDataAsync ( new Uri ( geositeUrl ) ) ;
172
+ }
101
173
}
102
174
103
175
public static bool MergeAndWritePACFile ( string group , bool blacklist )
0 commit comments