62 lines
5.2 KiB
Markdown
62 lines
5.2 KiB
Markdown
# 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-протоколом не предусмотрена.
|