# ICMP Proxy (icmp_proxy) ## 1. Назначение Проксирование ICMP Echo (ping) между клиентским и exit-узлом по протоколу ETCP. Клиент принимает ICMP Echo Request с TUN-интерфейса, упаковывает запрос и отправляет через `etcp_route_send` на exit. Exit-узел через нативный `SOCK_RAW`-сокет отправляет ICMP Echo во внешнюю сеть, сопоставляет ответы по `echo_id`/`echo_seq` и возвращает клиенту. Клиент восстанавливает IP/ICMP Echo Reply и доставляет в TUN. Один экземпляр контекста на процесс (глобальный `g_icmp_ctx`). Режим определяется флагом `inst->tcp_proxy_server.enabled`. Для тестов предусмотрен loopback-режим без raw-сокета. ## 2. Как пользоваться ### Инициализация ```c icmp_proxy_init(inst, ua); // exit создаёт SOCK_RAW, клиент — нет ``` При инициализации регистрируется коллбэк `icmp_proxy_recv_cb` в `etcp_router` для сервиса `ETCP_RT_ID_ICMP_PROXY`. На exit создаётся один `SOCK_RAW(IPPROTO_ICMP)` на весь модуль. ### Клиент: отправка ping-запроса ```c icmp_proxy_send_to_exit(inst, exit_node_id, dst_ip, orig_src_ip, echo_id, echo_seq, payload, len); ``` Вызывается из обработчика TUN-трафика. Запрос упаковывается и отправляется через `etcp_route_send`. Ответ приходит асинхронно в `icmp_proxy_recv_cb` (REPLY), где вызывается `icmp_proxy_deliver_reply` для сборки IP/ICMP Echo Reply и записи в TUN. ### Тестовый loopback ```c icmp_proxy_set_test_loopback(inst, 1); // exit отвечает эмуляцией без raw-сокета ``` В этом режиме exit не отправляет реальный ICMP Echo, а сразу возвращает REPLY клиенту — полезно для тестирования прохождения пакетов через ETCP без необходимости в SOCK_RAW и внешней сети. ### Очистка ```c icmp_proxy_destroy(inst); // закрывает raw-сокет, удаляет pending-запросы, unbind ``` ### Нюансы - Запросы истекают через 5 секунд (`ICMP_TIMEOUT_TB`). Таймер `expire_timer` запускается при добавлении первого запроса и перезапускается после каждой очистки. - Неопознанные echo-ответы (не найденные в pending) логируются как `DEBUG_WARN` и игнорируются. - Контрольная сумма ICMP пересчитывается на exit (при отправке) и на клиенте (при сборке ответа). - Поле `orig_src_ip` в протоколе нужно для восстановления исходного dst_ip на клиенте. ## 3. API ### Структуры | Структура | Назначение | |-----------|-----------| | `struct icmp_request` | Состояние активного echo-запроса на exit: client_node_id, dst_ip, orig_src_ip, echo_id, echo_seq, payload, время отправки. Связный список. | | `struct icmp_proxy_ctx` | Глобальный контекст: is_exit, inst, ua, raw_sock, raw_read_id, список pending, таймаут запросов, флаг test_loopback, таймер очистки. | ### Формат пакета | Смещение | Размер | Поле | |----------|--------|------| | 0 | 1 | `svc_id` = `ETCP_RT_ID_ICMP_PROXY` | | 1 | 1 | `subcmd` = REQUEST (0x01) / REPLY (0x02) | | 2 | 8 | `sender_node_id` | | 10 | 4 | `dst_ip` (IP цели для ping) | | 14 | 4 | `orig_src_ip` (IP исходного отправителя для обратной доставки) | | 18 | 2 | `echo_id` (icmp_id) | | 20 | 2 | `echo_seq` (icmp_seq) | | 22 | N | `payload` (данные ICMP echo) | ### Функции | Функция | Назначение | |---------|-----------| | `icmp_proxy_init(inst, ua)` | Выделяет контекст, определяет is_exit, на exit создаёт SOCK_RAW и регистрирует его в uasync. Регистрирует коллбэк в etcp_router. | | `icmp_proxy_destroy(inst)` | Закрывает raw-сокет, отменяет таймер, освобождает pending, отвязывает коллбэк, освобождает память. | | `icmp_proxy_recv_cb(conn, entry)` | Единый коллбэк etcp_router. По subcmd направляет REQUEST → `exit_handle_request`, REPLY → `client_handle_reply`. | | `icmp_proxy_send_to_exit(inst, ...)` | Клиент: упаковывает ICMP Echo Request и отправляет через etcp_route_send на exit. | | `icmp_proxy_deliver_reply(inst, ...)` | Клиент: собирает IP/ICMP Echo Reply-пакет и помещает в TUN input_queue. | | `icmp_proxy_set_test_loopback(inst, enabled)` | Включает/выключает тестовый loopback-режим на exit (эмуляция echo-ответа без raw-сокета). |