- PVSM.RU - https://www.pvsm.ru -

Немного извращений из мира прокси и VPN

XTLS-Reality, XHTTP, Naiveproxy и всякие там AnyTLS - это не интересно. Давайте копнем чуть глубже и посмотрим, где прячется настоящее безумие. Особенно учитывая, что мы живем во времена, когда даже самые, казалось бы, безумные вещи, могут оказаться весьма полезными чтобы не сойти с ума.

Немного извращений из мира прокси и VPN - 1

Pingtunnel

Идея классическая и простая как будерброд. ICMP пакеты могут нести полезную информацию. Полезную в смысле не “проверить, жив ли хост на той стороне”, а натурально какую-то стопку байт, которая, будут отправлена с клиента, будет получена сервером (если по пути не произойдет ничего плохого). А раз так, ничего не межает проксироваться через него. Самая известная реализация идеи - Pingtunnel [1]. Сервер запускается и настраивается до смешного просто: отключили в sysctl системные ответы на пинги, чтобы не мешали, закинули бинарник на VPS [2], запустили его с ключом -server:

./pingtunnel -type server

И радуемся. Опционально можно добавить параметр -key с числом в диапазоне 0-2147483647 - это не полноценное шифрование (шифрование делает уже клиентский софт своим обычным TLS), а скорее простенькая защита от любопытных глаз, чтобы пакеты выглядели как случайный набор байт.

На клиенте - тот же самый бинарник, только с клиентскими параметрами:

pingtunnel -type client -l :4455 -s www.yourserver.com [3] -sock5 1

(открывает socks-прокси на порту 4455),
А на Windows, Linux и - тадам! - Android можно использовать и красивый клиент itismoej/pingtunnel-client [4] 

Добавляем там новое подключение с URL типа pingtunnel://your-server-ip?key=XXX&mode=vpn, нажимаем Connect, и поехали.

Под Windows там есть баг в виде криво собранного бандла, что при попытке запустить подключение оно падает с “Unable to load asset” ошибкой, решается созданием папки assets/binaries/pingtunnel/windows-amd64, закидыванием в нее pingtunnel.exe, и выставлением переменной окружения PINGTUNNEL_ASSETS_DIR пути корня этой папки (там где лежит дира assets).

Ну и имейте в виду, что на Pingtunnel агрятся многие антивирусы, определяя его как HackTool, видимо потому что какие-то малвари использовали его в качестве транспорта.

Как оно работает? Ну, где как. При белых списках ICMP иногда не ходит вообще даже до белосписочных адресов, но кое-где ходит исправно почти куда угодно. У некоторых хостеров могут триггернуться фаерволлы, посчитав большой поток ICMP-пакетов с одного адреса DDoS-атакой. Но в остальных случаях - оно работает очень даже неплохо!

Важно: в Google Play и на гитхабе есть еще один PingTunnel клиент для Android от HexaSoftware (и гугл выдает его в первых строках по таким запросам). Его не советую - он работает как говно, иногда вообще не подключается, или работает очень медленно, что серфить невозможно. Лучше пользоваться тем клиентом, ссылка на который была ваше.

Кстати, в XRay теперь есть аналогичный транспорт XICMP, правда реализация еще сырая, и документации, по традиции, почти никакой. А знаете где есть еще ICMP-туннель? В War Thunder в GoST, замечательном комбайне, про который рассказывалось в этой статье: GOST: швейцарский нож для туннелирования и обхода блокировок / Хабр [5]

DNSTT, Slipstream, MasterDnsVpn

Тут идея другая - использование DNS для проксирования. Важно понять следущее: речь идет не про простое заворачивание ваших данных в пакеты DNS-протокола и посылки их на ваш сервер. Нет и нет. Тут именно что используются публичные DNS-сервера (например, вашего провайдера). Клиент делает DNS-запрос касательно домена qJdESz0gPBiqojX1jK6kOLn1FAlnEuF9enklEWHlPpQ.yourdomain.com. DNS-сервер вашего провайдера без понятия, что это за такой домен, поэтому он спрашивает ns.yourdomain.com (который тоже управляется вами) “Эй, брат, скажи - что это там у тебя за поддомен?”. А тот отвечает: у этого домена есть TXT-запись со значением “alWXjPTjL0LwKN-Q3gtd25fkVN73UwPk2XEupyG6Rgc” (где тоже закодирована передаваемая информация), а DNS-сервер вашего провайдера это знание передает обратно клиенту. Вот так оно и гоняет данные-туда сюда, используя только провайдерский (или еще какой) DNS.

