В этой короткой статье я расскажу, как определить IP-адреса, которые использует Telegram. А что делать с этой информацией дальше - решайте сами.

Мне нужно было автоматизировать блокировку богоненавистного Telegram в своей сети. Сначала я пытался блокировать его по всем известным доменам: это давало лишь частичный эффект, а в последний месяц такой способ практически перестал работать. Затем я пробовал использовать публично доступные списки IP-адресов Telegram, например такие:

91.108.56.0/22
91.108.4.0/22
91.108.8.0/22
91.108.16.0/22
91.108.12.0/22
149.154.160.0/20
91.105.192.0/23
91.108.20.0/22
185.76.151.0/24
2001:b28:f23d::/48
2001:b28:f23f::/48
2001:67c:4e8::/48
2001:b28:f23c::/48
2a0a:f280::/32

Но и это не помогло: Telegram продолжал просачиваться. Тогда я решил пойти другим путем - получать IP-адреса прямо из запущенного клиента Telegram и фиксировать все адреса, к которым он подключается. И о чудо, это сработало!

Предполагаю, что Telegram использует разные IP-адреса в зависимости от региона, CDN и других условий, поэтому статические списки быстро теряют актуальность. Именно поэтому я и написал этот небольшой материал.

Я сделал PowerShell-скрипт, который отслеживает приложение Telegram в Windows, собирает IP-адреса его соединений и сразу передает их на роутер OpenWRT по ssh для добавления в список блокировки. После этого Telegram у меня стабильно блокируется. Минус - нужно держать скрипт включенным всегда.

Пользуйтесь.

Маршрутизация на OpenWRT у меня настроена по этой статье:

https://habr.com/ru/articles/767464/

param(
    [string]$ProcessName = "Telegram",
    [string]$OutputFile = ".\telegram_ips.txt",
    [int]$PollSeconds = 3,

    [string]$RouterHost = "192.168.1.1",
    [string]$RouterUser = "root",
    [string]$NftFamily = "inet",
    [string]$NftTable = "fw4",
    [string]$NftSet = "vpn_domains",

    [bool]$UseTimeout = $false,
    [string]$TimeoutValue = "1h",

    [string]$SshKeyPath = "$env:USERPROFILE\.ssh\openwrt_ed25519"
)

[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8

$seen = [System.Collections.Generic.HashSet[string]]::new()

if (Test-Path $OutputFile) {
    Get-Content $OutputFile | ForEach-Object {
        $ip = $_.Trim()
        if ($ip) {
            [void]$seen.Add($ip)
        }
    }
}

function Test-PublicIPv4([string]$ip) {
    try {
        $addr = [System.Net.IPAddress]::Parse($ip)
    } catch {
        return $false
    }

    if ($addr.AddressFamily -ne [System.Net.Sockets.AddressFamily]::InterNetwork) {
        return $false
    }

    $b = $addr.GetAddressBytes()

    if ($b[0] -eq 10) { return $false }
    if ($b[0] -eq 127) { return $false }
    if ($b[0] -eq 169 -and $b[1] -eq 254) { return $false }
    if ($b[0] -eq 172 -and $b[1] -ge 16 -and $b[1] -le 31) { return $false }
    if ($b[0] -eq 192 -and $b[1] -eq 168) { return $false }
    if ($b[0] -eq 100 -and $b[1] -ge 64 -and $b[1] -le 127) { return $false }
    if ($ip -eq "0.0.0.0") { return $false }

    if ($ip -eq "8.8.8.8") { return $false }
    if ($ip -eq "8.8.4.4") { return $false }
    if ($ip -eq "1.1.1.1") { return $false }
    if ($ip -eq "1.0.0.1") { return $false }

    return $true
}

function Add-IpToOpenWrt([string]$ip) {
    $target = "$RouterUser@$RouterHost"

    if ($UseTimeout) {
        $remoteCmd = "nft add element $NftFamily $NftTable $NftSet { $ip timeout $TimeoutValue } 2>/dev/null || true"
    } else {
        $remoteCmd = "nft add element $NftFamily $NftTable $NftSet { $ip } 2>/dev/null || true"
    }

    & ssh `
        -i $SshKeyPath `
        -o IdentitiesOnly=yes `
        -o BatchMode=yes `
        $target `
        $remoteCmd | Out-Null

    return $LASTEXITCODE
}

Write-Host "Watching process $ProcessName"
Write-Host "IPs file: $OutputFile"
Write-Host "OpenWrt target: $RouterUser@$RouterHost"
Write-Host "SSH key: $SshKeyPath"
Write-Host "nft set: $NftFamily $NftTable $NftSet"
Write-Host "Stop: Ctrl+C"
Write-Host ""

while ($true) {
    $procs = Get-Process -Name $ProcessName -ErrorAction SilentlyContinue

    if ($procs) {
        $pids = @($procs | Select-Object -ExpandProperty Id)

        $connections = Get-NetTCPConnection -ErrorAction SilentlyContinue |
            Where-Object {
                $_.State -eq "Established" -and
                $pids -contains $_.OwningProcess
            } |
            Select-Object -ExpandProperty RemoteAddress -Unique

        foreach ($ip in $connections) {
            if (-not (Test-PublicIPv4 $ip)) {
                continue
            }

            if ($seen.Add($ip)) {
                Add-Content -Path $OutputFile -Value $ip
                Write-Host "New IP found: $ip"

                $rc = Add-IpToOpenWrt $ip
                if ($rc -eq 0) {
                    Write-Host "Added to OpenWrt: $ip"
                } else {
                    Write-Host "SSH/nft failed for: $ip (exit code $rc)"
                }
            }
        }
    }

    Start-Sleep -Seconds $PollSeconds
}