@@ -6,9 +6,11 @@ import (
6
6
"fmt"
7
7
"os"
8
8
"os/exec"
9
+ "os/signal"
9
10
"path/filepath"
10
11
"strconv"
11
12
"strings"
13
+ "syscall"
12
14
"time"
13
15
)
14
16
@@ -40,6 +42,7 @@ var domainList = []struct {
40
42
{"4" , "speedtest.net" },
41
43
{"5" , "steampowered.com" },
42
44
{"6" , "custom" },
45
+ {"7" , "custom_multiple" },
43
46
{"0" , "exit" },
44
47
}
45
48
@@ -99,13 +102,21 @@ func requestElevation() error {
99
102
return fmt .Errorf ("failed to get executable path: %v" , err )
100
103
}
101
104
102
- cmd := exec .Command ("powershell" , "Start-Process" , executable , "-Verb" , "RunAs" , "-ArgumentList" , "--elevated" )
105
+ cmd := exec .Command ("powershell" , "-Command" , fmt .Sprintf (`
106
+ $proc = Start-Process -FilePath "%s" -Verb RunAs -PassThru -WindowStyle Normal
107
+ if ($proc.ExitCode -ne 0) {
108
+ exit $proc.ExitCode
109
+ }
110
+ ` , executable ))
111
+ cmd .Stdout = os .Stdout
112
+ cmd .Stderr = os .Stderr
113
+
103
114
return cmd .Run ()
104
115
}
105
116
106
117
func ensureProcessTerminated (processName string ) {
107
118
cmd := exec .Command ("taskkill" , "/F" , "/IM" , processName )
108
- cmd .Run () // Игнорируем ошибки, так как процесс может не существовать
119
+ cmd .Run () // Ignore errors as the process may not exist
109
120
}
110
121
111
122
func waitForProcess (processName string , timeout time.Duration ) bool {
@@ -138,14 +149,17 @@ func testConnection(domain string, timeout time.Duration) bool {
138
149
return err == nil
139
150
}
140
151
141
- func getDomainChoice () (string , error ) {
152
+ func getDomainChoice () ([] string , error ) {
142
153
fmt .Println ("\n Select domain for checking:" )
143
154
for _ , item := range domainList {
144
- if item .domain == "exit" {
155
+ switch item .domain {
156
+ case "exit" :
145
157
fmt .Printf ("%s. Exit\n " , item .number )
146
- } else if item . domain == "custom" {
158
+ case "custom" :
147
159
fmt .Printf ("%s. Enter your own domain\n " , item .number )
148
- } else {
160
+ case "custom_multiple" :
161
+ fmt .Printf ("%s. Enter multiple domains (space-separated)\n " , item .number )
162
+ default :
149
163
fmt .Printf ("%s. %s\n " , item .number , item .domain )
150
164
}
151
165
}
@@ -155,7 +169,7 @@ func getDomainChoice() (string, error) {
155
169
fmt .Print ("\n Enter number of variant: " )
156
170
choice , err := reader .ReadString ('\n' )
157
171
if err != nil {
158
- return "" , fmt .Errorf ("error reading input: %v" , err )
172
+ return nil , fmt .Errorf ("error reading input: %v" , err )
159
173
}
160
174
choice = strings .TrimSpace (choice )
161
175
@@ -168,19 +182,41 @@ func getDomainChoice() (string, error) {
168
182
}
169
183
if item .domain == "custom" {
170
184
fmt .Print ("Enter domain (for example, example.com): " )
171
-
172
185
domain , err := reader .ReadString ('\n' )
173
186
if err != nil {
174
- return "" , err
187
+ return nil , err
175
188
}
176
189
domain = strings .TrimSpace (domain )
177
190
if isValidDomain (domain ) {
178
- return formatDomainWithPort (domain ), nil
191
+ return [] string { formatDomainWithPort (domain )} , nil
179
192
}
180
193
fmt .Println ("Invalid domain format. Use format domain.com" )
181
194
continue
182
195
}
183
- return formatDomainWithPort (item .domain ), nil
196
+ if item .domain == "custom_multiple" {
197
+ fmt .Print ("Enter domains separated by spaces: " )
198
+ domains , err := reader .ReadString ('\n' )
199
+ if err != nil {
200
+ return nil , err
201
+ }
202
+
203
+ domainList := strings .Fields (domains )
204
+ var formattedDomains []string
205
+
206
+ for _ , domain := range domainList {
207
+ if ! isValidDomain (domain ) {
208
+ fmt .Printf ("Invalid domain format for '%s'. Use format domain.com\n " , domain )
209
+ continue
210
+ }
211
+ formattedDomains = append (formattedDomains , formatDomainWithPort (domain ))
212
+ }
213
+
214
+ if len (formattedDomains ) > 0 {
215
+ return formattedDomains , nil
216
+ }
217
+ continue
218
+ }
219
+ return []string {formatDomainWithPort (item .domain )}, nil
184
220
}
185
221
}
186
222
fmt .Printf ("Invalid selection. Please select number from 0 to %d\n " , len (domainList )- 1 )
@@ -219,54 +255,102 @@ func formatDomainWithPort(domain string) string {
219
255
220
256
func checkDPIFingerprint (domain string ) (DPITestResult , error ) {
221
257
cmd := exec .Command ("powershell" , "-Command" , fmt .Sprintf (`
258
+ # Save console settings
259
+ $originalForeground = $host.UI.RawUI.ForegroundColor
260
+ $originalBackground = $host.UI.RawUI.BackgroundColor
261
+
262
+ # Force TLS 1.2
263
+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
264
+
222
265
try {
223
- $webRequest = [System.Net.WebRequest]::Create("https://%s")
266
+ $url = "https://%s"
267
+ Write-Information "Trying to connect to $url"
268
+
269
+ $webRequest = [System.Net.WebRequest]::Create($url)
224
270
$webRequest.Timeout = 5000
225
- $response = $webRequest.GetResponse()
226
- $response.Close()
227
- return 0 # NoDPI
228
- } catch [System.Net.WebException] {
229
- if ($_.Exception.Message -like "*actively refused*") {
230
- return 1 # HasDPI
271
+ $webRequest.AllowAutoRedirect = $false
272
+
273
+ try {
274
+ $response = $webRequest.GetResponse()
275
+ $response.Close()
276
+ Write-Output "0" # NoDPI
277
+ } catch [System.Net.WebException] {
278
+ $exception = $_.Exception
279
+ Write-Information "Exception details: $($exception.Message)"
280
+ Write-Information "Status: $($exception.Status)"
281
+
282
+ if ($exception.Message -like "*actively refused*" -or
283
+ $exception.Message -like "*connection was forcibly closed*" -or
284
+ $exception.Status -eq [System.Net.WebExceptionStatus]::SecureChannelFailure -or
285
+ $exception.Status -eq [System.Net.WebExceptionStatus]::TrustFailure -or
286
+ $exception.Status -eq [System.Net.WebExceptionStatus]::ProtocolError) {
287
+ Write-Output "1" # HasDPI
288
+ } elseif ($exception.Status -eq [System.Net.WebExceptionStatus]::NameResolutionFailure) {
289
+ Write-Output "2" # DNS resolution failed
290
+ Write-Information "DNS resolution failed"
291
+ } elseif ($exception.Status -eq [System.Net.WebExceptionStatus]::Timeout) {
292
+ Write-Output "1" # Treat timeout as potential DPI
293
+ Write-Information "Connection timed out - possible DPI"
294
+ } else {
295
+ Write-Output "2" # NoConnection
296
+ Write-Information "Unknown connection error"
297
+ }
231
298
}
232
- return 2 # NoConnection
299
+ } catch {
300
+ Write-Output "2" # NoConnection
301
+ Write-Information "Unexpected error: $_"
302
+ } finally {
303
+ # Restore console settings
304
+ $host.UI.RawUI.ForegroundColor = $originalForeground
305
+ $host.UI.RawUI.BackgroundColor = $originalBackground
233
306
}
307
+ exit 0
234
308
` , domain ))
235
309
310
+ cmd .Stderr = os .Stderr // Show diagnostic output
236
311
output , err := cmd .Output ()
237
312
if err != nil {
238
- return NoConnection , err
313
+ if len (output ) == 0 {
314
+ return NoConnection , fmt .Errorf ("no output from DPI check: %v" , err )
315
+ }
239
316
}
240
317
241
- result , err := strconv .Atoi (strings .TrimSpace (string (output )))
318
+ // Берем только последнюю строку вывода, которая содержит результат
319
+ lines := strings .Split (strings .TrimSpace (string (output )), "\n " )
320
+ result , err := strconv .Atoi (lines [len (lines )- 1 ])
242
321
if err != nil {
243
- return NoConnection , err
322
+ return NoConnection , fmt . Errorf ( "invalid output from DPI check: %v" , err )
244
323
}
245
324
246
325
return DPITestResult (result ), nil
247
326
}
248
327
249
328
func runBypassCheck (config Config ) error {
250
- domainWithoutPort := strings .Split (config .targetDomain , ":" )[ 0 ]
329
+ domains := strings .Split (config .targetDomain , " " )
251
330
252
- fmt .Printf ("\n Starting testing domain : %s\n " , config .targetDomain )
331
+ fmt .Printf ("\n Starting testing domains : %s\n " , config .targetDomain )
253
332
fmt .Println ("------------------------------------------------" )
254
333
255
- fmt .Println ("Checking DPI blocks..." )
256
- result , err := checkDPIFingerprint (domainWithoutPort )
257
- if err != nil {
258
- fmt .Printf ("Error occurred while checking: %v\n " , err )
259
- } else {
260
- fmt .Printf ("Checking result: %s\n " , result )
334
+ // Check DPI for each domain
335
+ for _ , domain := range domains {
336
+ // Remove port before DPI check but keep it for display
337
+ domainForCheck := strings .Split (domain , ":" )[0 ]
338
+ fmt .Printf ("\n Checking DPI blocks for %s...\n " , domainForCheck )
339
+ result , err := checkDPIFingerprint (domainForCheck )
340
+ if err != nil {
341
+ fmt .Printf ("Checking result for %s: %s (with error: %v)\n " , domainForCheck , result , err )
342
+ } else {
343
+ fmt .Printf ("Checking result for %s: %s\n " , domainForCheck , result )
344
+ }
261
345
262
346
if result == NoDPI {
263
- fmt .Println ("Using DPI spoofer not required." )
264
- return nil
347
+ fmt .Printf ("Using DPI spoofer not required for %s. \n " , domainForCheck )
348
+ continue
265
349
}
266
350
267
351
if result == NoConnection {
268
- fmt .Println ("Check internet connection and if domain is correct." )
269
- return nil
352
+ fmt .Printf ("Check internet connection and if domain %s is correct.\n " , domainForCheck )
353
+ continue
270
354
}
271
355
}
272
356
@@ -282,10 +366,44 @@ func runBypassCheck(config Config) error {
282
366
for _ , batFile := range batFiles {
283
367
fmt .Printf ("\n %sRunning pre-config: %s%s\n " , colorMagenta , batFile , colorReset )
284
368
285
- // Ensure no previous process is running
286
369
ensureProcessTerminated (config .processName )
287
370
288
- cmd := exec .Command ("cmd" , "/c" , batFile )
371
+ cmd := exec .Command ("powershell" , "-Command" , fmt .Sprintf (`
372
+ # Save console settings
373
+ $originalForeground = $host.UI.RawUI.ForegroundColor
374
+ $originalBackground = $host.UI.RawUI.BackgroundColor
375
+ $originalBufferSize = $host.UI.RawUI.BufferSize
376
+ $originalWindowSize = $host.UI.RawUI.WindowSize
377
+
378
+ # Save font settings
379
+ $key = 'HKCU:\Console'
380
+ $originalFontSize = Get-ItemProperty -Path $key -Name 'FontSize' -ErrorAction SilentlyContinue
381
+ $originalFaceName = Get-ItemProperty -Path $key -Name 'FaceName' -ErrorAction SilentlyContinue
382
+ $originalFontFamily = Get-ItemProperty -Path $key -Name 'FontFamily' -ErrorAction SilentlyContinue
383
+
384
+ try {
385
+ # Execute BAT file
386
+ cmd /c "%s"
387
+ } finally {
388
+ # Restore console settings
389
+ $host.UI.RawUI.ForegroundColor = $originalForeground
390
+ $host.UI.RawUI.BackgroundColor = $originalBackground
391
+ $host.UI.RawUI.BufferSize = $originalBufferSize
392
+ $host.UI.RawUI.WindowSize = $originalWindowSize
393
+
394
+ # Restore font settings
395
+ if ($originalFontSize) {
396
+ Set-ItemProperty -Path $key -Name 'FontSize' -Value $originalFontSize.FontSize
397
+ }
398
+ if ($originalFaceName) {
399
+ Set-ItemProperty -Path $key -Name 'FaceName' -Value $originalFaceName.FaceName
400
+ }
401
+ if ($originalFontFamily) {
402
+ Set-ItemProperty -Path $key -Name 'FontFamily' -Value $originalFontFamily.FontFamily
403
+ }
404
+ }
405
+ ` , batFile ))
406
+
289
407
cmd .Stdout = os .Stdout
290
408
cmd .Stderr = os .Stderr
291
409
@@ -300,35 +418,52 @@ func runBypassCheck(config Config) error {
300
418
continue
301
419
}
302
420
303
- if testConnection (config .targetDomain , config .connectionTimeout ) {
421
+ // Check all domains
422
+ allDomainsWork := true
423
+ for _ , domain := range domains {
424
+ if ! testConnection (domain , config .connectionTimeout ) {
425
+ fmt .Printf ("%s[FAIL] Failed to establish connection to %s using pre-config: %s%s\n " ,
426
+ colorRed , domain , batFile , colorReset )
427
+ allDomainsWork = false
428
+ break
429
+ }
430
+ }
431
+
432
+ if allDomainsWork {
304
433
filename := filepath .Base (batFile )
305
- fmt .Printf ("\n %s!!!!!!!!!!!!!\n [SUCCESS] It seems, this pre-config is suitable for you - %s\n !!!!!!!!!!!!!\n %s\n " ,
434
+ fmt .Printf ("\n %s!!!!!!!!!!!!!\n [SUCCESS] It seems, this pre-config is suitable for all specified domains - %s\n !!!!!!!!!!!!!\n %s\n " ,
306
435
colorGreen , filename , colorReset )
307
436
cmd .Process .Kill ()
308
437
success = true
309
438
break
310
- } else {
311
- fmt .Printf ("%s[FAIL] Failed to establish connection using pre-config: %s%s\n " ,
312
- colorRed , batFile , colorReset )
313
- cmd .Process .Kill ()
314
439
}
440
+
441
+ cmd .Process .Kill ()
315
442
}
316
443
317
- // Final cleanup
318
444
ensureProcessTerminated (config .processName )
319
445
time .Sleep (500 * time .Millisecond )
320
446
ensureProcessTerminated (config .processName )
321
447
322
448
if ! success {
323
449
fmt .Println ("\n ------------------------------------------------" )
324
- fmt .Println ("Unfortunately, not found pre-config we can establish connection with :(" )
450
+ fmt .Println ("Unfortunately, not found pre-config we can establish connection with for all specified domains :(" )
325
451
fmt .Println ("Try to run BLOCKCHECK, to find necessary parameters for BAT file." )
326
452
}
327
453
328
454
return nil
329
455
}
330
456
331
457
func main () {
458
+ // Add signal handling at the start of main
459
+ c := make (chan os.Signal , 1 )
460
+ signal .Notify (c , os .Interrupt , syscall .SIGTERM )
461
+ go func () {
462
+ <- c
463
+ fmt .Print (showCursor + exitAltScreen )
464
+ os .Exit (1 )
465
+ }()
466
+
332
467
var buf bytes.Buffer
333
468
buf .Grow (bufferSize )
334
469
@@ -354,26 +489,28 @@ func main() {
354
489
return
355
490
}
356
491
fmt .Print (showCursor + exitAltScreen )
492
+ // Wait a bit to ensure new process starts
493
+ time .Sleep (1 * time .Second )
357
494
os .Exit (0 )
358
495
}
359
496
360
- targetDomain , err := getDomainChoice ()
497
+ targetDomains , err := getDomainChoice ()
361
498
if err != nil {
362
499
fmt .Printf ("Error: %v\n " , err )
363
500
return
364
501
}
365
502
366
503
config := Config {
367
504
batchDir : "pre-configs" ,
368
- targetDomain : targetDomain ,
505
+ targetDomain : strings . Join ( targetDomains , " " ) ,
369
506
processName : "winws.exe" ,
370
507
processWaitTime : 10 * time .Second ,
371
508
connectionTimeout : 5 * time .Second ,
372
509
}
373
510
374
511
// Use buffered output for all writes
375
512
buf .Reset ()
376
- buf .WriteString (fmt .Sprintf ("\n Starting testing domain : %s\n " , config .targetDomain ))
513
+ buf .WriteString (fmt .Sprintf ("\n Starting testing domains : %s\n " , config .targetDomain ))
377
514
output .Write (buf .Bytes ())
378
515
output .Flush ()
379
516
0 commit comments