Естественно, при наивной реализации работает оно очень медленно и ненадежно, поэтому умные люди стали думать, как это оптимизировать.
Самымы старым и известным вариантом является DNSTT, использующий алгоритмы из протокола KCP. На хабре есть замечательная статья DNSTT. DNS туннель для обхода блокировок / Хабр [6] про его настройку. В XRay, судя по всему, очень похожая реализация недавно появилась под именем XDNS, но я не проверял - и времени не было, и DNSTT сам по себе уже прошлый век.

А теперь к более современным вариантам. Знакомьтесь: SlipStream. Почти то же самое, но использует механизмы протокола QUIC, и да - работает гораздо быстрее.

Оригинальная реализация: EndPositive/slipstream: High-performance multi-path covert channel over DNS [7]  - довольно глючная и забагованная,

но есть еще переписанная на Rust Mygod/slipstream-rust: High-performance multi-path covert channel over DNS in Rust with vibe coding [8] - и она работает очень хорошо.

Из мобильных клиентов я пробовал DNSTT.XYZ [9] (не смотря на название, он поддерживает SlipStream) и SlipNet Lite [10] (у него не пермиссивная лицензия, но очень хорош).
Есть и другие клиенты разной степени хорошести, например плагин для Shadowsocks: Mygod/slipstream-plugin-android: SIP003 Android plugin using slipstream-rust [11] 

А теперь тяжелая артиллерия - MasterDnsVPN [12]. Как говорит автор,
“По своей основной цели он похож на такие проекты, как DNSTT или SlipStream, но имеет принципиально иную структуру и подход к реализации. Эта система разработана с учетом совместимости со многими типами поведения резолверов и сложными сетевыми условиями, с целью сохранения максимально возможной стабильности и доставки данных даже в наихудших случаях.”

И у него действительно получилось. Среди всех мною попробованных протоколов, он самый быстрый и стабильный, а в сравнении с оригинальным DNSTT так просто небо и земля. Плюс огромное количество параметров, которые можно подкрутить для тонкой настройки.

Консольный клиент работает где угодно и на чем угодно, а еще есть два неплохих клиента для Android:

(второй мне нравится больше, первый как-то неаккуратно сделан).

Основной вопрос - какие DNS использовать. Некоторые публичные DNS могут оказаться недоступными в некоторых условиях. Некоторые DNS-сервера могут иметь ratelimit, в результате чего, например, через такой туннель через них еще можно будет как-то переписываться в Telegram и очень неспешно серфить, но вот видео уже не посмотришь. А еще может быть, что провайдер перехватывает все нешифрованные запросы на 53 UDP-порт и переадресовывает их на свои сервера (но так делают далеко не все).

Поэтому стоит действовать так: сначала пробуем провайдерские DNS (не все клиенты умеют подхватывать их автоматически, стоит посмотреть в параметрах соединения и вбить вручную адреса), потом пробуем публичные типа 8.8.8.8 и 1.1.1.1 (вдруг доступны?), еще есть DNS-сервер MSK-IX 62.76.76.62, и верх цинизма - сервер НСДИ от Роскомнадзора 195.208.4.1 :)

Если ничего из вышеперечисленного не подходит, то идем куда-нибудь сюда: DNS servers in Russian Federation [15], скачиваем список в виде текстового файла, заталкиваем в клиент, и пусть он проверяет. А чтобы не пришлось проверять слишком много, можно использовать простой Python-скрипт, который для начала отсечет точно недоступные варианты:

Скрипт тут
#!/usr/bin/env python3
"""
Usage:
    ./resolve_check.py <ip_list_file> <domain> <output_file> [--timeout 3] [--workers 50]
"""

import argparse
import ipaddress
import sys
from concurrent.futures import ThreadPoolExecutor, as_completed

import dns.resolver
import dns.exception


def load_ipv4_addresses(path: str) -> list[str]:
    """Read file, return unique IPv4 addresses preserving order."""
    seen = set()
    ips = []
    with open(path, "r", encoding="utf-8") as f:
        for line_no, raw in enumerate(f, 1):
            line = raw.strip()
            if not line or line.startswith("#"):
                continue
            try:
                addr = ipaddress.ip_address(line)
            except ValueError:
                print(f"[skip] line {line_no}: not an IP -> {line}", file=sys.stderr)
                continue
            if not isinstance(addr, ipaddress.IPv4Address):
                continue  # ignore IPv6
            s = str(addr)
            if s not in seen:
                seen.add(s)
                ips.append(s)
    return ips


