Skip to main content

typhoon/tailer/
structure.rs

1#[cfg(test)]
2#[path = "../../tests/tailer/structure.rs"]
3mod tests;
4
5use std::fmt::{Debug, Formatter, Result as FmtResult};
6use std::marker::PhantomData;
7
8use crate::bytes::{ByteBuffer, ByteBufferMut, DynamicByteBuffer, StaticByteBuffer};
9use crate::settings::consts::{CD_OFFSET, FG_OFFSET, ID_OFFSET, PL_OFFSET, PN_OFFSET, TAILER_LENGTH, TM_OFFSET};
10use crate::tailer::flags::{PacketFlags, ReturnCode};
11use crate::utils::unix_timestamp_ms;
12
13const TM_LENGTH: usize = 4;
14const PN_LENGTH: usize = 8;
15const PL_LENGTH: usize = 2;
16
17pub trait IdentityType: Send + Sync {
18    fn from_bytes(bytes: &[u8]) -> Self;
19
20    fn to_bytes(&self) -> &[u8];
21
22    fn length() -> usize;
23}
24
25/// Server-side connection handler: generates identities, produces server initial data, and checks client version.
26pub trait ServerConnectionHandler<T: IdentityType>: Send + Sync {
27    /// Derive a client session identity from the client's decrypted initial data bytes.
28    fn generate(&self, initial_data: &[u8]) -> T;
29
30    /// Produce initial data to include in the server handshake response for the given identity.
31    fn initial_data(&self, identity: &T) -> StaticByteBuffer;
32
33    /// Check whether the client version (from the handshake tailer ID field) is compatible.
34    /// Returns `true` if the handshake should proceed, `false` if it should be rejected.
35    /// Implementations are responsible for any logging before returning.
36    fn verify_version(&self, version_bytes: &[u8]) -> bool;
37}
38
39/// Client-side connection handler: produces client initial data and the version bytes for the handshake.
40pub trait ClientConnectionHandler: Send + Sync {
41    /// Produce initial data to include in the client handshake.
42    fn initial_data(&self) -> StaticByteBuffer;
43
44    /// Produce the version bytes to place in the handshake tailer ID field, clamped to `length` bytes.
45    fn version(&self, length: usize) -> StaticByteBuffer;
46}
47
48/// Tailer view (16 + TYPHOON_ID_LENGTH bytes total).
49/// Zero-copy view into a `DynamicByteBuffer` containing tailer metadata.
50/// All field access reads directly from the underlying buffer.
51///
52/// Layout:
53/// - FG (flags): 1 byte - packet type flags
54/// - CD (code): 1 byte - client type or return code
55/// - TM (time): 4 bytes - next_in delay in milliseconds
56/// - PN (packet number): 8 bytes - timestamp (4) + incremental (4)
57/// - PL (payload length): 2 bytes - length of encrypted payload
58/// - ID (identity): TYPHOON_ID_LENGTH bytes - client UUID
59pub struct Tailer<T: IdentityType> {
60    buffer: DynamicByteBuffer,
61    _phantom: PhantomData<T>,
62}
63
64impl<T: IdentityType> Tailer<T> {
65    /// Wrap an existing buffer as a tailer view. No data is copied.
66    /// The buffer must contain at least `Self::len()` bytes.
67    pub fn new(buffer: DynamicByteBuffer) -> Self {
68        let buffer = buffer.ensure_size(Self::len());
69        Self {
70            buffer,
71            _phantom: PhantomData,
72        }
73    }
74
75    /// Construct a tailer view from a received buffer and validate it against the
76    /// accompanying body length. Unlike [`Tailer::new`], this constructor never
77    /// expands the buffer via the pool — receive paths must supply a slice whose
78    /// length is already at least `Self::len()`.
79    pub fn validated(buffer: DynamicByteBuffer, body_len: usize) -> Option<Self> {
80        if buffer.len() < Self::len() {
81            return None;
82        }
83        let view = Self {
84            buffer,
85            _phantom: PhantomData,
86        };
87        let flags = view.flags();
88        if flags.is_empty() {
89            return None;
90        }
91        if flags.bits().count_ones() > 1 && !flags.is_shadowride() {
92            return None;
93        }
94        if (view.payload_length() as usize) > body_len {
95            return None;
96        }
97        Some(view)
98    }
99
100    /// Write a data packet tailer into the buffer.
101    pub fn data(buffer: DynamicByteBuffer, identity: &T, payload_length: u16, packet_number: u64) -> Self {
102        let view = Self::new(buffer);
103        view.set_flags(PacketFlags::DATA);
104        view.set_code(0);
105        view.set_time(0);
106        view.set_packet_number_raw(packet_number);
107        view.set_payload_length(payload_length);
108        view.set_identity(identity);
109        view
110    }
111
112    /// Write a health check packet tailer into the buffer.
113    pub fn health_check(buffer: DynamicByteBuffer, identity: &T, next_in: u32, packet_number: u64) -> Self {
114        let view = Self::new(buffer);
115        view.set_flags(PacketFlags::HEALTH_CHECK);
116        view.set_code(0);
117        view.set_time(next_in);
118        view.set_packet_number_raw(packet_number);
119        view.set_payload_length(0);
120        view.set_identity(identity);
121        view
122    }
123
124    /// Write a shadowride packet tailer (data + health check) into the buffer.
125    pub fn shadowride(buffer: DynamicByteBuffer, identity: &T, payload_length: u16, next_in: u32, packet_number: u64) -> Self {
126        let view = Self::new(buffer);
127        view.set_flags(PacketFlags::DATA | PacketFlags::HEALTH_CHECK);
128        view.set_code(0);
129        view.set_time(next_in);
130        view.set_packet_number_raw(packet_number);
131        view.set_payload_length(payload_length);
132        view.set_identity(identity);
133        view
134    }
135
136    /// Write a handshake packet tailer into the buffer.
137    /// `body_len` is the length of the handshake body (excluding tailer), allowing receivers
138    /// to strip any fake header/body prefix before parsing the handshake data.
139    pub fn handshake(buffer: DynamicByteBuffer, identity: &T, code: u8, next_in: u32, packet_number: u64, body_len: u16) -> Self {
140        let view = Self::new(buffer);
141        view.set_flags(PacketFlags::HANDSHAKE);
142        view.set_code(code);
143        view.set_time(next_in);
144        view.set_packet_number_raw(packet_number);
145        view.set_payload_length(body_len);
146        view.set_identity(identity);
147        view
148    }
149
150    /// Write a decoy packet tailer into the buffer.
151    pub fn decoy(buffer: DynamicByteBuffer, identity: &T, packet_number: u64) -> Self {
152        let view = Self::new(buffer);
153        view.set_flags(PacketFlags::DECOY);
154        view.set_code(0);
155        view.set_time(0);
156        view.set_packet_number_raw(packet_number);
157        view.set_payload_length(0);
158        view.set_identity(identity);
159        view
160    }
161
162    /// Write a debug probe tailer into the buffer.
163    ///
164    /// Field semantics in debug mode:
165    /// - **FG**: `DATA` flag (same as data packets so probes blend in).
166    /// - **CD**: `ref_num` — rolling reference number (0–255) uniquely identifying this probe.
167    /// - **TM**: `send_time_ms` — lower 32 bits of the Unix send timestamp in milliseconds.
168    /// - **PN**: `sequence << 32 | phase` — global sequence number and debug phase identifier.
169    /// - **PL**: `payload_len` — length of the probe payload.
170    pub fn debug_probe(buffer: DynamicByteBuffer, identity: &T, ref_num: u8, send_time_ms: u32, sequence: u32, phase: u32, payload_len: u16) -> Self {
171        let view = Self::new(buffer);
172        view.set_flags(PacketFlags::DATA);
173        view.set_code(ref_num);
174        view.set_time(send_time_ms);
175        view.set_packet_number_raw(((sequence as u64) << 32) | (phase as u64));
176        view.set_payload_length(payload_len);
177        view.set_identity(identity);
178        view
179    }
180
181    /// Write a termination packet tailer into the buffer.
182    pub fn termination(buffer: DynamicByteBuffer, identity: &T, code: ReturnCode, packet_number: u64) -> Self {
183        let view = Self::new(buffer);
184        view.set_flags(PacketFlags::TERMINATION);
185        view.set_code(code.into());
186        view.set_time(0);
187        view.set_packet_number_raw(packet_number);
188        view.set_payload_length(0);
189        view.set_identity(identity);
190        view
191    }
192
193    // --- Getters ---
194
195    #[inline]
196    pub fn flags(&self) -> PacketFlags {
197        PacketFlags::from_bits_truncate(*self.buffer.get(FG_OFFSET))
198    }
199
200    #[inline]
201    pub fn code(&self) -> u8 {
202        *self.buffer.get(CD_OFFSET)
203    }
204
205    #[inline]
206    pub fn time(&self) -> u32 {
207        u32::from_be_bytes(self.buffer.slice_both(TM_OFFSET, TM_OFFSET + TM_LENGTH).try_into().unwrap())
208    }
209
210    #[inline]
211    pub fn packet_number(&self) -> u64 {
212        u64::from_be_bytes(self.buffer.slice_both(PN_OFFSET, PN_OFFSET + PN_LENGTH).try_into().unwrap())
213    }
214
215    #[inline]
216    pub fn payload_length(&self) -> u16 {
217        u16::from_be_bytes(self.buffer.slice_both(PL_OFFSET, PL_OFFSET + PL_LENGTH).try_into().unwrap())
218    }
219
220    #[inline]
221    pub fn identity(&self) -> T {
222        T::from_bytes(self.buffer.slice_both(ID_OFFSET, ID_OFFSET + T::length()))
223    }
224
225    /// Extract timestamp from packet number (upper 32 bits).
226    #[inline]
227    pub fn timestamp(&self) -> u32 {
228        (self.packet_number() >> 32) as u32
229    }
230
231    /// Extract incremental number from packet number (lower 32 bits).
232    #[inline]
233    pub fn incremental(&self) -> u32 {
234        self.packet_number() as u32
235    }
236
237    /// Get return code from code field.
238    #[inline]
239    pub fn return_code(&self) -> ReturnCode {
240        ReturnCode::from(self.code())
241    }
242
243    // --- Debug accessors (reinterpret fields per debug-mode semantics) ---
244
245    /// Debug: rolling reference number from the CD field (0–255).
246    #[inline]
247    pub fn debug_ref_num(&self) -> u8 {
248        self.code()
249    }
250
251    /// Debug: send timestamp in milliseconds from the TM field (lower 32 bits of Unix time).
252    #[inline]
253    pub fn debug_send_time(&self) -> u32 {
254        self.time()
255    }
256
257    /// Debug: global probe sequence number from the upper 32 bits of the PN field.
258    #[inline]
259    pub fn debug_sequence(&self) -> u32 {
260        (self.packet_number() >> 32) as u32
261    }
262
263    /// Debug: phase identifier from the lower 32 bits of the PN field.
264    /// `0` = reachability, `1` = return time, `2` = throughput.
265    #[inline]
266    pub fn debug_phase(&self) -> u32 {
267        self.packet_number() as u32
268    }
269
270    /// Get the underlying buffer.
271    #[inline]
272    pub fn buffer(&self) -> &DynamicByteBuffer {
273        &self.buffer
274    }
275
276    /// Consume the tailer view and return the underlying buffer.
277    #[inline]
278    pub fn into_buffer(self) -> DynamicByteBuffer {
279        self.buffer
280    }
281
282    // --- Setters (write through to the buffer) ---
283
284    #[inline]
285    pub fn set_flags(&self, flags: PacketFlags) {
286        self.buffer.set(FG_OFFSET, flags.bits());
287    }
288
289    #[inline]
290    pub fn set_code(&self, code: u8) {
291        self.buffer.set(CD_OFFSET, code);
292    }
293
294    #[inline]
295    pub fn set_time(&self, time: u32) {
296        self.buffer.slice_both_mut(TM_OFFSET, TM_OFFSET + TM_LENGTH).copy_from_slice(&time.to_be_bytes());
297    }
298
299    #[inline]
300    pub fn set_packet_number_raw(&self, pn: u64) {
301        self.buffer.slice_both_mut(PN_OFFSET, PN_OFFSET + PN_LENGTH).copy_from_slice(&pn.to_be_bytes());
302    }
303
304    /// Set packet number from timestamp and incremental counter.
305    #[inline]
306    pub fn set_packet_number(&self, timestamp: u32, incremental: u32) {
307        let pn = ((timestamp as u64) << 32) | (incremental as u64);
308        self.set_packet_number_raw(pn);
309    }
310
311    /// Set packet number using current timestamp and given incremental.
312    pub fn set_packet_number_now(&self, incremental: u32) {
313        let timestamp = (unix_timestamp_ms() / 1000) as u32;
314        self.set_packet_number(timestamp, incremental);
315    }
316
317    #[inline]
318    pub fn set_payload_length(&self, len: u16) {
319        self.buffer.slice_both_mut(PL_OFFSET, PL_OFFSET + PL_LENGTH).copy_from_slice(&len.to_be_bytes());
320    }
321
322    #[inline]
323    pub fn set_identity(&self, identity: &T) {
324        self.buffer.slice_both_mut(ID_OFFSET, ID_OFFSET + T::length()).copy_from_slice(identity.to_bytes());
325    }
326
327    // --- Static helpers that read from a raw buffer ---
328
329    #[inline]
330    pub fn get_payload_length(buffer: &DynamicByteBuffer) -> u16 {
331        let correct_buffer = buffer.ensure_size(TAILER_LENGTH);
332        u16::from_be_bytes(correct_buffer.slice_both(PL_OFFSET, PL_OFFSET + PL_LENGTH).try_into().unwrap())
333    }
334
335    /// Extract identity from a raw tailer buffer.
336    #[inline]
337    pub fn get_identity(buffer: &DynamicByteBuffer) -> T {
338        let correct_buffer = buffer.ensure_size(Self::len());
339        T::from_bytes(correct_buffer.slice_both(ID_OFFSET, ID_OFFSET + T::length()))
340    }
341
342    #[inline]
343    pub fn len() -> usize {
344        T::length() + TAILER_LENGTH
345    }
346
347    /// Wire length of the obfuscated client→server tailer (plaintext tailer + c2s obfuscation overhead).
348    #[inline]
349    pub(crate) fn encrypted_len_c2s() -> usize {
350        Self::len() + crate::crypto::TAILER_C2S_OVERHEAD
351    }
352
353    /// Wire length of the obfuscated server→client tailer (plaintext tailer + s2c obfuscation overhead).
354    #[inline]
355    pub(crate) fn encrypted_len_s2c() -> usize {
356        Self::len() + crate::crypto::TAILER_S2C_OVERHEAD
357    }
358}
359
360impl<T: IdentityType> Clone for Tailer<T> {
361    fn clone(&self) -> Self {
362        Self {
363            buffer: self.buffer.clone(),
364            _phantom: PhantomData,
365        }
366    }
367}
368
369impl<T: IdentityType + PartialEq> PartialEq for Tailer<T> {
370    fn eq(&self, other: &Self) -> bool {
371        self.buffer.slice() == other.buffer.slice()
372    }
373}
374
375impl<T: IdentityType> Debug for Tailer<T> {
376    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
377        f.debug_struct("Tailer").field("flags", &self.flags()).field("code", &self.code()).field("time", &self.time()).field("packet_number", &self.packet_number()).field("payload_length", &self.payload_length()).finish()
378    }
379}