97 lines
10 KiB
Markdown
97 lines
10 KiB
Markdown
# Подписанная запись узла
|
||
|
||
`TOPO_NODE.timestamp` — версия всей подписанной записи, а не отдельного адреса.
|
||
Узел-владелец назначает Unix microseconds, строго больше предыдущей сохранённой
|
||
версии. Имя, тип, активность, адреса, метаданные сокетов, REALITY и подпись
|
||
заменяются вместе. Timestamp входит в подпись. Групповые пути и подсети
|
||
остаются в `TOPO_GROUP_NODE` и не являются частью общей записи узла.
|
||
|
||
Получатель проверяет подпись до изменения реестра или маршрутов. Более свежая
|
||
запись заменяет старую целиком, включая пустые списки адресов. Старые записи
|
||
игнорируются; разные подписанные записи с одинаковым timestamp — конфликт.
|
||
Повторное BGP-объявление может обновить путь, но не содержимое общей записи.
|
||
8-битный `ver` сохраняется как диагностический счётчик; свежесть определяется
|
||
только timestamp.
|
||
|
||
Живая телефонная занятость передаётся без изменения структуры NODEINFO: в существующем
|
||
`flags` бит `0x04` означает известное состояние, `0x08` — занятость звонком.
|
||
Это групповые флаги `TOPO_GROUP_NODE.phone_status`, как флаг рации `0x02`;
|
||
они не входят в подпись общей записи и используются только для цвета трубки в GUI.
|
||
Без разрешения Android, при выключенной публикации и после ухода узла статус неизвестен.
|
||
Решение о начале вызова принимает адресат по локальному состоянию ОС, а не по BGP-подсказке.
|
||
Изменения публикуются обычной новой версией NODEINFO во всех CHAT-группах; отдельного опроса и таймера нет.
|
||
|
||
Профиль endpoint в SOCKMETA содержит независимые `mapping` и `inbound`, источник `source`.
|
||
ID и время измерения не передаются: последний успешный профиль действует до
|
||
явного изменения endpoint или подтверждённого нового результата. Повторная
|
||
проверка с тем же результатом не меняет NODEINFO. Все поля SOCKMETA — отдельные байты;
|
||
границы списков metadata/адресов/REALITY также входят в каноническую подпись.
|
||
Алгоритм и условия неопределённости описаны в `doc/nat_detection.txt`.
|
||
`source=ETCP` обозначает результат детектора рабочего endpoint. Одно UDP-наблюдение может дать
|
||
адрес `TOPO_ADDR_NAT` при `mapping=UNKNOWN`, `inbound=UNKNOWN`: это NAT-кандидат
|
||
для пробного подключения, а не адрес интерфейса или подтверждённый открытый вход.
|
||
Общий внешний адрес подтверждает EIM; strict не публикует универсальный NAT-адрес.
|
||
Source входит в подпись; SOCKMETA занимает 5 байт. `source=STUN` означает предварительный
|
||
EIM? для того же локального IP/netif с неизвестным входом; измерение ETCP приоритетно.
|
||
Владелец снимает STUN-оценку после TTL. Внешний адрес тестового порта не публикуется:
|
||
NAT-кандидат по-прежнему требует наблюдения рабочего сокета.
|
||
Для TCP достаточно одного публичного пира: внешний IP с неизвестным входящим
|
||
портом публикуется как `TOPO_ADDR_NAT` с `port=0`, `mapping=UNKNOWN`, `inbound=UNKNOWN`.
|
||
NCD пропускает нулевые порты. Непубличный локальный TCP IP сразу означает NAT;
|
||
совпавший с наблюдением публичный IP даёт UNCHANGED без подтверждения открытого входа.
|
||
|
||
Таблица `node_snapshots` хранит полную сериализованную запись без группового
|
||
окружения. `node_addresses` остаётся проекцией для поиска и отображения, а не
|
||
источником для восстановления подписанной записи. При наличии сохранённого
|
||
snapshot загрузка использует его. Локальная публикация сохраняется до рассылки;
|
||
ошибка сохранения не разрешает публикацию новой версии.
|
||
|
||
В проекции адресов сохраняются `nat_mapping`, `nat_inbound`, `nat_source`, `address_kind`.
|
||
Уникальность определяется endpoint и видом адреса,
|
||
а не отображаемым классом NAT. Старый производный формат пересоздаётся;
|
||
bootstrap-загрузка без подписанного snapshot не подтверждает NAT-профиль.
|
||
При удалении старых `nat_evidence`/`nat_checked` адреса и REALITY сохраняются для bootstrap,
|
||
старые профили сбрасываются, сериализованные snapshots инвалидируются.
|
||
Максимальные timestamp snapshots сохраняются, чтобы новая локальная публикация
|
||
не откатывала версию даже при коррекции часов. Чат и ключи миграция не изменяет.
|
||
|
||
Timestamp 0 обозначает bootstrap-сведения без подписи (конфиг, приглашение,
|
||
начальные адреса). Они могут помочь установить первое соединение, но не
|
||
заменяют принятую подписанную запись. По BGP принимаются подписанные записи
|
||
с ненулевым timestamp. Формат NODEINFO изменён без обратной совместимости.
|
||
|
||
После принятия BGP-записи `node_conn_direct_update_node` применяет адреса к
|
||
существующему NCD-соединению. Отсутствующее соединение этот вызов не создаёт.
|
||
Линки дополняются как при UP, так и до установления соединения; повторная
|
||
доставка не создаёт дубликаты UDP/TCP. Работающие линки не закрываются только
|
||
из-за смены списка адресов. NCD удерживает ссылку на общую запись, пока
|
||
обслуживает соединение, и использует её при восстановлении.
|
||
|
||
`node_conn_direct_open_node` сверяет переданную запись с реестром/БД. Более
|
||
свежая подписанная запись принимается целиком, старая уступает уже известной.
|
||
Bootstrap-адреса не перекрывают подписанную запись даже при DOWN.
|
||
|
||
Конфигурационные подключения UTUN используют один адаптер
|
||
`init_client_connections` для старта и reload. Все адреса, TCP и REALITY
|
||
передаются NCD; адаптер не создаёт ETCP-линки. Новый набор handles открывается
|
||
до освобождения старого; при ошибке старые handles сохраняются. Конфигурация
|
||
удерживает один handle на клиента, независимо от количества его адресов.
|
||
|
||
Включение конфигурационного пира в UTUN-группу выполняет callback NCD UP.
|
||
Транспортный UP и наличие callback старого `etcp_connect` больше не включают
|
||
соединение в UTUN-группу автоматически. Входящий JOIN остаётся явным запросом
|
||
участия. При пересоздании UTUN-группы учитываются её конфигурационные handles.
|
||
Удаление клиента отправляет `LEAVE_GROUP` и освобождает удержание UTUN-группы
|
||
с обеих сторон. Другие владельцы NCD сохраняют транспорт. Поздние NODEINFO и
|
||
WITHDRAW от отсоединённого UTUN-пира игнорируются, чтобы не вернуть его маршруты.
|
||
LEAVE ждёт backpressure через queue waiter и временно удерживает собственный
|
||
NCD handle. Закрытие транспорта отменяет ожидание; новое участие в группе
|
||
делает ожидающий LEAVE устаревшим, и он не отправляется.
|
||
Причина удаления пира передаётся явно: только потеря транспорта запускает
|
||
recovery каскадных маршрутов. Локальный/удалённый LEAVE и удаление битой
|
||
member-записи не должны восстанавливать намеренно закрытое участие.
|
||
|
||
REALITY использует полное SNI до 255 символов; размер поля в записи узла
|
||
согласован с транспортом. Если локального TCP listen-сокета нет, NCD может
|
||
создать исходящий TCP-линк с выбором локального адреса операционной системой.
|