def can_resolve(ip: str, domain: str, timeout: float) -> bool:
    """Return True if `ip` (used as DNS server) successfully resolves `domain`."""
    resolver = dns.resolver.Resolver(configure=False)
    resolver.nameservers = [ip]
    resolver.timeout = timeout       # per-try
    resolver.lifetime = timeout      # total
    try:
        answer = resolver.resolve(domain, "A")
        return len(answer) > 0
    except (dns.resolver.NoAnswer,
            dns.resolver.NXDOMAIN,
            dns.resolver.NoNameservers,
            dns.exception.Timeout,
            dns.exception.DNSException,
            OSError):
        return False


def main() -> int:
    p = argparse.ArgumentParser(description="Test which IPv4 addresses can resolve a domain.")
    p.add_argument("input", help="File with IP addresses, one per line")
    p.add_argument("domain", help="Domain name to resolve, e.g. example.com")
    p.add_argument("output", help="File to write working DNS server IPs to")
    p.add_argument("--timeout", type=float, default=3.0, help="DNS timeout in seconds (default 3)")
    p.add_argument("--workers", type=int, default=50, help="Parallel queries (default 50)")
    args = p.parse_args()

    ips = load_ipv4_addresses(args.input)
    if not ips:
        print("No IPv4 addresses found in input.", file=sys.stderr)
        return 1

    print(f"Testing {len(ips)} IPv4 address(es) against domain '{args.domain}'...")

    working: list[str] = []
    with ThreadPoolExecutor(max_workers=args.workers) as pool:
        futures = {pool.submit(can_resolve, ip, args.domain, args.timeout): ip for ip in ips}
        for fut in as_completed(futures):
            ip = futures[fut]
            ok = False
            try:
                ok = fut.result()
            except Exception as e:
                print(f"[error] {ip}: {e}", file=sys.stderr)
            status = "OK " if ok else "FAIL"
            print(f"  {status}  {ip}")
            if ok:
                working.append(ip)

    # Preserve original input order in the output
    order = {ip: i for i, ip in enumerate(ips)}
    working.sort(key=lambda x: order[x])

    with open(args.output, "w", encoding="utf-8") as f:
        f.write("n".join(working) + ("n" if working else ""))

    print(f"nDone. {len(working)}/{len(ips)} resolved '{args.domain}'. Saved to {args.output}")
    return 0


if __name__ == "__main__":
    sys.exit(main())

Bridge To Freedom

А вот тут уже идет тяжелая наркомания. Если вы устали от попыток “поймать” белый IP-адрес в Яндекс-Облаке и подобных, или для вас это слишком дорого, то наверняка задумывались об использовании других их сервисов для проксирования. Из самых дешевых вариантов у них есть serverless functions. Это такая функция на каком-нибудь языке программирования, которая не имеет состояния, и единственная задача которой - родиться, обработать один или несколько входящих запросов и сдохнуть. Из-за ограниченности времени жизни функций, и еще более важно - из-за того, что входящие запросы к таким функциям проходят через очень строгий яндексовский API Gateway, то использовать XHTTP (а вы знаете, что XHTTP - это не инновация от авторов XRay, а эта идея была реализована еще за несколько лет до них в виде PHT в том же упомянутом выше GoST?) не получится. Зато оно все вполне официально поддерживает websockets. 

“Ага, значит это можно использовать для проксирования”, - подумал автор yac-ws-bridge, оно же Bridge To Freedom [16].

Serverless-функция может реагировать на события “open”, “close”, “ondata”, и сама посылать данные в уже установленное соединение. Поэтому автор yac-ws-bridge попробовал сначала сделать “прозрачный” (не требующий каких-либо модификаций клиента) прокси, но работало оно ужасно - через API Gateway пакеты с данными могли прилетать в неправильной последовательности, что ломало TLS и HTTP - Telegram еще как-то работал со скрипом, но серфить было очень тяжело с кучей обрывов.

Был еще вариант, где вместо оперирования TCP-потоками оно пересылало IP-пакеты (как в полноценном VPN), чтобы восстановление порядка данных и потерянных частей занимался TCP-стек операционной системы - оно работало, но очень медленно.

В итоге самым стабильным оказался вариант со своим собственным протоколом мультиплексирования и восстановления порядка пакетов, плюс если у клиента доступен не только endpoint serverless-функции, но API Gateway Яндекса, то функция используется вообще только для того, чтобы клиент и сервер “нашли” друг друга (узнали ID вебсокет-подключений друг друга), а дальше данные шлются между ними напрямую через API яндекса, и в итоге все работает гораздо быстрее. 

Позавчера (15.05.26) появилось вот такое обновление:

