Перейти к содержимому
НовостиGitHubСкачать

Исходящий desync

Исходящий desync приспосабливает прямые соединения к сетям с DPI-фильтрацией. Он подключается как DIRECT и до отправки преобразует первый TLS ClientHello соединения: делит его на несколько TLS-записей или TCP-записей, может отправить часть с числом хопов, которое истечёт по пути, или с последующим срочным байтом, а первую передачу может заменить подделка с малым TTL. Сервер получает тот же handshake. Всё после ClientHello и соединения, которые начинаются не с него, проходят без изменений. Это не туннель, сервер ему не нужен. Преобразования берутся из библиотеки desync версии v0.1.0.

proxies:
- name: desync-yt
type: desync
tlsrec: "1+s" # позиции через запятую
# split: "2" # по желанию: отдельные TCP-записи
# split-delay: 0 # пауза между ними в мс, 0–1000
# split-wait: sent # sent | acked
# disorder: true # нужен split
# oob: true # нужен split
# random:
# tlsrec: [{ from: "-8+s", to: "8+s", count: 2 }]
# fake: { ttl: 4, prefix: -1, sni: [www.example.com], randomize: true }
# udp: { ttl: 4, template: quic, quic-only: true }
proxy-groups:
- name: youtube
type: fallback
proxies: [desync-yt, vpn-node] # сначала desync, узел прокси в резерве
url: https://www.youtube.com/generate_204
interval: 300
rules:
- DOMAIN-SUFFIX,youtube.com,youtube
- DOMAIN-SUFFIX,googlevideo.com,youtube
- MATCH,DIRECT
Ключ Что задаёт
tlsrec Где делить ClientHello на TLS-записи. 3 — байт 3 TLS-потока (считая от заголовка первой записи), 1+s — один байт после начала имени сервера, -2+s — два байта до него.
split Где делить его на отдельные TCP-записи, в той же нотации. Как поток делится на TCP-сегменты, решает операционная система.
split-delay Пауза между частями в миллисекундах, 0–1000. Нужны позиции разделения.
split-wait sent или acked: перед каждой следующей частью ждать, пока ядро сообщит, что все прежние байты отправлены или подтверждены сервером. Ожидание заканчивается, как только это сообщено, и никогда не заменяется паузой по времени. Нужны позиции разделения.
split-wait-timeout Предел каждого ожидания в миллисекундах, 0–60000 (по умолчанию 2000). Он же ограничивает ожидание disorder. Если время вышло, соединение закрывается.
disorder Первая часть уходит с числом хопов 1 и истекает на первом маршрутизаторе; TCP передаёт её повторно после того, как сервер получил следующие части (ByeDPI --disorder). Нужны позиции разделения; не сочетается со split-wait: acked.
oob После первой части отправляется один срочный (MSG_OOB) байт (ByeDPI --oob, вместе с disorder — --disoob). TCP сервера убирает его из потока. Нужны позиции разделения.
oob-byte Этот байт, один ASCII-символ (по умолчанию a). Нужен oob.
random Случайные разрезы для каждого соединения в дополнение к tlsrec/split: списки диапазонов в tlsrec и split, каждый { from, to, count, min-piece }. Диапазон даёт count разрезов (1–64, по умолчанию 1) из from..to (включительно, оба абсолютные или оба +s), не ближе min-piece байт друг к другу (по умолчанию 1); диапазон, который не помещается, обрезается. Не больше 16 диапазонов в списке. seed: 0 (по умолчанию) берёт новое зерно для каждого соединения; другое значение режет все соединения одинаково — для тестов и отчётов об ошибках. Случайные разрезы записей считаются позициями разделения.
fake Windows, Linux и Android. Первая передача префикса ClientHello несёт подделку с малым числом хопов, повторная — исходные байты. С позициями разделения (или с disorder, oob) конец префикса — ещё один разрез, и подделкой становится часть, которая на нём кончается; первая часть тогда должна остаться обычной, иначе запись завершится ошибкой до отправки. prefix считается после деления на записи, отрицательный — от конца (по умолчанию -1); timeout ограничивает системную отправку в миллисекундах (по умолчанию 3000). Не сочетается со split-wait: acked.
fake.ttl Число хопов подделки, 1–255. Обязателен без auto-ttl; с ним — запасное значение, когда путь не наблюдается (0 или не задан: такое соединение завершится ошибкой).
fake.auto-ttl { delta, min, max }: вывести число хопов из TTL пакета SYN-ACK сервера, хопы - delta в пределах min..max (по умолчанию 1, 3, 20; auto-ttl: {} берёт их). Наблюдается только на Linux и Android по IPv6, см. таблицу ниже.
fake.sni Список имён сервера для поддельного ClientHello, для каждого соединения выбирается одно; * заменяется случайной буквой или цифрой, ? — буквой, # — цифрой. Только DNS-имена, не больше 64.
fake.randomize Новые random, session ID и key share в подделке для каждого соединения.
fake.from-original Строить подделку из собственного ClientHello соединения вместо встроенного шаблона. Нужен sni или randomize.
fake.offset Начинать подделку с этого байта, 0–65535, например чтобы совместить её с частью, которая начинается не с начала потока.
udp Перед каждой из первых packets (1–8, по умолчанию 3) датаграмм к адресату отправляет repeats (1–16, по умолчанию 6) датаграмм с малым TTL (ttl); исходные не меняются. Без udp UDP этого исходящего — обычный DIRECT.
udp.template zero (64 нулевых байта, по умолчанию) или quic: каждая серия — заново созданный QUIC v1 Initial для udp.sni (по умолчанию www.wikipedia.org).
udp.quic-only Серия только перед датаграммами, похожими на QUIC Initial клиента; остальной UDP проходит без изменений и не учитывается в packets.
interface-name, routing-mark, ip-version Как у direct.

