Align packet dump and CRC32 contracts with implementations
This commit is contained in:
1 parent
c3fa6d4db1
commit
ce30ec5fe6
3 files changed
+60
-24
No files matched your search
@@ -14,16 +14,19 @@ extern "C" {
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// Initialize CRC32 table (called automatically on first use)
|
||||
/* Инициализирует общую таблицу (повторный вызов ничего не меняет).
|
||||
* Вызывается автоматически из calc/calc_ex; до параллельных вызовов выполнить в одном потоке. */
|
||||
void crc32_init(void);
|
||||
|
||||
// Calculate CRC32 checksum
|
||||
/* data/len — блок байтов, выравнивание не требуется. Для непустого блока возвращает финальный CRC-32;
|
||||
* при data==NULL или len==0 возвращает UINT32_MAX, а не стандартный CRC пустого блока (0). */
|
||||
uint32_t crc32_calc(const uint8_t *data, size_t len);
|
||||
|
||||
// Calculate CRC32 with initial value
|
||||
/* Обновляет initial_crc байтами data[0..len), возвращает CRC без финальной инверсии.
|
||||
* При data==NULL или len==0 возвращает initial_crc. Для обычного CRC начать с UINT32_MAX. */
|
||||
uint32_t crc32_calc_ex(const uint8_t *data, size_t len, uint32_t initial_crc);
|
||||
|
||||
// Update CRC32 incrementally
|
||||
/* Эквивалент crc32_calc_ex(data, len, crc); финальная инверсия — ответственность вызывающего. */
|
||||
uint32_t crc32_update(uint32_t crc, const uint8_t *data, size_t len);
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
# crc32
|
||||
|
||||
## 1. Назначение
|
||||
Модуль вычисления контрольной суммы **CRC-32 (IEEE 802.3)** с полиномом `0xEDB88320`. Используется в подсистемах `secure_channel` и `stcp` для контроля целостности данных при передаче — перед шифрованием к данным добавляется CRC32, при расшифровке CRC32 пересчитывается и сверяется.
|
||||
Модуль вычисления контрольной суммы **CRC-32 (IEEE 802.3)** с отражённым полиномом `0xEDB88320`. Используется в подсистемах `secure_channel` и `stcp` для контроля целостности данных при передаче — перед шифрованием к данным добавляется CRC32, при расшифровке CRC32 пересчитывается и сверяется. `stun_nat` также использует результат для поля FINGERPRINT с дополнительным XOR `0x5354554e`.
|
||||
|
||||
Общая изменяемая таблица инициализируется без синхронизации. Перед первым параллельным использованием
|
||||
нужно вызвать `crc32_init()` в одном потоке, завершив инициализацию до запуска остальных;
|
||||
после этого вычисления только читают таблицу. Динамических выделений и логирования нет.
|
||||
|
||||
## 2. Как пользоваться
|
||||
|
||||
**Одноразовое вычисление (внутренне инициализирует таблицу при первом вызове):**
|
||||
```c
|
||||
// Исходное значение 0xFFFFFFFF, результат XOR-ится с ~0
|
||||
// Для непустого блока: исходное значение UINT32_MAX, в конце побитовая инверсия
|
||||
uint32_t crc = crc32_calc(data, data_len);
|
||||
```
|
||||
|
||||
@@ -20,6 +24,9 @@ while (chunk) {
|
||||
crc ^= 0xFFFFFFFF; // финальный XOR
|
||||
```
|
||||
|
||||
Для пустого потока этот пример даёт 0. В отличие от него, `crc32_calc(NULL, len)` и
|
||||
`crc32_calc(data, 0)` возвращают `UINT32_MAX`: это особенность API, а не стандартный CRC пустого блока.
|
||||
|
||||
**С произвольным начальным значением (без финального XOR):**
|
||||
```c
|
||||
uint32_t crc = crc32_calc_ex(data, len, initial_crc);
|
||||
@@ -29,7 +36,7 @@ uint32_t crc = crc32_calc_ex(data, len, initial_crc);
|
||||
|
||||
| Функция | Описание |
|
||||
|---------|----------|
|
||||
| `crc32_init()` | Принудительная инициализация lookup-таблицы (256 × uint32_t). Автоматически вызывается при первом использовании, ручной вызов не обязателен. |
|
||||
| `crc32_init()` | Инициализация lookup-таблицы (256 × uint32_t). Повторный вызов ничего не меняет. Для однопоточного использования достаточно автоинициализации; для многопоточного нужна предварительная инициализация. |
|
||||
| `crc32_calc(data, len)` | CRC32 «в один проход». Авто-инит, начальное значение `0xFFFFFFFF`, финальный `~crc`. При `data == NULL` или `len == 0` возвращает `0xFFFFFFFF`. |
|
||||
| `crc32_ex(data, len, initial_crc)` | CRC32 с заданным начальным значением, **без** финального XOR. Подходит для инкрементального использования и цепочек вызовов. |
|
||||
| `crc32_update(crc, data, len)` | Синоним `crc32_ex(data, len, crc)` — инкрементальное обновление. |
|
||||
| `crc32_calc_ex(data, len, initial_crc)` | CRC32 с заданным начальным значением, **без** финального XOR. При `data == NULL` или `len == 0` возвращает `initial_crc`; иначе обрабатывает ровно `len` байт. |
|
||||
| `crc32_update(crc, data, len)` | Эквивалент `crc32_calc_ex(data, len, crc)` — инкрементальное обновление. |
|
||||
@@ -1,9 +1,9 @@
|
||||
# Packet Dump (декодирование IP-пакетов)
|
||||
|
||||
## 1. Назначение
|
||||
Вспомогательный модуль для диагностики: парсит сырой IPv4-пакет и формирует человекочитаемую строку с IP-адресами, протоколом, портами, флагами и hex-дампом 32 байт после IP-заголовка, включая транспортный заголовок. Вызывается из отладочных логов категорий `tun` и `traffic`.
|
||||
Вспомогательный модуль для диагностики: парсит сырой IPv4-пакет и формирует человекочитаемую строку с IP-адресами, протоколом, портами, флагами и hex-дампом до 32 байт после IP-заголовка, включая транспортный заголовок. Вызывается из отладочных логов категорий `tun` и `traffic`.
|
||||
|
||||
**Незавершённый аудит 25.10.2026:** hex-дамп во всех трёх ветках читает фиксированные 32 байта без проверки остатка входного пакета. Это дефект, затрагивающий также распознанные TCP/UDP/ICMP-пакеты. Ограничение длины выходного буфера не защищает входные чтения. Исправление и оставшиеся проверки описаны в `doc/tasks.md`; runtime-проверка в этом продолжении не выполнялась.
|
||||
Все чтения ограничены доступной длиной и полем IPv4 total length. Выравнивание входного указателя не требуется: адреса и поля читаются побайтно, независимо от порядка байтов процессора. Динамическая память не выделяется.
|
||||
|
||||
## 2. Как пользоваться
|
||||
|
||||
@@ -23,10 +23,9 @@ DEBUG_DEBUG(DEBUG_CATEGORY_TUN, "[TUN->] %s", str);
|
||||
### Примеры вывода
|
||||
|
||||
```
|
||||
IPv4 TCP 192.168.1.5:443 -> 10.0.0.2:54321 (1420 bytes) [ACK,PSH] seq=123456 ack=789012 win=64240 data: 1703012345...
|
||||
IPv4 UDP 10.0.0.1:53 -> 192.168.1.3:45678 (76 bytes) len=56 data: 4500003c...
|
||||
IPv4 ICMP 10.0.0.1 -> 8.8.8.8 (84 bytes) echo_request seq=1 id=1234 data: 08004d2c...
|
||||
IPv4 ICMP 8.8.8.8 -> 10.0.0.1 (84 bytes) echo_reply seq=1 id=1234 data: 0000552c...
|
||||
IPv4 UDP 192.168.1.2:0 -> 10.20.30.40:443 (28 bytes) len=8 data: 000001bb00080000
|
||||
IPv4 ICMP 192.168.1.2 -> 10.20.30.40 (28 bytes) echo_request seq=43981 id=4660 data: 080000001234abcd
|
||||
IPv4 UNKNOWN 192.168.1.2 -> 10.20.30.40 (20 bytes) data:
|
||||
```
|
||||
|
||||
## 3. API
|
||||
@@ -36,18 +35,37 @@ IPv4 ICMP 8.8.8.8 -> 10.0.0.1 (84 bytes) echo_reply seq=1 id=1234 data: 0000552c
|
||||
**`dump_ip_packet_to_buffer(data, len)`** — парсит IPv4-заголовок и заголовок транспортного уровня, возвращает строку вида `IPv4 PROTO SRC:PORT -> DST:PORT (SIZE bytes) DETAILS data: HEX...`.
|
||||
|
||||
Параметры:
|
||||
- `data` — указатель на начало IPv4-пакета
|
||||
- `len` — полная длина данных
|
||||
- Возвращает `static char[1024]`
|
||||
- `data` — указатель на начало IPv4-пакета; `NULL` даёт диагностическую строку.
|
||||
- `len` — число доступных байт; может включать хвост после IPv4 total length, который игнорируется.
|
||||
- Возвращает общий NUL-терминированный `static char[1024]`; не освобождать и не изменять.
|
||||
- Размер в штатной строке — IPv4 total length, а не длина захваченного буфера.
|
||||
|
||||
Перед разбором проверяются минимальные 20 байт IPv4, version=4, IHL>=20,
|
||||
наличие всех байт IHL и условие IHL<=total length<=len.
|
||||
При отказе возвращается только причина с длинами (`Missing IP packet`, `Packet too small`,
|
||||
`Non-IPv4 packet`, `Invalid IP header length`, `Truncated IP header`,
|
||||
`Invalid IP total length`, `Truncated IPv4 packet`); она также логируется как `dump=warn`.
|
||||
|
||||
Обрабатываемые протоколы:
|
||||
- **TCP (6):** порты, seq/ack, флаги (FIN, SYN, RST, PSH, ACK, URG, ECE, CWR), window
|
||||
- **UDP (17):** порты, длина
|
||||
- **ICMP (1):** тип/code, echo_request/echo_reply с seq и id
|
||||
- **TCP (6):** при наличии 20 байт — порты, seq/ack, флаги (FIN, SYN, RST, PSH, ACK, URG, ECE, CWR), window.
|
||||
- **UDP (17):** при наличии 8 байт — порты и поле длины UDP.
|
||||
- **ICMP (1):** при наличии 8 байт — тип/code, для echo_request/echo_reply также seq и id.
|
||||
|
||||
Для нераспознанных протоколов выводит `src_ip:0 -> dst_ip:0` и пытается прочитать 32 байта после IP-заголовка. При коротком остатке это чтение выходит за границы входа; допустимым контрактом API такое поведение не является.
|
||||
Порты выводятся также при значении 0. Все восемь TCP-флагов помещаются целиком;
|
||||
при отсутствии флагов выводится `none`. Полную корректность транспорта, его длины и checksum модуль не проверяет.
|
||||
|
||||
Hex-дамп: 32 байта начиная с `data[ihl]`, включая транспортный заголовок, 4 группы по 8 байт. Корректное ограничение фактически доступной длиной пока отсутствует.
|
||||
При ненулевом IPv4 fragment offset транспортный заголовок не разбирается;
|
||||
имя протокола, адреса и hex-фрагмент сохраняются. Для всех фрагментированных пакетов
|
||||
добавляется `fragment offset=N MF=0/1`, где offset измеряется в байтах.
|
||||
Первый фрагмент с MF=1 разбирается, если его транспортный заголовок помещается.
|
||||
При коротком заголовке выводится `partial header: available=N required=M` (`dump=debug`);
|
||||
для нефрагментированного пакета — `truncated header: available=N required=M` (`dump=warn`).
|
||||
В обоих случаях доступный hex-фрагмент сохраняется.
|
||||
|
||||
Для нераспознанного протокола выводит `UNKNOWN`, адреса без портов и доступный hex-фрагмент.
|
||||
|
||||
Hex-дамп: min(32, total length - IHL) байт начиная с `data[ihl]`, включая транспортный заголовок;
|
||||
группы по 8 байт разделены пробелом. При пустом остатке после `data:` нет hex-цифр.
|
||||
|
||||
**`tcp_flags_to_str(flags)`** (static) — преобразует байт TCP-флагов в строку вида `SYN,ACK` или `none`.
|
||||
|
||||
@@ -56,5 +74,13 @@ Hex-дамп: 32 байта начиная с `data[ihl]`, включая тра
|
||||
- `routing_layer/routing.c` — логирование пакетов перед передачей в локальный TUN (категория `traffic`, уровень `debug`)
|
||||
|
||||
### Зависимости
|
||||
- `platform_compat.h` — порядок байт (не используется в текущей реализации, IP-адреса читаются напрямую как LE)
|
||||
- `debug_config.h` — диагностика ошибочного входа и частичного транспортного заголовка (категория `dump`).
|
||||
- Стандартная библиотека: `<stdio.h>`, `<string.h>`
|
||||
|
||||
### Проверки
|
||||
|
||||
`make -C tests test_packet_dump` и `./tests/test_packet_dump` вызывают настоящий форматтер:
|
||||
проверяются вывод TCP/UDP/ICMP/UNKNOWN, все TCP-флаги, нулевые порты, IPv4 options,
|
||||
77 длин захваченного пакета, невыровненный вход, фрагменты, диагностика неверных заголовков
|
||||
и сохранность входа. Матрица из 2904 случаев проверяет точный hex для четырёх протоколов,
|
||||
11 значений IHL и 0..65 байт после IP-заголовка.
|
||||
Reference in new issue
Block a user