Инкапсуляция одного надежного транспортного протокола внутрь другого на первый взгляд кажется логичным решением. Сетевые инженеры и пользователи нередко направляют трафик VPN через порт TCP 443, чтобы преодолеть строгие корпоративные межсетевые экраны, отбрасывающие сырые дейтаграммы UDP. Однако запуск протокола TCP поверх другого TCP порождает в распределенных системах критический режим сбоя, известный как TCP-over-TCP Meltdown (коллапс вложенного TCP).
В реальных сетях с естественными колебаниями задержки (джиттером) и потерями пакетов два независимых контура управления TCP начинают взаимно разрушать связь. Вместо стабилизации соединения некоординированные таймеры повторной передачи вызывают лавинообразное раздувание очередей, экспоненциальное замедление и катастрофическое падение пропускной способности практически до нуля. Понимание этого явления объясняет, почему современные архитектуры VPN — включая WireGuard и протокол RiceGuard от VPNRice — работают исключительно поверх дейтаграмм UDP на третьем сетевом уровне (Layer 3).
Проблема двух контуров: конфликт вложенных протоколов
Протокол TCP создавался на основе принципа сквозного взаимодействия (end-to-end principle). Транспортный уровень исходит из того, что физическая сеть под ним ненадежна (IP-пакеты могут теряться или менять порядок), и гарантирует доставку с помощью порядковых номеров (sequence numbers), подтверждений (ACK), скользящих окон и алгоритмов контроля перегрузки (CUBIC или BBR).
Когда VPN-туннель упаковывает данные в TCP, на одном физическом маршруте возникают два независимых и нескоординированных контура управления:
+-------------------------------------------------------------------------+
| Конфликт двух контуров вложенного TCP |
+-------------------------------------------------------------------------+
| Прикладной уровень: HTTPS, SSH, вызовы API |
| | |
| v |
| [ Внутренний контур TCP (Inner Loop) ] |
| - Номера последовательностей, оценка RTT приложения, таймер RTO |
| - Окно перегрузки (cwnd) масштабируется по прикладной доставке |
| | |
| v (Упаковывается как полезная нагрузка в интерфейс туннеля) |
| [ Внешний контур TCP (Outer Loop) ] |
| - Работает на физическом канале (Wi-Fi, 4G/5G, оптоволокно) |
| - Свои номера последовательностей, внешний RTT и таймер RTO |
| - Автономно буферизует, переупорядочивает и повторно отправляет пакеты|
+-------------------------------------------------------------------------+
При потере даже одного физического пакета на линии эти два контура реагируют противоположным образом:
- Внешний TCP начинает восстановление: Обнаружив пропажу пакета (через повторные ACK или тайм-аут внешнего RTO), туннель задерживает передачу последующих байт прикладному интерфейсу и запрашивает повторную отправку на физическом уровне.
- Искусственный всплеск задержки: Пока внешний TCP ждет повторный пакет, виртуальный интерфейс не может передать данные приложению из-за строгой упорядоченности байтового потока. Значение RTT, наблюдаемое внутренним стеком TCP, моментально взлетает с десятков миллисекунд до сотен и тысяч.
- Срабатывание внутреннего таймера: Таймер ожидания повторной передачи (RTO) внутреннего TCP, рассчитанный в условиях стабильной связи, истекает раньше, чем внешний туннель успевает устранить физическую потерю.
- Вброс дубликатов: Решив, что пакет утрачен в сети, приложение формирует повторный дубликат тех же данных.
- Лавинообразное переполнение буфера: Внешний TCP принимает этот повторный пакет как новую полезную нагрузку и помещает его в очередь позади уже задержанных данных.
Анатомия коллапса: лавина повторных передач
Коллапс развивается от единичной потери пакета до полной остановки обмена данными по предсказуемой математической цепочке.
+-------------------------------------------------------------------------+
| Последовательность развития коллапса |
+-------------------------------------------------------------------------+
| Физический канал: потерян пакет #10 |
| |
| Внешний TCP: |
| - Фиксирует потерю -> Приостанавливает поток -> Режим Fast Retransmit |
| - Удерживает пакеты #11, #12, #13 в ожидании пакета #10 |
| |
| Внутренний TCP (сессия приложения): |
| - Ожидает подтверждения (ACK) на внутренний пакет #4 |
| - Таймер внутреннего RTO истекает (например, прошло 200 мс) |
| - Окно cwnd падает до минимума: cwnd = 1 MSS |
| - Повторно отправляет пакет #4 -> попадает в очередь внешнего TCP |
| |
| Внешний TCP восстанавливает пакет #10: |
| - Передает исходный пакет #4 приложению |
| - Вынужден дополнительно отправлять дубликат #4 через радиоканал |
| |
| Результат: Bufferbloat, рост RTO, скорость падает к нулю |
+-------------------------------------------------------------------------+
Математика прогрессирующего таймера RTO
В соответствии с RFC 6298 вычисление RTO базируется на сглаженном значении задержки (SRTT) и дисперсии (RTTVAR):
$$\text{RTO} \leftarrow \text{SRTT} + \max(G, 4 \cdot \text{RTTVAR})$$
Когда внешний уровень сталкивается с потерями, задержка для внутреннего стека возрастает:
$$\text{RTT}{\text{внутр., факт}} = \text{RTT}{\text{внешн.}} + \text{Задержка повторной передачи}$$
Поскольку задержка внешней повторной отправки почти всегда превышает сглаженный $\text{SRTT}$ приложения, внутренний RTO неизбежно срабатывает преждевременно. При каждом срабатывании без ответа протокол удваивает интервал ожидания (Exponential Backoff):
$$\text{RTO}{\text{след.}} = 2 \cdot \text{RTO}{\text{тек.}}$$
Оба уровня одновременно переходят в режим экспоненциального отката. Окно перегрузки прикладного соединения сжимается до 1 MSS, а буфер внешнего канала переполняется устаревшими пакетами, блокируя передачу полезной информации.
Блокировка начала очереди (Head-of-Line Blocking)
В стандартном сценарии пользовательский туннель одновременно обслуживает множество потоков:
- Системные запросы DNS
- Голосовые и видеовызовы WebRTC
- Сессии SSH и активные вкладки браузера
Когда туннель построен на базе TCP, потеря одного сегмента при фоновой загрузке файла замораживает абсолютно все параллельные соединения. Из-за строгой очередности байтов ядро не может отдать приложению поступившие пакеты, пока не будет получен утраченный сегмент туннеля. В результате звук в звонках прерывается, ввод в терминале зависает, а веб-страницы выдают ошибку тайм-аута.
Сравнение: туннелирование TCP против дейтаграммного UDP
Современные сетевые протоколы используют исключительно дейтаграммы UDP на сетевом уровне, отделяя доставку пакетов от логики надежности.
+-------------------------------------------------------------------------+
| Сравнение туннелей TCP и дейтаграммных UDP |
+-------------------------------------------------------------------------+
| Параметр | Туннель TCP | Туннель UDP (WireGuard)|
|------------------------|-----------------------|------------------------|
| Модель передачи | Надежный байтовый поток| Автономные дейтаграммы |
| Контроль перегрузки | Два конфликтующих ряда| Единственный сквозной |
| Реакция на потери | Повтор на внешнем слое| Отбрасывание и передача|
| Блокировка очереди | Затрагивает весь канал| Изолирована в сессии |
| Чувствительность к RTO | Критическая (коллапс) | Полный иммунитет |
| Мобильный роуминг | Перезапуск сокета | Без состояния (0 мс) |
| Трафик реального времени| Деградация звука/видео| Сохранение низкой задержки|
+-------------------------------------------------------------------------+
Преимущество UDP: автономность пакетов
При использовании инкапсуляции в дейтаграммы UDP (как в WireGuard, IPsec ESP и RiceGuard):
- Отсутствие повторных передач в туннеле: Сетевой интерфейс не следит за последовательностью и никогда повторно не пересылает потерянные дейтаграммы.
- Сквозная ответственность приложений: Если приложению требуется надежность (HTTPS через TCP), его собственный стек TCP отслеживает потери и запрашивает повтор. В системе действует ровно один контур управления.
- Защита критичного к задержкам трафика: Запросы DNS, голосовые звонки и трафик протокола QUIC не зависят от потерь данных в соседних потоках и передаются мгновенно.
Диагностика коллапса с помощью дампа трафика
Анализ TCP-в-TCP соединения при искусственной потере 2% пакетов в утилите tcpdump наглядно демонстрирует симптомы коллапса:
# Трассировка пакетов: каскадный конфликт повторной отправки
14:10:01.102341 IP client.45210 > vpn.443: Flags [P.], seq 1024:2472, ack 1
14:10:01.102410 IP client.45210 > vpn.443: Flags [P.], seq 2472:3920, ack 1
14:10:01.182105 IP vpn.443 > client.45210: Flags [.], ack 1024, win 65535, options [sack 1 {2472:3920}]
14:10:01.182190 IP client.45210 > vpn.443: Flags [P.], seq 1024:2472, ack 1 <-- Внешний повтор
14:10:01.382410 IP client.45210 > vpn.443: Flags [P.], seq 3920:5368, ack 1 <-- Сработал внутренний RTO
14:10:01.782890 IP client.45210 > vpn.443: Flags [P.], seq 5368:6816, ack 1 <-- Рост таймера до 400 мс
Трассировка четко показывает:
- Сигнал SACK указывает на потерю сегмента
1024:2472в физическом канале. - Внешнее соединение повторно отправляет недостающие данные в
14:10:01.182. - Однако таймер внутреннего приложения (200 мс) срабатывает в
14:10:01.382, вбрасывая в канал лишнюю копию. - Последующее удвоение таймеров до 400 мс и 800 мс приводит к полному простою канала связи.
Работа в сетях с фильтрацией UDP без риска коллапса
Если локальная сеть полностью блокирует исходящие дейтаграммы UDP, туннель вынужден использовать резервный протокол TCP. Чтобы минимизировать риск коллапса в такой ситуации, архитектура туннеля должна соблюдать строгие правила:
- Отключение алгоритма Нейгла (
TCP_NODELAY): Запрещает сокету накапливать мелкие пакеты, предотвращая искусственные скачки задержки. - Ограничение буферов сокета: Уменьшение размера буфера записи не позволяет туннелю накапливать избыточные дубликаты, передавая сигнал обратного давления приложению вовремя.
- Приоритет возврата на UDP: Клиентское приложение непрерывно проверяет доступность прямого канала UDP в фоновом режиме, возвращая соединение на дейтаграммную основу при первой возможности.
Архитектура сетевого ядра VPNRice
Сетевое ядро RiceGuard от VPNRice построено на строгом разделении потоков данных на третьем сетевом уровне (Layer 3), полностью устраняя риск вложенного коллапса:
- Трансляция дейтаграмм по умолчанию: Весь пользовательский трафик инкапсулируется в независимые пакеты UDP, оставляя прикладным сессиям полный контроль над окнами перегрузки.
- Исключение блокировок очереди: Запросы DNS, видеоконференции и просмотр страниц изолированы друг от друга и не испытывают задержек при сбоях в фоновых загрузках.
- Бесшовный мобильный роуминг: Бесклассовая криптографическая маршрутизация позволяет устройству переключаться между Wi-Fi и сотовой сетью без сброса сокетов и длительного повторного согласования.