Нужен хотя бы один из tlsrec, split, random, fake или udp. tfo, mptcp и dialer-proxy не принимаются: с TFO ClientHello ушёл бы вместе с SYN, до того как его можно разделить. Способ, который операционная система не реализует, — ошибка конфига с названием системы и причиной, а не молчаливый DIRECT.

Параметр Windows Linux Android macOS
tlsrec, split, split-delay, random ✓ ✓ ✓ ✓
split-wait: sent ✓¹ ✓ ✓⁵ —
split-wait: acked ✓¹ ✓ ✓ ✓
disorder ✓¹ ✓ ✓⁵ ✓²
oob, oob-byte ✓ ✓ ✓ ✓
fake (с sni, randomize, from-original, offset, частями) ✓ ✓ ✓⁵ —³
fake.auto-ttl только запасной ttl⁴ IPv6; IPv4 берёт запасной ttl⁴ IPv6; IPv4 берёт запасной ttl⁴ —
udp (с template, sni, quic-only) ✓ ✓ ✓ ✓

¹ Windows сообщает о ходе отправки счётчиками (SIO_TCP_INFO), а не состоянием очереди, поэтому ожидание может закончиться раньше. ² macOS не видит неотправленные байты: часть с малым числом хопов пишется, когда буфер отправки пуст, сама передача выводится, а не наблюдается. ³ macOS не может сделать так, чтобы повторная передача несла другие байты, чем первая. ⁴ На Windows, macOS и для IPv4 на Linux нет непривилегированного способа узнать TTL пакетов, полученных TCP-сокетом. auto-ttl без ttl — ошибка конфига на Windows и на Linux с ip-version: ipv4-only; на Linux с IPv6 он принимается, а соединение по IPv4 тогда завершится ошибкой при первой записи (в журнал пишется предупреждение). На Android здесь всё как на Linux. ⁵ Проверяется для каждого соединения: Android не даёт приложениям читать неотправленные байты сокета через SIOCOUTQNSD, поэтому они читаются из TCP_INFO, а для этого нужно ядро Linux 4.6 или новее. Конфиг принимается, в журнал пишется, что метод проверяется для каждого соединения; на ядре без этого поля соединение завершается ошибкой с названием метода до того, как что-либо отправлено. Ничто не заменяется паузой или другим методом.

Исходящий выбирается как любой другой: правила и группы ссылаются на него по имени, глобальный DIRECT не меняется. Проверки здоровья и URL-тесты исходящего проходят через преобразование, поэтому группа fallback или url-test переключится на узел прокси, когда маршрут через desync перестанет работать, и вернётся, когда он заработает. Имена он разрешает через direct-nameserver, как DIRECT, подключается к адресу, проверенному IP-правилом, и отклоняет собственное соединение, вернувшееся через листенер Citrus. Пользователь серверного входящего не может через него обратиться к частным адресам и loopback, как и через DIRECT.

Значения TTL вроде 4 — примеры, а не значения, подходящие любой сети: поддельный пакет должен истечь после фильтрующего оборудования и до сервера. Поможет ли способ, зависит от сети; локальная проверка показывает только, что байты отправлены так, как настроено.

GET /proxies показывает исходящий с "type": "Desync" и объектом desync: действующая стратегия strategy (static — заданные параметры) и параметры tcp с подставленными значениями по умолчанию (split-wait, split-wait-timeout, disorder, oob, random, fake). В fake поле last-ttl — число хопов, с которым ушла последняя подделка, и вывел ли его auto-ttl (null до первой подделки). С udp — его параметры и счётчики исходных и поддельных датаграмм, ошибок и адресатов. Счётчики показывают, что датаграммы отправлены, а не что они помогли.