mirror of https://github.com/ospab/ostp.git
Polish docs/README to match v0.4.x: fix license mismatch, CLI, crypto docs
- README.md/README.ru.md: License section still said "Business Source
License 1.1 ... converts to MIT in 2030" while the badge right above it,
Cargo.toml, and LICENSE itself all say AGPL-3.0 — a direct contradiction.
Now both say AGPL-3.0 and link to LICENSE.
- README.md/README.ru.md: CLI Reference / Quick Start described the old
flag-based interface (--init, --check, --generate-key, --links, bare
positional URL) that no longer exists after the subcommand refactor.
Rewrote both to the current `ostp <command>` surface (run/connect/setup/
init/check/gk/links/import/update/migrate/prober/proxy-env/uninstall),
including gk's alias and update's --branch/--version. RU previously had
no command reference at all; added one to match EN.
- docs/{en,ru}/obfuscation.md: removed the XTLS-Reality section (feature
removed in §A) and replaced it with an accurate description of junk
packets + TCP fragmentation, the actual current supplementary stealth
mechanism, including the per-key junk marker (no global DPI signature).
Also corrected the key-derivation and masking-algorithm descriptions,
which described a much older scheme (SHA-256(access_key)[0..8] + static/
nonce-based XOR) than what derive_all_secrets()/derive_payload_mask()
actually implement now (HKDF with version-gated, domain-separated
outputs; HMAC-SHA256 mask keyed on the packet's own ciphertext). The RU
version was additionally rewritten out of an oddly formal "industrial
telemetry" register into plain technical Russian.
This commit is contained in:
parent
5e0ff4a7ef
commit
6929d42736
48
README.md
48
README.md
|
|
@ -95,10 +95,10 @@ graph TD
|
|||
|
||||
```bash
|
||||
# On your VPS (server):
|
||||
./ostp --init server
|
||||
./ostp init server
|
||||
|
||||
# On your machine (client):
|
||||
./ostp --init client
|
||||
./ostp init client
|
||||
```
|
||||
|
||||
### 2. Edit config
|
||||
|
|
@ -131,14 +131,14 @@ graph TD
|
|||
```bash
|
||||
./ostp # Uses config.json in current directory
|
||||
./ostp --config /path/to.json # Custom config path
|
||||
./ostp --check # Validate config without running
|
||||
./ostp --generate-key # Generate a new access key
|
||||
./ostp --links # Print client share links
|
||||
./ostp check # Validate config without running
|
||||
./ostp gk # Generate a new access key
|
||||
./ostp links # Print client share links
|
||||
```
|
||||
|
||||
### 4. Connect via share link (one-liner)
|
||||
```bash
|
||||
./ostp "ostp://ACCESS_KEY@server.com:50000?..."
|
||||
./ostp connect "ostp://ACCESS_KEY@server.com:50000?..."
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
|
|
@ -171,21 +171,34 @@ Full API reference: [Management API](https://github.com/ospab/ostp/wiki/Manageme
|
|||
## CLI Reference
|
||||
|
||||
```
|
||||
ostp [OPTIONS] [URL]
|
||||
ostp [--config <PATH>] [COMMAND]
|
||||
|
||||
Options:
|
||||
--config <PATH> Config file path (default: config.json)
|
||||
--init <MODE> Generate template config (server/client)
|
||||
--check Validate configuration and exit
|
||||
-g, --generate-key Generate a secure access key
|
||||
-c, --count <N> Number of keys to generate (default: 1)
|
||||
Commands:
|
||||
run Run the daemon using the config file (default when no command is given)
|
||||
connect <URL> Connect once using a share link: ostp://KEY@HOST:PORT
|
||||
setup Interactive setup wizard
|
||||
init <MODE> Generate a template config (server/client/relay)
|
||||
check Validate the configuration file and exit
|
||||
gk Generate a secure access key (alias: generate-key)
|
||||
--format <FMT> Key format: hex, base64 (default: hex)
|
||||
--links Print client share links from server config
|
||||
-n, --count <N> Number of keys to generate (default: 1)
|
||||
links Print client share links from the server config
|
||||
import <URL> Import a share link into the config file
|
||||
update Update OSTP to the latest release
|
||||
-b, --branch <NAME> Release channel: stable, pre-release, nightly (default: stable)
|
||||
-v, --version <VER> Update to an exact version instead of the channel's latest
|
||||
migrate Force-migrate the configuration file to the current format
|
||||
prober Run the DNS-transport resolver prober
|
||||
proxy-env Print shell export commands for the local SOCKS proxy
|
||||
proxy-env-clear Print shell export commands to unset it
|
||||
uninstall Stop the service and remove the binary and config
|
||||
|
||||
Arguments:
|
||||
[URL] Connect via share link: ostp://KEY@HOST:PORT
|
||||
Global options:
|
||||
--config <PATH> Config file path (default: config.json)
|
||||
```
|
||||
|
||||
Every subcommand also accepts `-h`/`--help` for its own option list.
|
||||
|
||||
---
|
||||
|
||||
## Protocol Summary
|
||||
|
|
@ -230,8 +243,7 @@ cargo test -p ostp-core -p ostp-server
|
|||
|
||||
## License
|
||||
|
||||
Business Source License 1.1. Free for personal and non-commercial use.
|
||||
Converts to MIT License on May 14, 2030.
|
||||
GNU Affero General Public License v3.0 (AGPL-3.0). See [LICENSE](LICENSE) for the full text.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
38
README.ru.md
38
README.ru.md
|
|
@ -84,8 +84,8 @@ irm https://raw.githubusercontent.com/ospab/ostp/master/scripts/install.ps1 | ie
|
|||
|
||||
Создать конфиг по умолчанию:
|
||||
```bash
|
||||
./ostp --init server # VPS
|
||||
./ostp --init client # Локальная машина
|
||||
./ostp init server # VPS
|
||||
./ostp init client # Локальная машина
|
||||
```
|
||||
|
||||
### Сервер (`config.json`)
|
||||
|
|
@ -156,6 +156,37 @@ irm https://raw.githubusercontent.com/ospab/ostp/master/scripts/install.ps1 | ie
|
|||
./ostp
|
||||
```
|
||||
|
||||
### Справка по командам
|
||||
|
||||
```
|
||||
ostp [--config <PATH>] [КОМАНДА]
|
||||
|
||||
Команды:
|
||||
run Запустить демон по конфигу (по умолчанию, если команда не указана)
|
||||
connect <URL> Подключиться по share-ссылке: ostp://KEY@HOST:PORT
|
||||
setup Интерактивный мастер настройки
|
||||
init <MODE> Сгенерировать шаблон конфига (server/client/relay)
|
||||
check Проверить конфиг и выйти
|
||||
gk Сгенерировать access-key (алиас: generate-key)
|
||||
--format <FMT> Формат ключа: hex, base64 (по умолчанию hex)
|
||||
-n, --count <N> Количество ключей (по умолчанию 1)
|
||||
links Вывести client-share-ссылки из серверного конфига
|
||||
import <URL> Импортировать share-ссылку в конфиг
|
||||
update Обновить OSTP до актуального релиза
|
||||
-b, --branch <NAME> Канал релиза: stable, pre-release, nightly (по умолчанию stable)
|
||||
-v, --version <VER> Обновиться на точную версию вместо последней в канале
|
||||
migrate Принудительно мигрировать конфиг к текущему формату
|
||||
prober Запустить DNS-transport prober
|
||||
proxy-env Вывести shell-команды для локального SOCKS-прокси
|
||||
proxy-env-clear Вывести shell-команды для их отмены
|
||||
uninstall Остановить сервис и удалить бинарник с конфигом
|
||||
|
||||
Глобальные опции:
|
||||
--config <PATH> Путь к конфигу (по умолчанию config.json)
|
||||
```
|
||||
|
||||
У каждой подкоманды есть своя справка через `-h`/`--help`.
|
||||
|
||||
### TUN-режим (Windows)
|
||||
Использует встроенный сетевой стек `smoltcp` и виртуальный адаптер `wintun` (необходима `wintun.dll`). Требует запуска с правами Администратора.
|
||||
|
||||
|
|
@ -204,5 +235,4 @@ cross build --release --target x86_64-unknown-linux-gnu
|
|||
|
||||
## Лицензия
|
||||
|
||||
Business Source License 1.1. Бесплатно для личного и некоммерческого использования.
|
||||
Переходит в MIT License 14 мая 2030 года.
|
||||
GNU Affero General Public License v3.0 (AGPL-3.0). Полный текст — в файле [LICENSE](LICENSE).
|
||||
|
|
|
|||
|
|
@ -5,40 +5,38 @@ Traditional tunneling protocols (such as TLS, OpenVPN, and WireGuard) exhibit di
|
|||
|
||||
---
|
||||
|
||||
## Obfuscation Key Derivation
|
||||
## Secret Derivation
|
||||
|
||||
To dynamically mask protocol data, an 8-byte obfuscation key is statically derived from the shared `access_key` configured on both the client and the server:
|
||||
Every protocol secret — the obfuscation key, the Noise PSK, the handshake padding range, and the per-key junk marker (see below) — is derived from the shared `access_key` via a single HKDF-SHA256 pass, domain-separated by a trailing info byte per output:
|
||||
|
||||
$$\text{Key} = \text{SHA-256}(\text{access\_key})[0..8]$$
|
||||
```
|
||||
PRK = HKDF-Extract(salt = SHA-256(access_key)[0..16], IKM = access_key || PROTOCOL_VERSION)
|
||||
obfuscation_key = HKDF-Expand(PRK, info = SHA-256(access_key)[16..] || 0x01, 8 bytes)
|
||||
psk = HKDF-Expand(PRK, info = SHA-256(access_key)[16..] || 0x02, 32 bytes)
|
||||
handshake_pad = HKDF-Expand(PRK, info = SHA-256(access_key)[16..] || 0x03, 2 bytes)
|
||||
junk_marker = HKDF-Expand(PRK, info = SHA-256(access_key)[16..] || 0x04, 4 bytes)
|
||||
```
|
||||
|
||||
This key is established pre-session and is never transmitted across the wire in any capacity.
|
||||
The wire protocol version is mixed into the IKM, not sent as a plaintext byte: peers on a different protocol version derive an entirely different `obfuscation_key`, so they simply cannot deobfuscate each other's packets and are rejected as unauthorized — a hard version gate with no recognizable marker ever appearing on the wire. No secret is ever transmitted; both sides derive the same values independently from the shared access key.
|
||||
|
||||
---
|
||||
|
||||
## Dynamic In-Place Masking Algorithm
|
||||
|
||||
OSTP datagrams are processed "in-place" immediately prior to transmission and right after arrival. Two distinct mathematical modes are utilized based on the current handshake phase:
|
||||
OSTP datagrams are masked "in-place" immediately prior to transmission and right after arrival. The mask itself is **derived from the packet's own ciphertext**, not from a fixed keystream or a counter, so it changes with every packet automatically:
|
||||
|
||||
```
|
||||
mask = HMAC-SHA256(key = obfuscation_key, message = ciphertext[0..min(32, len)])
|
||||
```
|
||||
|
||||
### 1. Handshake Phase Mode (`is_handshake = true`)
|
||||
During connection initiation (Noise Handshake), the wire packet consists of a 4-byte `session_id` prefixed to the Noise payload. To mask the fixed session ID:
|
||||
|
||||
* **Masking**: The first 4 bytes are XORed with the first 4 bytes of the derived obfuscation key:
|
||||
$$\text{raw}[i] = \text{raw}[i] \oplus \text{Key}[i \pmod 8], \quad i \in [0..3]$$
|
||||
* **De-masking**: A repeated XOR with the identical key bytes recovers the original `session_id`.
|
||||
The wire packet is `[4-byte session_id][2-byte noise_len][Noise payload]`. The mask is computed over the Noise payload (`raw[6..]`), and its first 6 bytes are XORed onto `session_id || noise_len`.
|
||||
|
||||
### 2. Data Transmission Mode (`is_handshake = false`)
|
||||
Post-handshake, the wire layout contains:
|
||||
`[4-byte session_id]` + `[8-byte nonce]` + `[AEAD Ciphertext]`
|
||||
The wire packet is `[4-byte session_id][8-byte nonce][AEAD ciphertext]`. The mask is computed over the AEAD ciphertext, and its first 12 bytes are XORed onto `session_id || nonce`.
|
||||
|
||||
To completely randomize metadata, a two-tiered dynamic XOR masking process is applied:
|
||||
|
||||
1. **Nonce Masking**: The 8-byte `nonce` (sequence counter) is XORed with the full 8-byte static key:
|
||||
$$\text{nonce\_bytes}[i] = \text{nonce\_bytes}[i] \oplus \text{Key}[i], \quad i \in [0..7]$$
|
||||
2. **Session ID Masking**: The 4-byte `session_id` is masked using high dynamic entropy — the lower 32 bits of the **original (unmasked)** `nonce` value:
|
||||
$$\text{session\_id\_bytes}[i] = \text{session\_id\_bytes}[i] \oplus \text{real\_nonce\_low32\_bytes}[i], \quad i \in [0..3]$$
|
||||
|
||||
#### Impact of the Scheme:
|
||||
Because the `nonce` increments strictly with each outgoing datagram, the session ID's masking keystream continuously changes. This breaks all packet header correlations and eliminates repeating byte patterns, rendering statistical fingerprinting futile.
|
||||
#### Impact of the Scheme
|
||||
Because the mask is keyed on both the shared secret and the packet's own ciphertext, no two packets — even consecutive ones from the same session — share a keystream, without needing an explicit counter-based scheme. This breaks all packet header correlations and eliminates repeating byte patterns, rendering statistical fingerprinting futile.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -50,6 +48,13 @@ The `AdaptivePadder` calculates dynamic dummy byte quantities to append to the p
|
|||
- **Dynamic Distributions**: The padding algorithms emulate length profiles commonly seen in whitelisted HTTPS or real-time video streams.
|
||||
- **Encrypted Overheads**: The appended padding resides within the AEAD cipher scope. Consequently, passive observers cannot distinguish padding bytes from useful application payload, hiding the true message boundary lengths.
|
||||
|
||||
## XTLS-Reality Impersonation
|
||||
---
|
||||
|
||||
OSTP provides a custom, dependency-free implementation of the XTLS-Reality protocol. It fully simulates a TLS 1.3 handshake (with realistic ClientHello profiles) to bypass advanced DPI filters. Post-handshake, it utilizes ChaCha20Poly1305 to seamlessly encrypt and tunnel the inner HTTP/WSS connections.
|
||||
## Junk Packets & TCP Fragmentation
|
||||
|
||||
OSTP does not try to impersonate a known protocol (TLS, HTTP, or otherwise) — a fingerprint-matching filter can always be updated to catch an impersonation attempt. Instead it follows a **zapret-like** approach: no recognizable header at all, plus active manipulation of packet boundaries, so there is nothing distinctive to fingerprint in the first place.
|
||||
|
||||
- **Junk packets**: before the handshake, the client sends a configurable number (`junk_pc`) of random-size (`junk_ps`) filler datagrams. Each carries a 4-byte marker **derived from the access key** (the `junk_marker` above) rather than a fixed constant — a fixed marker would itself be a universal signature any observer could filter on across every OSTP deployment. The server derives the same per-key marker while trying candidate keys and drops matching junk silently, before it ever reaches the "unauthorized probe" logging path.
|
||||
- **TCP fragmentation** (UoT/TCP transport only): the first packet (the handshake) is split into small chunks (`frag_chunk` bytes) with short delays (`frag_sleep` ms) between writes, so DPI that inspects only the first TCP segment never sees a complete handshake to fingerprint.
|
||||
|
||||
Both are configurable per-profile; neither is sent over plain UDP transport, where a standalone junk datagram would look exactly like a random one-off probe to the server.
|
||||
|
|
@ -1,55 +1,60 @@
|
|||
# Маскирование энтропии сигналов OSTP
|
||||
# Обфускация трафика OSTP
|
||||
|
||||
## Философия структуры канала
|
||||
## Философия
|
||||
|
||||
Традиционные сетевые протоколы промышленного сбора данных могут обладать фиксированными заголовками, что при анализе статистического распределения байт ведет к предвзятости выборок и искажению телеметрического профиля. Задача механизмов энтропийного маскирования OSTP — достижение **равномерного вероятностного распределения значений байт**, начиная с самого первого пакета. Это делает сигналы шины данных абсолютно однородными и устойчивыми к корреляционному анализу и структурному мониторингу сетевых контроллеров.
|
||||
Классические туннельные протоколы (TLS, OpenVPN, WireGuard) имеют узнаваемые сигнатуры в хэндшейке или статичные заголовки пакетов. Механизм обфускации OSTP спроектирован так, чтобы **начиная с первого байта** трафик был максимально похож на случайный шум — и для DPI-систем был неотличим от него.
|
||||
|
||||
---
|
||||
|
||||
## Производная сигнатурная матрица (Keystream Initialization Vector)
|
||||
## Деривация секретов
|
||||
|
||||
Для стабилизации битового распределения используется 8-байтовый вектор, вычисляемый на базе глобального идентификатора регистрации узла (`access_key`):
|
||||
Все секреты протокола — ключ обфускации, PSK Noise-хэндшейка, диапазон паддинга хэндшейка и маркер junk-пакетов (см. ниже) — выводятся из общего `access_key` одним проходом HKDF-SHA256, с разделением по доменам через последний байт `info`:
|
||||
|
||||
$$\text{Key} = \text{SHA-256}(\text{access\_key})[0..8]$$
|
||||
```
|
||||
PRK = HKDF-Extract(salt = SHA-256(access_key)[0..16], IKM = access_key || PROTOCOL_VERSION)
|
||||
obfuscation_key = HKDF-Expand(PRK, info = SHA-256(access_key)[16..] || 0x01, 8 байт)
|
||||
psk = HKDF-Expand(PRK, info = SHA-256(access_key)[16..] || 0x02, 32 байта)
|
||||
handshake_pad = HKDF-Expand(PRK, info = SHA-256(access_key)[16..] || 0x03, 2 байта)
|
||||
junk_marker = HKDF-Expand(PRK, info = SHA-256(access_key)[16..] || 0x04, 4 байта)
|
||||
```
|
||||
|
||||
Данная последовательность фиксируется на передающем и принимающем узлах и не передается через внешние сетевые шлюзы.
|
||||
Версия протокола подмешивается в IKM, а не передаётся открытым байтом на проводе: пиры с разной версией протокола выведут разный `obfuscation_key` и просто не смогут деобфусцировать пакеты друг друга — жёсткий version gate без единого узнаваемого маркера на проводе. Ни один секрет никогда не передаётся — обе стороны независимо выводят одинаковые значения из общего access_key.
|
||||
|
||||
---
|
||||
|
||||
## Алгоритм динамического маскирования пакетов (In-place Masking)
|
||||
## Алгоритм динамического маскирования
|
||||
|
||||
Пакетные структуры OSTP проходят низкоуровневую предобработку непосредственно перед выдачей в канальный уровень (Layer 3) и при получении. В зависимости от фазы жизненного цикла сессии связи выделяют две модели:
|
||||
Датаграммы OSTP маскируются "на месте" прямо перед отправкой и сразу после получения. Сама маска **выводится из шифротекста самого пакета**, а не из статичного потока ключа или счётчика — поэтому она меняется от пакета к пакету автоматически:
|
||||
|
||||
### 1. Этап начального согласования среды (`is_handshake = true`)
|
||||
В период инициализации канала передачи пакет структурирован как 4-байтовое поле логического адреса порта `session_id` и криптографический блок согласования среды. Для подавления статических компонент ID порта применяется процедура обратимого битового сложения:
|
||||
```
|
||||
mask = HMAC-SHA256(key = obfuscation_key, message = ciphertext[0..min(32, len)])
|
||||
```
|
||||
|
||||
* **Обработка**: Первые 4 байта вектора пакета проходят побитовую операцию XOR с первыми 4 байтами сигнатурной матрицы:
|
||||
$$\text{raw}[i] = \text{raw}[i] \oplus \text{Key}[i \pmod 8], \quad i \in [0..3]$$
|
||||
* **Восстановление**: Обратное наложение сигнатурной матрицы возвращает корректное значение логического идентификатора.
|
||||
### 1. Фаза хэндшейка (`is_handshake = true`)
|
||||
Пакет на проводе — `[4 байта session_id][2 байта noise_len][Noise-полезная нагрузка]`. Маска считается по Noise-полезной нагрузке (`raw[6..]`), и её первые 6 байт накладываются XOR'ом на `session_id || noise_len`.
|
||||
|
||||
### 2. Этап высокоскоростного переноса данных (`is_handshake = false`)
|
||||
После перевода сессии в состояние активности кадр передачи принимает следующий вид:
|
||||
`[4 байта session_id]` + `[8 байт nonce]` + `[Полезная нагрузка блока]`
|
||||
### 2. Фаза передачи данных (`is_handshake = false`)
|
||||
Пакет на проводе — `[4 байта session_id][8 байт nonce][AEAD-шифротекст]`. Маска считается по шифротексту, и её первые 12 байт накладываются XOR'ом на `session_id || nonce`.
|
||||
|
||||
Для максимизации дифференциальной энтропии применяется двухступенчатое динамическое взвешивание:
|
||||
|
||||
1. **Коррекция счетчика цикла (Nonce Correction)**: 8-байтовое значение инкрементного счетчика пакета подвергается побитовому сложению с вектором матрицы:
|
||||
$$\text{nonce\_bytes}[i] = \text{nonce\_bytes}[i] \oplus \text{Key}[i], \quad i \in [0..7]$$
|
||||
2. **Маскирование ID сессии**: 4-байтовое поле логического адреса маскируется с помощью переменной высокочастотной энтропии — младших 32 бит **исходного** показателя системного счетчика пакетов:
|
||||
$$\text{session\_id\_bytes}[i] = \text{session\_id\_bytes}[i] \oplus \text{real\_nonce\_low32\_bytes}[i], \quad i \in [0..3]$$
|
||||
|
||||
#### Статистическая устойчивость:
|
||||
Благодаря инкрементации счетчика на каждом цикле отправки, маскирующий поток (keystream) для поля `session_id` постоянно видоизменяется. Это полностью нивелирует фиксированные битовые паттерны во всем спектре UDP-датаграмм и исключает появление повторяющихся префиксов.
|
||||
#### Эффект схемы
|
||||
Поскольку маска зависит одновременно от общего секрета и от содержимого шифротекста конкретного пакета, никакие два пакета — даже два подряд идущих в одной сессии — не используют одинаковый ключевой поток, и для этого не нужна явная схема на основе счётчика. Это полностью убирает корреляции между заголовками пакетов и повторяющиеся байтовые паттерны, делая статистический фингерпринтинг бесполезным.
|
||||
|
||||
---
|
||||
|
||||
## Выравнивание блоков по границам регистров (Adaptive Alignment)
|
||||
## Статистический паддинг
|
||||
|
||||
Дополнительно к маскировке заголовков, протокол OSTP исключает возможность анализа поведения системы на основе длин пакетов данных. Модуль адаптивного заполнения (`AdaptivePadder`) рассчитывает оптимальный размер буфера выравнивания (`padding`), интегрируемый в структуру пакета до момента активации шифрующего каскада:
|
||||
Помимо маскирования заголовков, OSTP защищается от анализа длин пакетов (Traffic Length Analysis). `AdaptivePadder` вычисляет случайный размер мусорных байт, добавляемых к полезной нагрузке ещё до шифрования:
|
||||
|
||||
- **Стратегия заполнения буферов**: Механизм анализирует текущую длину выборки телеметрии и производит масштабирование до типичных кратных длин промышленных сетей передачи данных и буферов потоковых агрегаторов.
|
||||
- **Изоляция выравнивания**: Данные заполнения помещаются внутрь защищенной области кадра. Внешние анализаторы топологии сети не способны определить внутренние границы между телеметрической нагрузкой и служебными полями выравнивания, видя только монолитный блок данных.
|
||||
- **Динамическое распределение**: длины паддинга подобраны так, чтобы напоминать профили длин обычного HTTPS-трафика или видеопотоков.
|
||||
- **Внутри шифротекста**: добавленный паддинг находится внутри области AEAD-шифрования — пассивный наблюдатель не может отличить паддинг от полезной нагрузки и не видит настоящую границу сообщения.
|
||||
|
||||
## XTLS-Reality (Имитация TLS 1.3)
|
||||
---
|
||||
|
||||
OSTP предоставляет собственную реализацию протокола XTLS-Reality без сторонних зависимостей. Протокол полностью имитирует рукопожатие TLS 1.3 (с реалистичным профилем ClientHello) для обхода продвинутых DPI фильтров. После успешного рукопожатия применяется ChaCha20Poly1305 для бесшовного шифрования и туннелирования внутренних HTTP/WSS соединений.
|
||||
## Junk-пакеты и TCP-фрагментация
|
||||
|
||||
OSTP не пытается притворяться известным протоколом (TLS, HTTP и т.п.) — фильтр по сигнатуре всегда можно обновить под конкретную имитацию. Вместо этого используется подход **в духе zapret**: никакого узнаваемого заголовка вообще, плюс активная манипуляция границами пакетов — фингерпринтить попросту нечего.
|
||||
|
||||
- **Junk-пакеты**: перед хэндшейком клиент отправляет настраиваемое количество (`junk_pc`) мусорных датаграмм случайного размера (`junk_ps`). Каждая несёт 4-байтовый маркер, **выведенный из access_key** (тот самый `junk_marker` выше), а не фиксированную константу — константный маркер сам по себе стал бы универсальной сигнатурой для любого наблюдателя сразу по всем серверам OSTP. Сервер, перебирая кандидатов-ключей, выводит тот же маркер и тихо отбрасывает junk, не доходя до логирования «unauthorized probe».
|
||||
- **TCP-фрагментация** (только для транспорта UoT/TCP): первый пакет (хэндшейк) режется на мелкие куски (`frag_chunk` байт) с небольшими задержками (`frag_sleep` мс) между записями — DPI, анализирующий только первый TCP-сегмент, никогда не видит цельный хэндшейк для фингерпринтинга.
|
||||
|
||||
Обе фичи настраиваются per-профиль; ни одна не применяется поверх обычного UDP-транспорта, где отдельная junk-датаграмма выглядела бы для сервера точь-в-точь как случайный одиночный проб.
|
||||
Loading…
Reference in New Issue