Document config identity and publication guarantees
This commit is contained in:
1 parent
bb87a0845b
commit
80eb331d6a
2 files changed
+79
-53
No files matched your search
+12
-3
@@ -1,6 +1,10 @@
|
||||
/* INI-конфигурация ядра: слушающие сокеты, исходящие пиры, сети/подсети и настройки сервисов.
|
||||
* parse_config читает файл, parse_config_from_buf — текст; filename задаёт источник в диагностике.
|
||||
* Успех возвращает выделенную utun_config со списками; освобождение — только free_config.
|
||||
* Файл и буфер проходят один разбор. Пробелы вокруг секций, ключей и значений удаляются;
|
||||
* имена секций нечувствительны к регистру, имена ключей чувствительны. Комментарий — #.
|
||||
* HEX проверяется целиком; ошибочный список REALITY short_ids не применяется частично.
|
||||
* Встроенный NUL и строки >1022 байтов до LF запрещены (CR входит в этот предел).
|
||||
* Парсер заполняет модель, запуск сетевых ресурсов выполняет utun_instance. */
|
||||
#ifndef CONFIG_PARSER_H
|
||||
#define CONFIG_PARSER_H
|
||||
@@ -133,7 +137,7 @@ struct global_config {
|
||||
char my_public_key_hex[MAX_KEY_LEN];
|
||||
uint64_t my_node_id;
|
||||
uint8_t client_type; // 0=server, 1=desktop, 2=mobile
|
||||
int tun_enabled; // 1 = create TUN (default), 0 = skip TUN (run without root)
|
||||
int tun_enabled; // 1 = запрошен TUN, 0 = выключен (значение по умолчанию)
|
||||
char tun_ifname[16]; // TUN interface name (e.g., "tun12")
|
||||
struct IP tun_ip;
|
||||
int mtu;
|
||||
@@ -141,7 +145,7 @@ struct global_config {
|
||||
char control_ip[MAX_ADDR_LEN]; // Control server IP address
|
||||
// Debug and logging configuration
|
||||
char log_file[256]; // Path to log file (empty = stdout)
|
||||
char db_path[256]; // Path to SQLite database (empty = disabled)
|
||||
char db_path[256]; // Каталог chats.db; пусто — ядро использует SQLite :memory:
|
||||
int db_sync_enabled; // 1 = enable distributed DB sync (default: 0)
|
||||
int chatserver_enabled; // 1 = chat server mode (set by [chatserver] section presence)
|
||||
uint32_t db_sync_ttl; // TTL for unsent records in seconds (default: 86400)
|
||||
@@ -165,7 +169,7 @@ struct global_config {
|
||||
int keepalive_timeout; // keepalive timeout in ms (default: 2000)
|
||||
int keepalive_interval; // keepalive interval in ms (default: 200)
|
||||
int keepalive_adaptive; // 1 = adaptive period (default), 0 = fixed interval
|
||||
int bbr_max_cwnd; // BBR cwnd cap in bytes (default: 100000)
|
||||
int bbr_max_cwnd; // BBR cwnd cap in bytes (default: 1048576)
|
||||
|
||||
// Firewall configuration
|
||||
struct CFG_FIREWALL_RULE *firewall_rules;
|
||||
@@ -261,7 +265,12 @@ struct utun_config {
|
||||
struct CFG_NETWORK* networks;
|
||||
};
|
||||
|
||||
/* Непустой путь; результат освобождать free_config. NULL при ошибке открытия, чтения,
|
||||
* закрытия, памяти или обязательной проверки формата. Часть ошибочных опций только
|
||||
* логируется и пропускается; ненулевой результат не гарантирует корректность всех полей. */
|
||||
struct utun_config* parse_config(const char *filename);
|
||||
/* buf — len байтов без завершающего NUL (NULL допустим при len=0), буфер не меняется.
|
||||
* filename — источник для диагностики, NULL означает <buffer>. Возврат как у parse_config. */
|
||||
struct utun_config* parse_config_from_buf(const char *buf, size_t len, const char *filename);
|
||||
void free_config(struct utun_config *config);
|
||||
void print_config(const struct utun_config *config);
|
||||
|
||||
+67
-50
@@ -1,67 +1,84 @@
|
||||
# Config Updater (config_updater.c/h)
|
||||
|
||||
## 1. Назначение
|
||||
Модуль обеспечивает согласованные X25519-ключи и node_id в INI-файле до его загрузки ядром.
|
||||
При включённом REALITY также обеспечивает private_key и непустой список short_ids.
|
||||
Публичный контракт приведён в config_updater.h, общий разбор строк — в config_ini.h.
|
||||
|
||||
Утилита автоматической инициализации и обновления ключей в конфигурационном файле uTun.
|
||||
## Выбор значений
|
||||
|
||||
Основная задача — гарантировать, что в конфиге всегда присутствуют корректные и согласованные:
|
||||
- `my_private_key` (X25519, 64 hex символа)
|
||||
- `my_public_key` (производный от private, 64 hex)
|
||||
- `my_node_id` (SHA256-идентификатор узла, 16 hex символов, вычисляется из private key)
|
||||
Имена секций сравниваются целиком без учёта регистра, пробелы вокруг имени секции,
|
||||
ключа и значения удаляются. Имена ключей чувствительны к регистру. Комментарии — #.
|
||||
Последнее текстовое значение ключа во всех соответствующих секциях определяет результат,
|
||||
включая пустое или некорректное. Опции из других секций не участвуют.
|
||||
|
||||
Если чего-то нет или значение неконсистентно — модуль генерирует недостающее через `secure_channel.h` и атомарно перезаписывает конфиг, сохраняя всё остальное содержимое файла нетронутым.
|
||||
- Корректный my_private_key — ровно 64 HEX-символа; его бинарное значение сохраняется.
|
||||
- my_public_key вычисляется через sc_compute_public_key_from_private().
|
||||
- my_node_id вычисляется через sc_derive_node_id_from_pubkey(): SHA256 публичного ключа,
|
||||
первые восемь байтов в представлении функции, старший бит сброшен.
|
||||
- Если приватный ключ отсутствует или некорректен, создаётся новая идентичность.
|
||||
- Сравнение HEX выполняется по байтам: регистр букв не вызывает перезапись.
|
||||
- При включённом REALITY некорректный/отсутствующий private_key генерируется заново.
|
||||
Некорректный/пустой/отсутствующий short_ids заменяется четырьмя случайными ID.
|
||||
Корректный список сохраняется целиком. Ошибка одного элемента отклоняет весь список.
|
||||
- При выключенном REALITY его параметры не исправляются.
|
||||
|
||||
## 2. Как пользоваться
|
||||
HEX проверяется посимвольно до декодирования. Частичные результаты проверки не применяются.
|
||||
Встроенный NUL и физические строки длиннее 1022 байтов до LF запрещены; CR учитывается в этом пределе.
|
||||
|
||||
```c
|
||||
#include "config_updater.h"
|
||||
## Изменение текста
|
||||
|
||||
int ret = config_ensure_keys_and_node_id("/etc/utun/config.ini");
|
||||
if (ret == 0) {
|
||||
// Конфиг готов: ключи и node_id гарантированно на месте
|
||||
} else {
|
||||
// Ошибка — смотри DEBUG_*(DEBUG_CATEGORY_CONFIG)
|
||||
}
|
||||
```
|
||||
Исправный файл остаётся побайтно неизменным. Если поле требует исправления,
|
||||
обновляются все его вхождения в соответствующих секциях. Недостающие поля добавляются
|
||||
в конец последней подходящей секции; отсутствующая секция создаётся в конце файла.
|
||||
|
||||
**Типовой сценарий (первый запуск):**
|
||||
1. Файла нет → создаётся минимальный `[global]` с `my_node_name`, сгенерированными ключами и `my_node_id`.
|
||||
2. Файл есть, но нет `my_private_key` → генерируется новая X25519-пара, записываются все три поля.
|
||||
3. Файл есть с `my_private_key`, но нет `my_public_key` или `my_node_id` → вычисляются из private key, дописываются.
|
||||
4. Все поля есть, но `my_public_key` не соответствует `my_private_key` или `my_node_id` не совпадает → перезаписываются на корректные.
|
||||
Посторонние строки сохраняются побайтно. В изменяемых строках сохраняются пробелы,
|
||||
комментарии и окончания строк вокруг заменяемого значения. Добавляемые строки используют
|
||||
тип первого окончания строки в файле, либо LF. При необходимости добавляется разделитель
|
||||
после последней строки без LF. Новый или пустой файл получает [global] с тремя полями идентичности.
|
||||
|
||||
**Нюансы:**
|
||||
- Вычисление pubkey: `sc_compute_public_key_from_private(priv_bin, pub_bin)`.
|
||||
- Вычисление node_id: `sc_derive_node_id(priv_bin)`.
|
||||
- Генерация новой пары ключей: `sc_generate_keypair(&mykeys)`.
|
||||
- Файл читается целиком в память, модифицируется через `insert_or_replace_option`, затем пишется обратно. Это атомарно: либо файл полностью перезаписан, либо остался нетронутым (при ошибке).
|
||||
- Редактирование in-place через `memmove`: строки не сдвигают остальной конфиг, только вставляются/заменяются нужные опции внутри секции `[global]`.
|
||||
- Для нового файла создаётся минимальный `[global]` с именем узла из `my_node_name` (или `"utun"` если не задано).
|
||||
Перед записью итоговый текст проверяется строгими декодерами и штатным парсером.
|
||||
Это проверка полей идентичности и необходимых параметров REALITY; парсер продолжает
|
||||
логировать и пропускать некоторые ошибки прочих опций.
|
||||
|
||||
## 3. API
|
||||
## Запись и ошибки
|
||||
|
||||
### Функции
|
||||
config_ensure_keys_and_node_id(filename) принимает непустой путь. Вызывающая сторона
|
||||
исключает параллельную запись конфигурации. Возврат 0 означает корректные значения и,
|
||||
если требовалось обновление, успешную запись. Возврат -1 означает ошибку с диагностикой CONFIG.
|
||||
|
||||
| Функция | Назначение |
|
||||
|---------|------------|
|
||||
| `config_ensure_keys_and_node_id(filename)` | **Основная функция.** Читает конфиг, проверяет/генерирует ключи и node_id, записывает обратно. Возвращает 0 при успехе, -1 при ошибке. |
|
||||
| `bytes_to_hex(bytes, len, hex_str, hex_len)` | Вспомогательная: конвертация бинарного массива в hex-строку. Безопасна для нулевых указателей и маленьких буферов. |
|
||||
Новый файл создаётся только при ENOENT. Ошибка доступа, чтения, выделения памяти или
|
||||
закрытия входного файла прекращает операцию. Временный файл создаётся эксклюзивно
|
||||
рядом с исходным. Проверяются запись, fflush, синхронизация и fclose до замены имени.
|
||||
|
||||
### Внутренние функции (static)
|
||||
На POSIX применяется rename, затем fsync каталога:
|
||||
- До успешного rename исходный файл при ошибках сохраняется.
|
||||
- Ошибка fsync каталога после rename возвращает -1 и логируется с replaced=1.
|
||||
Файл уже заменён; устойчивость замены к аварии не подтверждена.
|
||||
- Сохраняются uid/gid и обычные права доступа (0777); новый файл имеет 0600.
|
||||
ACL, xattrs и специальные биты режима не копируются.
|
||||
- Временный файл удаляется при ошибках до публикации; ошибка удаления логируется.
|
||||
|
||||
| Функция | Назначение |
|
||||
|---------|------------|
|
||||
| `is_valid_priv_key(key)` | Проверяет, что строка — 64 hex-символа |
|
||||
| `is_valid_pub_key(key)` | То же для публичного ключа |
|
||||
| `is_valid_node_id(node_id)` | Проверяет `node_id != 0` |
|
||||
| `write_mem_to_file(filename, buffer, size)` | Пишет буфер в файл (одной операцией) |
|
||||
| `find_section_global(buf, buf_len)` | Ищет позицию после `[global]` в текстовом буфере |
|
||||
| `find_option(buf, buf_len, option)` | Ищет строку `option=...` в буфере |
|
||||
| `insert_or_replace_option(buf, buf_len, buf_capacity, option, value)` | Заменяет значение опции при наличии, либо вставляет новую строку после `[global]`. Работает с `memmove`/`memcpy`, перевыделяет буфер при необходимости. |
|
||||
На Windows используются _commit и ReplaceFileA для существующего файла либо
|
||||
MoveFileExA с MOVEFILE_WRITE_THROUGH для нового. Модуль не расширяет гарантии
|
||||
восстановления после ошибок этих Windows API.
|
||||
|
||||
### Зависимости
|
||||
Если требуется запись, символические ссылки/reparse points и файлы с несколькими
|
||||
жёсткими ссылками отклоняются. Проверка исправного файла по ссылке возможна без записи.
|
||||
|
||||
- `secure_channel.h` — `sc_generate_keypair()`, `sc_compute_public_key_from_private()`, `sc_derive_node_id()`
|
||||
- `config_parser.h` — `parse_config_from_buf()`, `free_config()`, структуры `utun_config`/`global_config`
|
||||
- `lib/mem.h` — `u_malloc`, `u_realloc`, `u_free`
|
||||
- `lib/debug_config.h` — `DEBUG_*`
|
||||
Логи показывают причину генерации, изменяемые поля, этап ошибки и факт замены файла.
|
||||
Значения приватных ключей updater не выводит.
|
||||
|
||||
## Вспомогательная функция
|
||||
|
||||
bytes_to_hex(bytes, len, hex_str, hex_len) записывает 2*len строчных HEX-символов и NUL.
|
||||
Буферы не перекрываются. bytes и hex_str обязательны; hex_len задаёт ёмкость результата.
|
||||
При недостаточной ёмкости или NULL функция обнуляет доступный hex_str[0]; усечения нет.
|
||||
Проверка ёмкости не вычисляет переполняющееся 2*len+1. При len=0 результат пустой.
|
||||
|
||||
## Проверки
|
||||
|
||||
tests/test_config_updater.c проверяет сохранение идентичности, регистр, пробелы,
|
||||
секции и дубли, CRLF, повторный вызов, строгий HEX/списки, длинные строки/NUL, ссылки,
|
||||
права доступа, ошибки файловых операций и отказы памяти. Внедрение ошибок через
|
||||
Linux/ELF linker wrappers не добавляет тестовых веток в рабочий код.
|
||||
tests/test_reality_config.c проверяет базовые сценарии генерации REALITY.
|
||||
Reference in new issue
Block a user