test zapret.ps1 dpi suite v2 (#11349)

This commit is contained in:
Petr Osetrov
2026-03-26 07:01:59 +03:00
committed by GitHub
parent 9a1ce92593
commit 05ec945a05

View File

@@ -77,29 +77,25 @@ function Convert-Target {
# DPI checker defaults (override via MONITOR_* env vars like in monitor.ps1) # DPI checker defaults (override via MONITOR_* env vars like in monitor.ps1)
$dpiTimeoutSeconds = 5 $dpiTimeoutSeconds = 5
$dpiRangeBytes = 262144 $dpiRangeBytes = 65536
$dpiWarnMinKB = 14
$dpiWarnMaxKB = 22
$dpiMaxParallel = 8 $dpiMaxParallel = 8
$dpiCustomUrl = $env:MONITOR_URL $dpiCustomHost = $env:MONITOR_HOST
if ($env:MONITOR_TIMEOUT) { [int]$dpiTimeoutSeconds = $env:MONITOR_TIMEOUT } if ($env:MONITOR_TIMEOUT) { [int]$dpiTimeoutSeconds = $env:MONITOR_TIMEOUT }
if ($env:MONITOR_RANGE) { [int]$dpiRangeBytes = $env:MONITOR_RANGE } if ($env:MONITOR_RANGE) { [int]$dpiRangeBytes = $env:MONITOR_RANGE }
if ($env:MONITOR_WARN_MINKB) { [int]$dpiWarnMinKB = $env:MONITOR_WARN_MINKB }
if ($env:MONITOR_WARN_MAXKB) { [int]$dpiWarnMaxKB = $env:MONITOR_WARN_MAXKB }
if ($env:MONITOR_MAX_PARALLEL) { [int]$dpiMaxParallel = $env:MONITOR_MAX_PARALLEL } if ($env:MONITOR_MAX_PARALLEL) { [int]$dpiMaxParallel = $env:MONITOR_MAX_PARALLEL }
function Get-DpiSuite { function Get-DpiSuite {
# Suite sourced from https://github.com/hyperion-cs/dpi-checkers (Apache-2.0 license) # Suite sourced from https://github.com/hyperion-cs/dpi-checkers (Apache-2.0 license)
# Original copyright retained from dpi-checkers repository # Original copyright retained from dpi-checkers repository
$url = "https://hyperion-cs.github.io/dpi-checkers/ru/tcp-16-20/suite.json" $url = "https://hyperion-cs.github.io/dpi-checkers/ru/tcp-16-20/suite.v2.json"
try { try {
(Invoke-RestMethod -Uri $url -TimeoutSec $dpiTimeoutSeconds) | (Invoke-RestMethod -Uri $url -TimeoutSec $dpiTimeoutSeconds) |
Select-Object ` Select-Object `
@{n='Id'; e={$_.id}}, @{n='Id'; e={$_.id}},
@{n='Provider'; e={$_.provider}}, @{n='Provider'; e={$_.provider}},
@{n='Url'; e={$_.url}}, @{n='Сountry'; e={$_.country}},
@{n='Times'; e={$_.times}} @{n='Host'; e={$_.host}}
} }
catch { catch {
Write-Host "[WARN] Fetch dpi suite failed." -ForegroundColor Yellow Write-Host "[WARN] Fetch dpi suite failed." -ForegroundColor Yellow
@@ -109,23 +105,17 @@ function Get-DpiSuite {
function Build-DpiTargets { function Build-DpiTargets {
param( param(
[string]$CustomUrl [string]$CustomHost
) )
$suite = Get-DpiSuite $suite = Get-DpiSuite
$targets = @() $targets = @()
if ($CustomUrl) { if ($CustomHost) {
$targets += @{ Id = "CUSTOM"; Provider = "Custom"; Url = $CustomUrl } $targets += @{ Id = "CUSTOM"; Provider = "Custom"; Сountry = "💡"; Host = $CustomHost }
} else { } else {
foreach ($entry in $suite) { foreach ($entry in $suite) {
$repeat = $entry.Times $targets += @{ Id = $entry.Id; Сountry = $entry.Сountry; Provider = $entry.Provider; Host = $entry.Host }
if (-not $repeat -or $repeat -lt 1) { $repeat = 1 }
for ($i = 0; $i -lt $repeat; $i++) {
$suffix = ""
if ($repeat -gt 1) { $suffix = "@$i" }
$targets += @{ Id = "$($entry.Id)$suffix"; Provider = $entry.Provider; Url = $entry.Url }
}
} }
} }
@@ -137,8 +127,6 @@ function Invoke-DpiSuite {
[array]$Targets, [array]$Targets,
[int]$TimeoutSeconds, [int]$TimeoutSeconds,
[int]$RangeBytes, [int]$RangeBytes,
[int]$WarnMinKB,
[int]$WarnMaxKB,
[int]$MaxParallel [int]$MaxParallel
) )
@@ -151,45 +139,57 @@ function Invoke-DpiSuite {
$rangeSpec = "0-$($RangeBytes - 1)" $rangeSpec = "0-$($RangeBytes - 1)"
$warnDetected = $false $warnDetected = $false
Write-Host "[INFO] Targets: $($Targets.Count) (custom URL overrides suite). Range: $rangeSpec bytes; Timeout: $TimeoutSeconds s; Warn window: $WarnMinKB-$WarnMaxKB KB" -ForegroundColor Cyan Write-Host "[INFO] Targets: $($Targets.Count) (custom URL overrides suite). Range: $rangeSpec bytes; Timeout: $($TimeoutSeconds)s" -ForegroundColor Cyan
Write-Host "[INFO] Starting DPI TCP 16-20 checks (parallel: $MaxParallel)..." -ForegroundColor DarkGray Write-Host "[INFO] Starting DPI TCP 16-20 checks (parallel: $MaxParallel)..." -ForegroundColor DarkGray
$runspacePool = [runspacefactory]::CreateRunspacePool(1, $MaxParallel) $runspacePool = [runspacefactory]::CreateRunspacePool(1, $MaxParallel)
$runspacePool.Open() $runspacePool.Open()
$payload = New-Object byte[] $RangeBytes
[System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($payload)
$payloadFile = New-TemporaryFile
[IO.File]::WriteAllBytes($payloadFile, $payload)
$scriptBlock = { $scriptBlock = {
param($target, $tests, $rangeSpec, $TimeoutSeconds, $WarnMinKB, $WarnMaxKB) param($payloadFile, $target, $tests, $rangeSpec, $TimeoutSeconds)
$warned = $false $warned = $false
$lines = @() $lines = @()
foreach ($test in $tests) { foreach ($test in $tests) {
$curlArgs = @( $curlArgs = @(
"-L",
"--range", $rangeSpec, "--range", $rangeSpec,
"-m", $TimeoutSeconds, "-m", $TimeoutSeconds,
"-w", "%{http_code} %{size_download}", "-w", "%{http_code} %{size_upload} %{size_download} %{time_total}",
"-o", "NUL", "-o", "NUL",
"-X", "POST",
"--data-binary", "@$payloadFile",
"-s" "-s"
) + $test.Args + $target.Url ) + $test.Args + @("https://$($target.Host)")
$output = & curl.exe @curlArgs 2>&1 $output = $payload | curl.exe @curlArgs 2>&1
$exit = $LASTEXITCODE $exit = $LASTEXITCODE
$text = ($output | Out-String).Trim() $text = ($output | Out-String).Trim()
$code = "NA" $code = "NA"
$sizeBytes = 0 $upBytes = 0
$downBytes = 0
$time = -1
if ($text -match '^(?<code>\d{3})\s+(?<size>\d+)$') { if ($text -match '^(?<code>\d{3})\s+(?<up>\d+)\s+(?<down>\d+)\s+(?<time>[\d\.]+)$') {
$code = $matches['code'] $code = $matches['code']
$sizeBytes = [int64]$matches['size'] $upBytes = [int64]$matches['up']
$downBytes = [int64]$matches['down']
$time = [double]$matches['time']
} elseif (($exit -eq 35) -or ($text -match "not supported|does not support|protocol\s+'.+'\s+not\s+supported|protocol\s+.+\s+not\s+supported|unsupported protocol|TLS.not supported|Unrecognized option|Unknown option|unsupported option|unsupported feature|schannel|SSL")) { } elseif (($exit -eq 35) -or ($text -match "not supported|does not support|protocol\s+'.+'\s+not\s+supported|protocol\s+.+\s+not\s+supported|unsupported protocol|TLS.not supported|Unrecognized option|Unknown option|unsupported option|unsupported feature|schannel|SSL")) {
$code = "UNSUP" $code = "UNSUP"
} elseif ($text) { } elseif ($text) {
$code = "ERR" $code = "ERR"
} }
$sizeKB = [math]::Round($sizeBytes / 1024, 1) $upKB = [math]::Round($upBytes / 1024, 1)
$downKB = [math]::Round($downBytes / 1024, 1)
$status = "OK" $status = "OK"
$color = "Green" $color = "Green"
@@ -201,19 +201,20 @@ function Invoke-DpiSuite {
$color = "Red" $color = "Red"
} }
if (($sizeKB -ge $WarnMinKB) -and ($sizeKB -le $WarnMaxKB) -and ($exit -ne 0)) { if (($upBytes -gt 0) -and ($downBytes -eq 0) -and ($time -ge $TimeoutSeconds) -and ($exit -ne 0)) {
$status = "LIKELY_BLOCKED" $status = "LIKELY_BLOCKED"
$color = "Yellow" $color = "Yellow"
$warned = $true $warned = $true
} }
$lines += [PSCustomObject]@{ $lines += [PSCustomObject]@{
TargetId = $target.Id
Provider = $target.Provider
TestLabel = $test.Label TestLabel = $test.Label
Code = $code Code = $code
SizeBytes = $sizeBytes UpBytes = $upBytes
SizeKB = $sizeKB UpKB = $upKB
DownBytes = $downBytes
DownKB = $downKB
Time = $time
Status = $status Status = $status
Color = $color Color = $color
Warned = $warned Warned = $warned
@@ -223,6 +224,7 @@ function Invoke-DpiSuite {
return [PSCustomObject]@{ return [PSCustomObject]@{
TargetId = $target.Id TargetId = $target.Id
Provider = $target.Provider Provider = $target.Provider
Сountry = $target.Сountry
Lines = $lines Lines = $lines
Warned = $warned Warned = $warned
} }
@@ -231,17 +233,17 @@ function Invoke-DpiSuite {
$runspaces = @() $runspaces = @()
foreach ($target in $Targets) { foreach ($target in $Targets) {
$powershell = [powershell]::Create().AddScript($scriptBlock) $powershell = [powershell]::Create().AddScript($scriptBlock)
[void]$powershell.AddArgument($payloadFile)
[void]$powershell.AddArgument($target) [void]$powershell.AddArgument($target)
[void]$powershell.AddArgument($tests) [void]$powershell.AddArgument($tests)
[void]$powershell.AddArgument($rangeSpec) [void]$powershell.AddArgument($rangeSpec)
[void]$powershell.AddArgument($TimeoutSeconds) [void]$powershell.AddArgument($TimeoutSeconds)
[void]$powershell.AddArgument($WarnMinKB)
[void]$powershell.AddArgument($WarnMaxKB)
$powershell.RunspacePool = $runspacePool $powershell.RunspacePool = $runspacePool
$runspaces += [PSCustomObject]@{ $runspaces += [PSCustomObject]@{
Powershell = $powershell Powershell = $powershell
Handle = $powershell.BeginInvoke() Handle = $powershell.BeginInvoke()
TargetId = $target.Id
} }
} }
@@ -254,7 +256,7 @@ function Invoke-DpiSuite {
if ($handle -and $handle.AsyncWaitHandle) { if ($handle -and $handle.AsyncWaitHandle) {
$completed = $handle.AsyncWaitHandle.WaitOne($waitMs) $completed = $handle.AsyncWaitHandle.WaitOne($waitMs)
if (-not $completed) { if (-not $completed) {
Write-Host "[WARN] Runspace for target timed out after $waitMs ms; stopping runspace..." -ForegroundColor Yellow Write-Host "[WARN] Runspace for [$($rs.TargetId)] timed out after $waitMs ms; stopping runspace..." -ForegroundColor Yellow
try { $rs.Powershell.Stop() } catch {} try { $rs.Powershell.Stop() } catch {}
} }
} }
@@ -263,7 +265,23 @@ function Invoke-DpiSuite {
} }
try { try {
$results += $rs.Powershell.EndInvoke($rs.Handle) $res = $rs.Powershell.EndInvoke($rs.Handle)
$results += $res
Write-Host "`n=== [$($res.Сountry)][$($res.Provider)] $($res.TargetId) ===" -ForegroundColor DarkCyan
foreach ($line in $res.Lines) {
$msg = "[{0}] code={1} buf_up={2} bytes ({3} KB) buf_down={4} bytes ({5} KB) time={6}s status={7}" -f $line.TestLabel, $line.Code, $line.UpBytes, $line.UpKB, $line.DownBytes, $line.DownKB, $line.Time, $line.Status
Write-Host $msg -ForegroundColor $line.Color
if ($line.Status -eq "LIKELY_BLOCKED") {
Write-Host " Pattern matches 16-20KB freeze; censor likely cutting this strategy." -ForegroundColor Yellow
}
}
if ($res.Warned) {
$warnDetected = $true
} else {
Write-Host " No 16-20KB freeze pattern for this target." -ForegroundColor Green
}
} catch { } catch {
Write-Host "[WARN] EndInvoke failed for a runspace; treating as failure." -ForegroundColor Yellow Write-Host "[WARN] EndInvoke failed for a runspace; treating as failure." -ForegroundColor Yellow
$failedLine = [PSCustomObject]@{ $failedLine = [PSCustomObject]@{
@@ -282,24 +300,6 @@ function Invoke-DpiSuite {
$runspacePool.Close() $runspacePool.Close()
$runspacePool.Dispose() $runspacePool.Dispose()
foreach ($res in $results) {
Write-Host "`n=== $($res.TargetId) [$($res.Provider)] ===" -ForegroundColor DarkCyan
foreach ($line in $res.Lines) {
$msg = "[{0}][{1}] code={2} size={3} bytes ({4} KB) status={5}" -f $line.TargetId, $line.TestLabel, $line.Code, $line.SizeBytes, $line.SizeKB, $line.Status
Write-Host $msg -ForegroundColor $line.Color
if ($line.Status -eq "LIKELY_BLOCKED") {
Write-Host " Pattern matches 16-20KB freeze; censor likely cutting this strategy." -ForegroundColor Yellow
}
}
if (-not $res.Warned) {
Write-Host " No 16-20KB freeze pattern for this target." -ForegroundColor Green
} else {
$warnDetected = $true
}
}
if ($warnDetected) { if ($warnDetected) {
Write-Host "" Write-Host ""
Write-Host "[WARNING] Detected possible DPI TCP 16-20 blocking on one or more targets. Consider changing strategy/SNI/IP." -ForegroundColor Red Write-Host "[WARNING] Detected possible DPI TCP 16-20 blocking on one or more targets. Consider changing strategy/SNI/IP." -ForegroundColor Red
@@ -368,7 +368,7 @@ if ($hasErrors) {
exit 1 exit 1
} }
$dpiTargets = Build-DpiTargets -CustomUrl $dpiCustomUrl $dpiTargets = Build-DpiTargets -CustomHost $dpiCustomHost
# Config # Config
$targetDir = $rootDir $targetDir = $rootDir
@@ -793,7 +793,7 @@ try {
$globalResults += @{ Config = $file.Name; Type = 'standard'; Results = $targetResults } $globalResults += @{ Config = $file.Name; Type = 'standard'; Results = $targetResults }
} else { } else {
Write-Host " > Running DPI checkers..." -ForegroundColor DarkGray Write-Host " > Running DPI checkers..." -ForegroundColor DarkGray
$dpiResults = Invoke-DpiSuite -Targets $dpiTargets -TimeoutSeconds $dpiTimeoutSeconds -RangeBytes $dpiRangeBytes -WarnMinKB $dpiWarnMinKB -WarnMaxKB $dpiWarnMaxKB -MaxParallel $dpiMaxParallel $dpiResults = Invoke-DpiSuite -Targets $dpiTargets -TimeoutSeconds $dpiTimeoutSeconds -RangeBytes $dpiRangeBytes -MaxParallel $dpiMaxParallel
$globalResults += @{ Config = $file.Name; Type = 'dpi'; Results = $dpiResults } $globalResults += @{ Config = $file.Name; Type = 'dpi'; Results = $dpiResults }
} }