diff --git a/src/routing_layer/route_lib.txt b/src/routing_layer/route_lib.txt index a1c0dd76..88fff76f 100644 --- a/src/routing_layer/route_lib.txt +++ b/src/routing_layer/route_lib.txt @@ -1,31 +1,34 @@ -В таблице роутинга маршруты не пересекаются. Т.е. не может быть одновременно 192.168.1.1/24 и 192.168.1.100/30 - -Как работает роутинг: -1. типов маршрута бывает два: learned (роутятся в ETCP instance) и local (роутятся в TUN). - local - локальные маршруты из конфига (опция конфига my_subnet=IP/Mask) - при инициализации local сразу добавляются в роутинг таблицу (ипользуя запись BGP_NODEINFO_PACKET* my_nodeinfo). - -BGP_NODEINFO собирается на узле владельце node, далее распространяется по остальным узлам. - -2. При установке подключения к новому узлу мы отправляем этому узлу все nodeinfo. Если несколько доступных линков - отправляем только один - preferred_conn -3. При изменении preferred_conn рассылаем reroute (например старый preferred_conn удален) -3. При удалении всех подключений рассылаем withdraw. - -3. При получении BGP_NODEINFO_PACKET мы смотрим есть ли такой узел уже в таблице. Если узла нет - добавляем, если есть - обновляем информацию о узле включая его маршруты и список next_hop через которые доступен узел (nb_routes). - Добавляем так: - инкрементируем hop_count - устанавливая etcp линк с которого приняли как next_hop, добавляем его в hop_list. - рассылаем по всем активным линкам кроме линка с которого получили (обязательно) - Обновление: обновляем hop_list если поменялся - -4. При отключении от узла (если у node не осталось nb_routes) мы: - Удаляем node и вложенные структуры: все маршруты узла - Рассылаем withdraw для узла hop_id. - -Логика рассылки withdraw: - Если получен withdraw - удаляем этот маршрут и распространяем withdraw или reroute по всем линкам кроме того с которого получили. В зависимости от изменений (остались ли резервные линки или изменился preferred_conn). - -Метрик маршрута пока нет. используется первый доступный. - -Как работаеут маршрутизация: - destination IP -> route table lookup -> route entry (ip/mask, node_info*) -> выбор лучшего next_hop -> отправка в next_hop +route_lib — локальная таблица IPv4-подсетей UTUN +================================================ + +Подсети в таблице не пересекаются. Запрещены одинаковые и вложенные диапазоны, +как между узлами, так и внутри одного переданного набора. Например, +10.0.0.0/8 исключает 10.1.0.0/24; соседние 10.1.0.0/24 и 10.1.1.0/24 допустимы. +Маршрут /0 занимает всё адресное пространство и может быть только единственным. + +route_insert(table, node) добавляет все node->subnets->v4_subnets атомарно. +Префиксы должны быть в диапазоне 0..32; адреса нормализуются маской перед хранением. +При неверных аргументах, отсутствии подсетей, пересечении или OOM возвращает false, +не меняя таблицу и её статистику. Перед заменой маршрутов узла вызывают route_delete. + +Таблица — отсортированный массив. route_lookup получает IPv4 в host byte order +и бинарным поиском возвращает единственный подходящий диапазон либо NULL. +Это не LPM-таблица: вложенные префиксы исключены при вставке. +Указатель на ROUTE_ENTRY действителен только до следующего изменения таблицы. +Адреса TOPO_SUBNET4 хранятся в сетевых байтах, parse_subnet возвращает host order, +is_local_subnet принимает network order. parse_subnet сохраняет host-биты и читает +префикс через atoi; это не строгий валидатор всей строки CIDR. + +TOPO_GROUP_NODE заимствован, в том числе для локальных маршрутов. +Маршруты удаляют до освобождения узла. destroy освобождает массив, но не узлы. +Все вызовы выполняются в одном потоке ядра. + +Наполнение таблицы и поиск следующего узла — разные задачи: + IPv4 destination -> route_lookup -> TOPO_GROUP_NODE -> etcp_route_send + -> выбор живого next hop через CM/BGP -> ETCP. +Для локального владельца routing доставляет пакет в TUN после firewall. +Групповые пути, WITHDRAW, выбор по числу переходов и READY описаны в topo_group.h; +общая подписанная запись узла — в topo_node.h и doc/node_snapshot.md. + +IPv6-таблица route6_lib использует radix и разрешает вложенные префиксы. +Основной routing.c пока доставляет только IPv4. diff --git a/src/routing_layer/route_ping.h b/src/routing_layer/route_ping.h index 323567c7..45b0d2ad 100644 --- a/src/routing_layer/route_ping.h +++ b/src/routing_layer/route_ping.h @@ -25,7 +25,7 @@ int route_ping_addr_equal(const struct sockaddr_storage *a, const struct sockadd /* Отправить OBSERVE PING: group/round и generation сокета ненулевые, timeout_ms — мс. * peer_key — 32 байта ключа наблюдателя, peer_address — его UDP endpoint. - * Возвращает результат etcp_send_ping_to_socket (0/-1), callback/arg — его контракт. + * Возвращает 0 при запуске, отрицательный код ошибки ETCP при отказе; callback/arg — контракт ETCP. * Ответ: address(19) || tag(33); профиль сокета здесь не изменяется. */ int route_ping_observe(struct ETCP_SOCKET *socket, const uint8_t peer_key[SC_PUBKEY_SIZE], const struct sockaddr_storage *peer_address, uint64_t group, uint64_t round, int timeout_ms, diff --git a/src/routing_layer/route_ping_doc.md b/src/routing_layer/route_ping_doc.md index 9729b733..97c4a663 100644 --- a/src/routing_layer/route_ping_doc.md +++ b/src/routing_layer/route_ping_doc.md @@ -4,15 +4,16 @@ `ETCP_SOCKET`. Выбор B/C, пересылка управляющих сообщений и классификация профиля принадлежат `nat_detection`; алгоритм — в `doc/nat_detection.txt`. -`route_ping_observe(socket, peer_key, peer_address, round, timeout_ms, callback, arg)` +`route_ping_observe(socket, peer_key, peer_address, group, round, timeout_ms, callback, arg)` передаёт PING с `ETCP_PING_FLAG_OBSERVE`. PONG содержит фактически наблюдаемый source IP:port и исходный тег. Профиль не меняется от единственного ответа. -`route_ping_observation` проверяет размер, ID/поколение сокета и round. +`route_ping_observation` проверяет размер, ID/поколение сокета, round и group. Адрес занимает 19 байт: family(1: 4/6), IP(16: IPv4 + 12 нулей либо IPv6), -port(2, BE). Тег занимает 25 байт: `NAT2UDP!`(8), socket_id(1), -generation(8, BE), round(8, BE). Неправильные family, скрытые IPv4-байты -и нулевой порт отвергаются. Новый wire не использует native packed integers. +port(2, BE). Тег занимает 33 байта: `NAT4UDP!`(8), socket_id(1), +generation(8, BE), round(8, BE), group(8, BE). Декодирование отвергает неправильные +family, скрытые IPv4-байты и нулевой порт. IPv6 scope_id в wire не передаётся. +Кодирование нулевой порт не запрещает. Числа тега передаются в BE. В транспорте nonce генерируется CSPRNG; PONG должен соответствовать ожидаемому ключу, source IP:port и принимающему socket generation. Pending снимается @@ -20,8 +21,8 @@ generation(8, BE), round(8, BE). Неправильные family, скрытые совпадающие запросы без callback; arg остаётся собственностью вызывающего. `ETCP_PING_FLAG_ADDRESS_CHECK` обозначает прямое входящее испытание. Его -receipt фиксируется на рабочем сокете владельца до отправки PONG. Потеря -обратного PONG поэтому не превращает полученный ingress в отрицательный результат. +приём передаётся `nat_detection_receive_ingress` без UDP-ответа: ответ мог бы +испортить историю контактов. Результат передаётся по защищённому управляющему каналу. UDP-результаты не используются для TCP listener и SOCKS5 endpoint. Проверки: `tests/test_route_ping.c`, `tests/test_nat_detection.c`,