Preserve proxy TCP streams across connect, backpressure and FIN
This commit is contained in:
1 parent
09bc8c35c5
commit
e1946b208d
13 files changed
+831
-458
No files matched your search
@@ -0,0 +1,61 @@
|
||||
# Proxy: потоки TCP и датаграммы
|
||||
|
||||
Клиентские входы — TUN (lwIP), SOCKS5 CONNECT и HTTP proxy/CONNECT. Exit открывает
|
||||
обычный TCP-сокет к назначению. TCP-поток на exit определяется парой `(peer_node_id,
|
||||
stream_id)`. Клиент принимает ответы и уведомления restart только от настроенного
|
||||
exit в UTUN-группе. UDP/ICMP-контексты принадлежат конкретному `UTUN_INSTANCE`.
|
||||
|
||||
## TCP
|
||||
|
||||
Общие определения находятся в `src/proxy/proxy_protocol.h`. Передаваемый заголовок:
|
||||
`svc_id:1, command:1, stream_id:4`; поля маршрута добавляет ETCP-router.
|
||||
|
||||
- CONNECT (1): IPv4:4 и порт:2 в сетевом порядке.
|
||||
- CONNECTED (2): exit подтвердил успешный TCP connect. Только после этого клиент
|
||||
сообщает SOCKS success / HTTP 200 и начинает передавать накопленные данные.
|
||||
- DATA (3): от 1 до 4096 байт.
|
||||
- CLOSE (4), ERROR (5): прекращение потока.
|
||||
- FIN (6): конец одного направления; все предшествующие DATA должны быть переданы.
|
||||
- WINDOW (7): uint32_t, число дополнительно разрешённых байт.
|
||||
|
||||
У каждого направления начальное окно 65536 байт. DATA уменьшает окно отправителя
|
||||
и получателя. Получатель возвращает кредит после записи в локальный TCP-сокет
|
||||
либо принятия данных ограниченным send-buffer lwIP. Очередь ETCP сама по себе
|
||||
не является подтверждением потребления данных конечным TCP.
|
||||
|
||||
FIN ждёт освобождения исходящей очереди, включая данные, остановленные окном
|
||||
или backpressure роутера. Закрытие одного направления не прекращает другое.
|
||||
Окончательное освобождение происходит после обоих FIN и передачи оставшихся данных.
|
||||
Непереданные управляющие сообщения повторяются таймером. Ошибки и переходы
|
||||
состояния диагностируются категорией `proxy`; состояние сокетов — `socket`.
|
||||
|
||||
Парсеры сохраняют остаток после greeting/request/HTTP headers. HTTP CONNECT ждёт
|
||||
полного блока заголовков. Во время DNS/connect чтение ограничено очередью tcp_io;
|
||||
накопленные HTTP headers/body передаются частями размером DATA.
|
||||
|
||||
## UDP и ICMP
|
||||
|
||||
REQUEST и REPLY различаются явно. Ответ допускается только от настроенного exit.
|
||||
UDP-ответ восстанавливается с нулевой UDP checksum (допустимо для IPv4), IPv4 checksum
|
||||
пересчитывается. ICMP checksum учитывает нечётный последний байт без чтения за буфером.
|
||||
|
||||
Exit заменяет ICMP id/sequence уникальной среди ожидающих запросов парой и сопоставляет
|
||||
ответ также с IP назначения. Исходные id/sequence восстанавливаются для клиента.
|
||||
Это исключает смешивание ping-запросов разных клиентов с одинаковыми исходными ID.
|
||||
|
||||
## Проверки и ограничения
|
||||
|
||||
`test_proxy_packets` проверяет IPv4/UDP/ICMP и payload длиной 0..1501.
|
||||
`test_tcp_io_flush` проверяет уведомление после последнего синхронного send.
|
||||
`test_proxy_regressions` использует реальные локальные сокеты и управляемую доставку
|
||||
ETCP: совместные/раздельные handshake, ранние данные, отложенный CONNECTED, HTTP 502,
|
||||
большой POST, одинаковые stream ID разных пиров, FIN при закрытом окне, RST и IPv4 options.
|
||||
|
||||
На Linux полный `./check.sh`: 109 passed, 0 failed, 1 skipped; дополнительно прошли
|
||||
настоящий TUN, full-duplex burst и нагрузка 8 соединений / 128 МиБ.
|
||||
Windows/FreeBSD в этом прогоне не проверялись.
|
||||
|
||||
SOCKS IPv6 явно отклоняется кодом address type not supported. IPv4-фрагменты
|
||||
на входе proxy TUN отклоняются с диагностикой; сборка фрагментов не реализована.
|
||||
Формат TCP дополнен CONNECTED/WINDOW, UDP-команды разделены: клиент и exit необходимо
|
||||
обновлять вместе; совместимость со старым proxy-протоколом не предусмотрена.
|
||||
Reference in new issue
Block a user