Эта версия серьёзно оптимизирована. Хелпер теперь переупорядочивает фреймы по SeqID на приёме, пред-регистрирует stream до отправки OPEN (так что первые DATA-пакеты после OPEN_OK больше не теряются), использует асинхронную очередь записи на каждый stream (медленный локальный клиент больше не блокирует все остальные streams), и корректно делает half-close по FIN (HTTP-ответы больше не обрываются). На практике: подключение устанавливается заметно быстрее, и туннель работает значительно стабильнее, особенно на мобильных устройствах. 

Я попробовал, и оно действительно теперь работает достаточно быстро и стабильно - у меня получилось выдавить 40 мегабит на прием и 5 на отдачу.

В README есть подробное объяснение работы, инструкция по настройке серверной части и заливки serverless-функции в Яндекс. Функцию рекомендуется обязательно обфусцировать перед заливкой и поменять все пути со стандартных на нестандартные, чтобы Яндекс вас сразу не забанил.

В той же репе есть графический клиент для этого дела. Поскольку задача BTF - проброс TCP-потока, то работает он в паре в SOCKS- или VLESS-прокси, например v2RayN или v2rayNG: в v2RayN/v2RayNG вы настраиваете SOCKS- или VLESS-подключение к серверу, но обращаетесь на адрес localhost [17], где слушает BTF, он через инфраструктуру Яндекса передает все к вашему серверу, где подключается тоже на localhost [17], на котором слушает XRay или Dante. И все работает.

Клиент написан на .NET MAUI, есть сборки под Windows и под Android. Можно собрать под iOS самостоятельно, но понадобится Apple Developer Account, а еще MAUI теперь поддерживает сборку под Linux с бэкендами Avalonia и GTK4, поэтому в теории можно собраться и под Linux (ну либо использовать консольный Go-клиент, который работает везде).

Аудио-видеозвонки в мессенджерах

Nuff said. Тут без подробностей, ограничусь только ссылками:
KillTheCensorship/Turnel [18] (уже не поддерживается, но может быть полезным для изучения, как оно сделано)
nil2x/cheburnet: Обход белого списка с помощью ВК. [19]
TheAirBlow/Turnable: VPN core for stealthy tunneling through TURN or via SFU [20] (пока что самый подвинутый вариант).

Да прибудет с вами сила.

Автор: MiracleUsr

Источник [21]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/vpn/451770

Ссылки в тексте:

[1] Pingtunnel: https://esrrhs.github.io/pingtunnel/

[2] VPS: https://www.reg.ru/?rlink=reflink-717

[3] www.yourserver.com: http://www.yourserver.com

[4] itismoej/pingtunnel-client: https://github.com/itismoej/pingtunnel-client

[5] GOST: швейцарский нож для туннелирования и обхода блокировок / Хабр: https://habr.com/ru/articles/777656/

[6] DNSTT. DNS туннель для обхода блокировок / Хабр: https://habr.com/ru/articles/757420/

[7] EndPositive/slipstream: High-performance multi-path covert channel over DNS: https://github.com/EndPositive/slipstream

[8] Mygod/slipstream-rust: High-performance multi-path covert channel over DNS in Rust with vibe coding: https://github.com/Mygod/slipstream-rust

[9] DNSTT.XYZ: http://DNSTT.XYZ

[10] SlipNet Lite: https://github.com/anonvector/SlipNet

[11] Mygod/slipstream-plugin-android: SIP003 Android plugin using slipstream-rust: https://github.com/Mygod/slipstream-plugin-android

[12] MasterDnsVPN: https://github.com/masterking32/MasterDnsVPN

[13] Hidden-Node/MasterDnsVPN-AndroidClient: MasterDnsVPN Android client (community build) based on the upstream Go core—install signed APKs from Releases and connect to your own MasterDnsVPN server (domain/key/resolvers).: https://github.com/Hidden-Node/MasterDnsVPN-AndroidClient

[14] RevocGG/MasterDnsVPN-AndroidGG: MasterDnsVPN Android Client: https://github.com/RevocGG/MasterDnsVPN-AndroidGG

[15] DNS servers in Russian Federation: https://public-dns.info/nameserver/ru.html

[16] yac-ws-bridge, оно же Bridge To Freedom: https://github.com/noiseonwires/yac-ws-bridge

[17] localhost: http://localhost

[18] KillTheCensorship/Turnel: https://github.com/KillTheCensorship/Turnel

[19] nil2x/cheburnet: Обход белого списка с помощью ВК.: https://github.com/nil2x/cheburnet

[20] TheAirBlow/Turnable: VPN core for stealthy tunneling through TURN or via SFU: https://github.com/TheAirBlow/Turnable

[21] Источник: https://habr.com/ru/articles/1036100/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1036100