Browse Source

docs: describe NAT detector state and public API arguments

stream-multiview
evgeny 1 week ago
parent
commit
6a2164717e
  1. 113
      src/routing_layer/nat_detection.h

113
src/routing_layer/nat_detection.h

@ -1,8 +1,14 @@
/* Владелец измеряет рабочий UDP endpoint по разным IP, без сравнения портов одного IP.
* Наблюдения возвращаются через router. Прямые входящие пробы не получают UDP-ответа;
* незнакомость фактического source IP проверяет получатель до исходящего контакта.
* Mapping и inbound завершаются независимо; CONTACT — оценка по сериям до/после контакта.
* Все операции и callbacks выполняются в uasync-потоке ядра. */
/* Определяет NAT и доступность незнакомых входящих для рабочего UDP-сокета.
* Два узла сообщают, какой внешний IP:порт видят: стабильное равенство означает EIM
* (совпадение с локальным — отсутствие трансляции), различие — strict.
* Помощник отправляет пакеты до и после исходящего контакта:
* вход до контакта означает open, только после — оценку filtered.
* Получатель проверяет настоящий IP отправителя; непубличный адрес не подходит.
* Команды и результаты идут по работающей сети uTun, тестовые пакеты — напрямую.
* Недостаток данных оставляет соответствующую часть результата UNKNOWN.
* TCP-вход проверяется отдельно подключением к listener, без переноса UDP-профиля.
* Все функции вызываются в uasync-потоке ядра; detector ниже — контекст этого ядра.
* Общее описание алгоритма: doc/nat_detection.txt. */
#ifndef NAT_DETECTION_H
#define NAT_DETECTION_H
@ -19,55 +25,124 @@ struct UTUN_INSTANCE;
struct ETCP_CONN;
struct ETCP_LINK;
struct ETCP_SOCKET;
/* Закрытый контекст: проверки сокетов, история исходящих IP, задачи помощника и таймеры. */
struct NAT_DETECTION;
/* Почему проверка не завершилась полностью; отсутствие ответа само по себе не определяет NAT-тип. */
enum nat_check_reason {
NAT_REASON_NONE, NAT_REASON_NO_OBSERVER, NAT_REASON_NO_HELPER, NAT_REASON_CONTROL_LOST,
NAT_REASON_SEND_ERROR, NAT_REASON_TIMEOUT, NAT_REASON_ADDRESS_CHANGED, NAT_REASON_CONTACT_HISTORY,
NAT_REASON_PROXY, NAT_REASON_NO_LISTENER, NAT_REASON_CANCELLED, NAT_REASON_INVALID_OBSERVATION, NAT_REASON_DEPENDENT_MAPPING
NAT_REASON_NONE, /* Нет причины ошибки. */
NAT_REASON_NO_OBSERVER, /* Нет подходящего узла для наблюдения внешнего адреса. */
NAT_REASON_NO_HELPER, /* Нет подходящего помощника для проверки входящих. */
NAT_REASON_CONTROL_LOST, /* Потерян маршрут для команд и результатов. */
NAT_REASON_SEND_ERROR, /* Не удалось отправить тестовый пакет. */
NAT_REASON_TIMEOUT, /* Проверка не завершилась за отведённое время. */
NAT_REASON_ADDRESS_CHANGED, /* Наблюдаемый адрес изменился; прежний профиль сброшен. */
NAT_REASON_CONTACT_HISTORY, /* IP уже был знаком или история неполна: вход не подтверждён как незнакомый. */
NAT_REASON_PROXY, /* Сокет работает через SOCKS: его собственный NAT не измеряется. */
NAT_REASON_NO_LISTENER, /* Нет публичного TCP-listener для проверки входящих. */
NAT_REASON_CANCELLED, /* Проверка отменена. */
NAT_REASON_INVALID_OBSERVATION, /* Наблюдение непригодно, в том числе из-за непубличного source IP. */
NAT_REASON_DEPENDENT_MAPPING /* Определён strict, входящая доступность осталась неизвестной. */
};
/* Снимок состояния одного сокета для диагностики; получение снимка не запускает проверку. */
struct nat_check_status {
struct address_profile measured_profile, effective_profile;
uint64_t generation, round;
uint64_t group_id, observer, helper;
uint32_t rounds, helper_reselections;
uint8_t phase, reason, history_complete, cycling;
struct address_profile measured_profile; /* Сохранённый результат измерения NAT и входящих этого сокета. */
struct address_profile effective_profile; /* Профиль, выбранный для использования и публикации узлом. */
uint64_t generation; /* Поколение сокета: отличает переоткрытие с тем же socket ID. */
uint64_t round; /* Уникальный ID текущей или последней попытки. */
uint64_t group_id; /* ID группы, через которую передаются команды и результаты. */
uint64_t observer; /* ID узла, наблюдающего внешний адрес (B в описании алгоритма). */
uint64_t helper; /* ID помощника, проверяющего входящие (C). */
uint32_t rounds; /* Сколько попыток начато за время жизни состояния этого сокета. */
uint32_t helper_reselections; /* Сколько раз назначен переход к следующей паре кандидатов. */
uint8_t phase; /* 0 — ожидание; иначе внутренний номер текущего этапа. */
uint8_t reason; /* Причина завершения или неполного результата: enum nat_check_reason. */
uint8_t history_complete; /* 1 — история исходящих IP загружена без известных потерь. */
uint8_t cycling; /* 1 — идёт цикл проверки с перебором кандидатов. */
};
/* Создать детектор для instance с готовым маршрутизатором и группами; автоматические проверки включены.
* Возвращает контекст или NULL при ошибке; instance должен существовать до destroy(). */
struct NAT_DETECTION *nat_detection_create(struct UTUN_INSTANCE *instance);
/* Остановить проверки, снять обработчики и освободить detector; NULL допустим. Ядро и его рабочие сокеты не освобождаются. */
void nat_detection_destroy(struct NAT_DETECTION *detector);
/* Объединить изменения NODEINFO/READY и пересмотреть доступные группы в следующем uasync-вызове. */
/* Сообщить detector об изменении адресов/готовности групп; пересмотр кандидатов отложен и объединяет повторные вызовы. */
void nat_detection_topology_changed(struct NAT_DETECTION *detector);
/* Отменить раунды, задачи помощников и наблюдения до закрытия router-каналов группы. */
/* Отменить проверки, помощь другим узлам и наблюдения в группе group_id до закрытия её управляющих каналов. */
void nat_detection_cancel_group(struct NAT_DETECTION *detector, uint64_t group_id);
/* Короткий приоритет начального измерения перед фоновыми UDP-пробами достижимости; задержка в timebase. */
/* На сколько отложить фоновые UDP-пробы, чтобы сохранить незнакомые IP для измерения detector.
* Возвращает задержку в timebase (1 единица = 100 мкс), 0 — откладывать не нужно. */
uint64_t nat_detection_probe_delay(struct NAT_DETECTION *detector);
/* Фоновый UDP-ответ к незнакомому IP может откладываться; односторонние NAT-пробы принимаются независимо. */
/* Можно ли сейчас обрабатывать PING на socket с ответом, не испортив проверку незнакомого входа.
* peer_key — проверенный ключ отправителя (32 байта), source — фактический IP:порт, flags — флаги PING,
* tag/length — его пользовательские данные/размер. Возвращает 1 — разрешено, 0 — пропустить без ответа. */
int nat_detection_ping_allowed(struct NAT_DETECTION *detector, struct ETCP_SOCKET *socket,
const uint8_t peer_key[32], const struct sockaddr_storage *source,
uint8_t flags, const uint8_t *tag, size_t length);
/* Сообщить о готовности link; при отсутствии результата запланировать измерение его локального сокета. */
void nat_detection_link_ready(struct NAT_DETECTION *detector, struct ETCP_LINK *link);
/* Сообщить об утрате/перезапуске connection; запланировать пересмотр маршрутов и отмену зависимых проверок при их потере. */
void nat_detection_cancel_for_conn(struct NAT_DETECTION *detector, struct ETCP_CONN *connection);
/* Перепроверить после реально отправленных INIT к OPEN; CONTACT — только после исчерпания reverse. */
/* Сообщить о неудаче прямого подключения connection к узлу с известной входящей доступностью.
* reverse_done != 0 — обратное подключение тоже исчерпано; только тогда перепроверяется filtered (CONTACT). */
void nat_detection_connection_failed(struct NAT_DETECTION *detector, struct ETCP_CONN *connection, int reverse_done);
/* Удалить состояние socket и отменить связанные задачи; вызвать до освобождения самого сокета. */
void nat_detection_socket_removed(struct NAT_DETECTION *detector, struct ETCP_SOCKET *socket);
/* Учесть исходящую отправку с socket на destination (IP:порт) до передачи пакета транспорту.
* История хранится по IP; контакт с помощником во время проверки лишает вход статуса незнакомого. */
void nat_detection_note_send(struct NAT_DETECTION *detector, struct ETCP_SOCKET *socket,
const struct sockaddr_storage *destination);
/* Учесть observed — наш IP:порт, сообщённый пиром при установлении link.
* Непубличное наблюдение не меняет интернет-профиль; изменение внешнего адреса сбрасывает прежнее измерение. */
void nat_detection_observed_by_peer(struct NAT_DETECTION *detector, struct ETCP_LINK *link,
const struct sockaddr_storage *observed);
/* Обработать запрос наблюдения, полученный на socket: source — реальный IP:порт отправителя,
* peer_key — его проверенный ключ (32 байта), tag/length — тег попытки/его размер в байтах.
* Непубличный source отклоняется; результат возвращается через защищённый управляющий канал. */
void nat_detection_record_observation(struct NAT_DETECTION *detector, struct ETCP_SOCKET *socket,
const uint8_t peer_key[32], const struct sockaddr_storage *source,
const uint8_t *tag, size_t length);
/* Обработать входящую пробу помощника на проверяемом socket, не отвечая ему по UDP.
* peer_key — проверенный ключ (32 байта), source — фактический IP:порт, tag/length — тег попытки/размер в байтах.
* Проверяет подлинность, текущую попытку, публичность и незнакомость IP; неподходящего помощника заменяет. */
void nat_detection_receive_ingress(struct NAT_DETECTION *detector, struct ETCP_SOCKET *socket,
const uint8_t peer_key[32], const struct sockaddr_storage *source,
const uint8_t *tag, size_t length);
/* Запланировать новые проверки всех рабочих сокетов detector, отменив текущие; действует и в ручном режиме. */
void nat_detection_request_check_all(struct NAT_DETECTION *detector);
/* Запланировать проверку socket через конкретный observer (ненулевой ID узла), заменив текущую попытку.
* Возвращает 0 — запрос принят, -1 — сокет/детектор недоступен или observer равен 0; результат придёт позже. */
int nat_detection_request_check_socket(struct NAT_DETECTION *detector, struct ETCP_SOCKET *socket, uint64_t observer);
/* Только для тестов: allow != 0 допускает непубличные IPv4 и IPv6 loopback; по умолчанию такие источники запрещены. */
void nat_detection_set_allow_local(struct NAT_DETECTION *detector, int allow);
/* При ручном режиме помощники продолжают работать, раунды запускает request_check_all. */
/* automatic != 0 включает фоновые проверки (по умолчанию); 0 оставляет ручной запуск request_check_*().
* Уже начатые проверки и помощь другим узлам продолжаются в обоих режимах. */
void nat_detection_set_automatic(struct NAT_DETECTION *detector, int automatic);
/* Записать в status снимок состояния socket; не создаёт состояние и не начинает проверку.
* Возвращает 0 — снимок заполнен, -1 — состояния нет или аргументы непригодны. */
int nat_detection_get_status(struct NAT_DETECTION *detector, struct ETCP_SOCKET *socket, struct nat_check_status *status);
/* Вернуть постоянную строку для reason (enum nat_check_reason); неизвестному значению соответствует "invalid_reason". */
const char *nat_check_reason_name(uint8_t reason);
#ifdef __cplusplus

Loading…
Cancel
Save