docs [AI]

This commit is contained in:
2026-06-30 18:51:09 +07:00
parent 18cad76e38
commit f7a76353ea
67 changed files with 2104 additions and 1417 deletions
+42
View File
@@ -0,0 +1,42 @@
# Блок `rawcast` — локальный протокол сокет ⇄ кадр
Промежуточный формат между «локальной» стороной клиента (реальные TCP/UDP сокеты
приложений) и протоколом туннеля [`nrxp`](../nrxp). Когда трафик приходит не из
TUN напрямую, а из локальных соединений, его описывают компактным `RawCastFrame`,
а `RawCastAdapter` переводит это в кадры NRXP и обратно.
> Детали — в rustdoc, модуль `rawcast`.
## Файлы
| Файл | Что внутри |
|--------------|------------------------------------------------------------------|
| `frame.rs` | `RawCastFrame` + enum'ы `LocalProtocol`/`RawCastEvent`, wire-формат. |
| `adapter.rs` | `RawCastAdapter`: трансляция RawCast ⇄ NRXP-`Frame`. |
## Формат кадра
```text
┌──────────┬───────┬───────────┬─────────┬──────────┬─────────────┬─────────┐
│ protocol │ event │ socket_id │ dst_ip │ dst_port │ payload_len │ payload │
│ 1 байт │ 1 б. │ 8 байт │ 4 байта │ 2 байта │ 2 байта │ N байт │
└──────────┴───────┴───────────┴─────────┴──────────┴─────────────┴─────────┘
└──────────────── LOCAL_HEADER_SIZE = 16 ────────────────┘
```
## Ментальная модель
```text
локальный сокет ─→ RawCastFrame ─to_nrxp──→ NRXP Frame ─→ туннель
туннель ─→ NRXP Frame ─from_nrxp─→ RawCastFrame ─→ локальный сокет
```
`socket_id` локальной стороны напрямую отображается в `stream_id` потока NRXP, так
что мультиплексирование «бесплатно» переносится между двумя протоколами. ICMP в
формате распознаётся, но ядром NRXP не проксируется.
## Связи
Потребитель — клиентская точка входа `ClientHandler::connect` ([`net`](../net)):
она гоняет `RawCastFrame` между локальными соединениями ([`client`](../../../../client))
и туннелем.
+14
View File
@@ -1,3 +1,10 @@
//! Трансляция между локальным протоколом RawCast и протоколом туннеля NRXP.
//!
//! [`RawCastAdapter`] — чистый «переводчик» без состояния. Соответствия:
//! `socket_id` ⇄ `stream_id`, `(protocol, event)` ⇄ [`FrameType`]. Для `Connect`
//! без явного payload адрес назначения упаковывается строкой `"ip:port"` — это
//! то, что ожидает серверная сторона при открытии потока.
use bytes::Bytes;
use std::net::Ipv4Addr;
@@ -6,9 +13,13 @@ use crate::{
rawcast::frame::{LocalProtocol, RawCastEvent, RawCastFrame},
};
/// Безсостоятельный конвертер RawCast ⇄ NRXP.
pub struct RawCastAdapter;
impl RawCastAdapter {
/// RawCast → NRXP. Маппит протокол+событие в [`FrameType`]; для `Connect`
/// без payload подставляет адрес цели строкой `"ip:port"`. ICMP отвергается —
/// ядро NRXP его не проксирует.
pub(crate) fn to_nrxp(raw: RawCastFrame) -> Result<Frame, String> {
let stream_id = raw.socket_id as u32;
@@ -40,6 +51,9 @@ impl RawCastAdapter {
Ok(Frame::new(stream_id, frame_type, payload))
}
/// NRXP → RawCast. Обратный перевод; `is_udp` задаёт протокол локального
/// сокета (в NRXP-кадре эта информация частично растворена в типе). Кадры
/// `Heartbeat` сюда попадать не должны — их обрабатывает muxer, не мост.
pub(crate) fn from_nrxp(
nrxp_frame: Frame,
dst_ip: Ipv4Addr,
+34
View File
@@ -1,34 +1,61 @@
//! Кадр локального протокола RawCast и его (де)сериализация.
//!
//! Wire-формат: 16-байтовый фиксированный заголовок + 2 байта длины payload +
//! сам payload:
//!
//! ```text
//! ┌──────────┬───────┬───────────┬─────────┬──────────┬─────────────┬─────────┐
//! │ protocol │ event │ socket_id │ dst_ip │ dst_port │ payload_len │ payload │
//! │ 1 байт │ 1 б. │ 8 байт │ 4 байта │ 2 байта │ 2 байта │ N байт │
//! └──────────┴───────┴───────────┴─────────┴──────────┴─────────────┴─────────┘
//! └──────────────── LOCAL_HEADER_SIZE = 16 ────────────────┘
//! ```
use bytes::{Buf, BufMut, Bytes, BytesMut};
use std::net::Ipv4Addr;
use crate::parser::Parser;
/// Транспортный протокол локального сокета.
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(u8)]
pub enum LocalProtocol {
Tcp = 0x01,
Udp = 0x02,
/// ICMP распознаётся в формате, но ядром NRXP не поддерживается (см. адаптер).
Icmp = 0x03,
}
/// Событие жизненного цикла локального сокета.
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(u8)]
pub enum RawCastEvent {
/// Новое соединение/сессия к цели.
Connect = 0x01,
/// Полезные данные.
Data = 0x02,
/// Закрытие соединения.
Close = 0x03,
}
/// Описание одного события локального сокета — единица обмена RawCast.
#[derive(Debug, Clone)]
pub struct RawCastFrame {
/// TCP/UDP/ICMP.
pub protocol: LocalProtocol,
/// Connect/Data/Close.
pub event: RawCastEvent,
/// Идентификатор локального сокета (→ `stream_id` в NRXP).
pub socket_id: u64,
/// Адрес назначения.
pub dst_ip: Ipv4Addr,
/// Порт назначения.
pub dst_port: u16,
/// Полезные данные (пусто для Connect/Close).
pub payload: Bytes,
}
/// Размер фиксированной части заголовка (без поля длины и payload) — 16 байт.
const LOCAL_HEADER_SIZE: usize = 16;
impl RawCastFrame {
@@ -50,18 +77,22 @@ impl RawCastFrame {
}
}
/// Кадр-событие открытия соединения (без payload).
pub fn connect(protocol: LocalProtocol, id: u64, ip: Ipv4Addr, port: u16) -> Self {
Self::new(protocol, RawCastEvent::Connect, id, ip, port, Bytes::new())
}
/// Кадр с данными соединения.
pub fn data(protocol: LocalProtocol, id: u64, ip: Ipv4Addr, port: u16, data: Bytes) -> Self {
Self::new(protocol, RawCastEvent::Data, id, ip, port, data)
}
/// Кадр-событие закрытия соединения (без payload).
pub fn close(protocol: LocalProtocol, id: u64, ip: Ipv4Addr, port: u16) -> Self {
Self::new(protocol, RawCastEvent::Close, id, ip, port, Bytes::new())
}
/// Сериализует кадр в байты по wire-формату из обзора модуля.
pub fn into_bytes(self) -> BytesMut {
let total_size = LOCAL_HEADER_SIZE + 2 + self.payload.len();
let mut buf = BytesMut::with_capacity(total_size);
@@ -78,6 +109,9 @@ impl RawCastFrame {
}
}
/// Разбор кадра RawCast: `can_parse` подглядывает поле длины payload по
/// смещению `LOCAL_HEADER_SIZE` и проверяет, что весь кадр на месте; `parse`
/// читает фиксированный заголовок, затем payload.
impl Parser for RawCastFrame {
type Error = String;
+25
View File
@@ -1,3 +1,28 @@
//! # Блок RawCast (`rawcast`) — локальный протокол сокет ⇄ кадр
//!
//! Промежуточный формат между «локальной» стороной клиента (реальные TCP/UDP
//! сокеты приложений) и протоколом туннеля [`nrxp`](crate::nrxp). Когда трафик
//! приходит не из TUN, а из локальных соединений, его описывают компактным
//! [`RawCastFrame`] — «что за сокет, какой протокол, куда, какое событие, данные» —
//! а [`RawCastAdapter`] переводит это в кадры NRXP и обратно.
//!
//! ## Состав блока
//!
//! | Файл | Ответственность |
//! |-------------|------------------------------------------------------------------|
//! | [`frame`] | [`RawCastFrame`] + enum'ы [`LocalProtocol`]/[`RawCastEvent`], wire-формат. |
//! | [`adapter`] | [`RawCastAdapter`]: трансляция RawCast ⇄ NRXP-[`Frame`](crate::nrxp).|
//!
//! ## Связь с остальным
//!
//! ```text
//! локальный сокет ──→ RawCastFrame ──RawCastAdapter::to_nrxp──→ NRXP Frame ──→ туннель
//! туннель ──→ NRXP Frame ──RawCastAdapter::from_nrxp──→ RawCastFrame ──→ локальный сокет
//! ```
//!
//! `socket_id` локальной стороны напрямую отображается в `stream_id` потока NRXP,
//! так что мультиплексирование «бесплатно» переносится между двумя протоколами.
mod adapter;
mod frame;