diff --git a/doc/nat_detection.txt b/doc/nat_detection.txt index a7190846..0d0237af 100644 --- a/doc/nat_detection.txt +++ b/doc/nat_detection.txt @@ -6,15 +6,13 @@ к протоколу, семейству, фактическому локальному IP:port и поколению сокета. PUBLIC/NAT/PRIVATE/LOCAL — политика конфигурации, а не результат измерения. source=ETCP означает измерение рабочего endpoint; source=STUN — резервную оценку -по его IP/netif через другой порт. Измеренный ETCP имеет приоритет до истечения TTL. +по его IP/netif через другой порт. Успешный ETCP имеет приоритет до явного сброса endpoint. Модель: src/routing_layer/address_profile.h. mapping: UNKNOWN, UNCHANGED, EIM, DEPENDENT. inbound: UNKNOWN, OPEN, CONTACT_REQUIRED. source: NONE, ETCP, STUN. - evidence_id: случайный 64-битный ID завершённого раунда владельца. - checked_at: время измерения владельца, Unix microseconds. - generation: случайный 64-битный ID жизненного цикла локального endpoint. + round/generation: локальные ID раунда и жизненного цикла endpoint; в NODEINFO не входят. UNCHANGED означает совпадение наблюдаемых и локального адресов на испытанных направлениях. Оно не доказывает свободный вход. EIM означает одинаковый внешний @@ -75,11 +73,12 @@ facet не превращается в ложный STRICT. Потери, оши остаются подсказками для попыток, подтверждение связи даёт handshake с нужным ключом. Один активный раунд на S. Таймаут пробы — max(1 секунда, 4*RTT), не более 3 секунд; -три попытки, бюджет раунда 30 секунд. Повтор после ошибки через 30 секунд или -после появления подходящего транспорта; штатный refresh через 180 секунд. -Срок фактов — 300 секунд. Таймеры владельца используют monotonic timebase; -checked_at не обновляется повторным NODEINFO и не зависит от ответа сервера NTP. -При несогласованных часах получатель использует осторожные попытки, не отказ. +три попытки, бюджет раунда 30 секунд. До первого результата повтор после ошибки +через 30 секунд или после появления подходящего транспорта; штатный refresh через 30 минут. +Успешный профиль не протухает по таймеру. Ошибка перепроверки сохраняет прежний результат +и редкий период; неизвестный inbound при том же mapping/endpoint сохраняет прежний ETCP inbound. +Свойства разных источников не объединяются в один ETCP-профиль. Смена адреса отменяет +старый раунд, сбрасывает профиль и назначает скорую проверку. Таймеры используют monotonic timebase. TCP и прокси ------------- @@ -114,11 +113,12 @@ owner_key и helper_key имеют разные поля и никогда не --------------- Профиль публикуется только владельцем в общей подписанной записи NODEINFO. -Списки и их границы входят в подпись; mapping/inbound/evidence/checked_at +Списки и их границы входят в подпись; mapping/inbound/source сохраняются и загружаются вместе. node_addresses — производная проекция: -nat_mapping, nat_inbound, nat_evidence, nat_checked, address_kind. +nat_mapping, nat_inbound, nat_source, address_kind. При изменении формата старый кэш адресов пересоздаётся; старый NAT_TYPE не -интерпретируется как новая модель. Подписанные snapshots и записи чата не удаляются. +интерпретируется как новая модель. При сокращении SOCKMETA старые snapshots инвалидируются +с сохранением timestamp; адреса и REALITY остаются bootstrap-сведениями. Записи чата не изменяются. Общий NAT-адрес рекламируется только после EIM. DEPENDENT не рекламирует универсальный внешний endpoint. NTP.reachable не управляет рекламой адресов. diff --git a/doc/node_snapshot.md b/doc/node_snapshot.md index 91564b9f..57c39b29 100644 --- a/doc/node_snapshot.md +++ b/doc/node_snapshot.md @@ -13,14 +13,14 @@ 8-битный `ver` сохраняется как диагностический счётчик; свежесть определяется только timestamp. -Профиль endpoint в SOCKMETA содержит независимые `mapping` и `inbound`, источник `source`, -`evidence_id` и `checked_at`. Последние относятся к измерению владельца, -а не к версии всего NODEINFO: повтор записи или изменение имени не продлевает -измерение. Новые поля профиля на проводе кодируются явными BE-байтами; +Профиль endpoint в SOCKMETA содержит независимые `mapping` и `inbound`, источник `source`. +ID и время измерения не передаются: последний успешный профиль действует до +явного изменения endpoint или подтверждённого нового результата. Повторная +проверка с тем же результатом не меняет NODEINFO. Все поля SOCKMETA — отдельные байты; границы списков metadata/адресов/REALITY также входят в каноническую подпись. Алгоритм и условия неопределённости описаны в `doc/nat_detection.txt`. `source=ETCP` обозначает измерение рабочего endpoint, `source=STUN` — резервную оценку -по IP/netif с другого порта. Source входит в подпись; SOCKMETA занимает 21 байт. +по IP/netif с другого порта. Source входит в подпись; SOCKMETA занимает 5 байт. STUN mapped endpoint не публикуется как внешний адрес рабочего сокета. Таблица `node_snapshots` хранит полную сериализованную запись без группового @@ -29,10 +29,14 @@ STUN mapped endpoint не публикуется как внешний адре snapshot загрузка использует его. Локальная публикация сохраняется до рассылки; ошибка сохранения не разрешает публикацию новой версии. -В проекции адресов сохраняются `nat_mapping`, `nat_inbound`, `nat_evidence`, -`nat_checked`, `nat_source`, `address_kind`. Уникальность определяется endpoint и видом адреса, +В проекции адресов сохраняются `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-сведения без подписи (конфиг, приглашение, начальные адреса). Они могут помочь установить первое соединение, но не diff --git a/src/routing_layer/topo_node_sqlite.h b/src/routing_layer/topo_node_sqlite.h index db6a8f5b..dbe1e6eb 100644 --- a/src/routing_layer/topo_node_sqlite.h +++ b/src/routing_layer/topo_node_sqlite.h @@ -25,7 +25,7 @@ uint64_t topo_node_sqlite_snapshot_timestamp(sqlite3* db, uint64_t node_id); struct TOPO_NODE* topo_node_sqlite_snapshot_load(sqlite3* db, struct TOPO_GROUPS* groups, uint64_t node_id); /* Персистентная запись адресов узла в node_addresses (источник истины — BGP/topo_group). - * DELETE + INSERT из ni->v4_addrs/v6_addrs; mapping/inbound/evidence из подписанного SOCKMETA. */ + * DELETE + INSERT из ni->v4_addrs/v6_addrs; mapping/inbound/source из подписанного SOCKMETA. */ int topo_node_sqlite_addrs_put(sqlite3* db, uint64_t node_id, struct TOPO_NODE* ni); /* Есть ли у узла запись мембера хотя бы в одной peers_ (реальный мембер с ключами). */