Skip to content

include/qrnsp_morph.h

/*
 * QR-NSP Volcanic Edition — Traffic Morphing
 * Module 7: Statistical fingerprint matching
 *
 * Deep Packet Inspection (DPI) increasingly uses statistical
 * analysis beyond simple protocol signatures. They profile:
 *   - Packet size distributions
 *   - Inter-arrival time distributions
 *   - Burst patterns
 *   - Flow duration / volume ratios
 *   - TLS fingerprints (JA3/JA4)
 *
 * Traffic morphing transforms QR-NSP's traffic to statistically
 * match a target cover protocol (Netflix streaming, Zoom calls,
 * WhatsApp video, YouTube). The adversary's DPI classifier sees
 * traffic that matches the expected statistical profile.
 *
 * Approach: Learn statistical profiles of real services offline,
 * then pad/delay/batch outgoing packets to match the target
 * distribution at runtime.
 *
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

#ifndef QRNSP_MORPH_H
#define QRNSP_MORPH_H

#include <stdint.h>
#include <stddef.h>

/* ─────────────────────────────────────────────
 * Cover protocol profiles
 * ───────────────────────────────────────────── */

typedef enum {
    MORPH_COVER_NETFLIX_4K,     /* Netflix 4K streaming (~25 Mbps)     */
    MORPH_COVER_YOUTUBE_1080,   /* YouTube 1080p (~8 Mbps)             */
    MORPH_COVER_ZOOM_VIDEO,     /* Zoom video call (~3.5 Mbps)         */
    MORPH_COVER_WHATSAPP_CALL,  /* WhatsApp voice call (~64 kbps)      */
    MORPH_COVER_WEB_BROWSE,     /* General HTTPS browsing              */
    MORPH_COVER_CUSTOM,         /* User-provided profile               */
    MORPH_COVER_COUNT
} morph_cover_t;

/* ─────────────────────────────────────────────
 * Statistical profile: describes a traffic pattern
 *
 * Each profile contains histogram bins for packet sizes
 * and inter-arrival times. The morpher samples from these
 * distributions when shaping outgoing traffic.
 * ───────────────────────────────────────────── */

#define MORPH_SIZE_BINS     32    /* Packet size histogram bins         */
#define MORPH_IPAT_BINS     32    /* Inter-arrival time histogram bins  */
#define MORPH_BURST_BINS    16    /* Burst length histogram bins        */

typedef struct {
    morph_cover_t type;

    /* Packet size distribution */
    uint16_t size_bin_edge[MORPH_SIZE_BINS];  /* Bin upper edges (bytes) */
    double   size_bin_prob[MORPH_SIZE_BINS];  /* Probability per bin     */

    /* Inter-arrival time distribution */
    uint32_t ipat_bin_edge[MORPH_IPAT_BINS];  /* Bin upper edges (μs)   */
    double   ipat_bin_prob[MORPH_IPAT_BINS];  /* Probability per bin    */

    /* Burst profile */
    uint16_t burst_bin_edge[MORPH_BURST_BINS]; /* Packets per burst     */
    double   burst_bin_prob[MORPH_BURST_BINS];

    /* Aggregate stats */
    double   avg_bitrate_kbps;    /* Target average bitrate             */
    double   peak_bitrate_kbps;   /* Peak bitrate                       */
    double   avg_packet_size;     /* Mean packet size                   */
    double   avg_ipat_us;         /* Mean inter-arrival time            */

    /* TLS/QUIC fingerprint mimicry */
    uint16_t initial_pkt_sizes[8]; /* First 8 packet sizes to mimic     */
    int      initial_pkt_count;
} morph_profile_t;

/* ─────────────────────────────────────────────
 * Morpher session
 * ───────────────────────────────────────────── */

typedef struct {
    morph_profile_t profile;      /* Active cover profile               */
    int             active;       /* Morphing enabled                   */

    /* Shaping state */
    uint64_t last_tx_ns;          /* Last packet sent timestamp         */
    uint64_t session_start_ns;    /* Session start                      */
    uint64_t bytes_sent;          /* Total bytes sent this session      */
    uint64_t pkts_sent;           /* Total packets sent                 */

    /* Current burst tracking */
    uint32_t burst_remaining;     /* Packets left in current burst      */
    uint64_t burst_gap_ns;        /* Inter-burst gap                    */

    /* Padding buffer */
    uint8_t  pad_buf[2048];       /* For packet size padding            */

    /* PRNG for sampling from distributions */
    uint64_t rng_state[2];

    /* KS statistic monitoring (detect when we're drifting) */
    double   ks_size;             /* Running KS stat for size dist      */
    double   ks_ipat;             /* Running KS stat for IPAT dist      */
    uint64_t sample_count;
} morph_session_t;

/* ─────────────────────────────────────────────
 * API
 * ───────────────────────────────────────────── */

/* Initialize with a built-in cover profile */
int morph_init(morph_session_t *sess, morph_cover_t cover,
               const uint8_t seed[32]);

/* Initialize with a custom profile (e.g., captured from real traffic) */
int morph_init_custom(morph_session_t *sess,
                      const morph_profile_t *profile,
                      const uint8_t seed[32]);

void morph_destroy(morph_session_t *sess);

/*
 * Shape outgoing packet: given a payload, determine:
 *   - How much padding to add (target size from profile)
 *   - How long to delay before sending (target IPAT from profile)
 *   - Whether to split into multiple packets or batch
 *
 * out_size:  recommended padded packet size
 * out_delay: recommended delay in nanoseconds before sending
 *
 * Returns 0 on success.
 */
int morph_shape(morph_session_t *sess,
                size_t payload_size,
                size_t *out_size,
                uint64_t *out_delay_ns);

/*
 * Pad a packet buffer to the target size.
 * Fills extra space with random-looking padding.
 *
 * buf:      packet buffer (must have capacity >= target_size)
 * data_len: actual data in buffer
 * target:   target padded size (from morph_shape)
 */
int morph_pad(morph_session_t *sess,
              uint8_t *buf, size_t data_len, size_t target);

/*
 * Record that a packet was sent (updates internal statistics).
 */
void morph_record_tx(morph_session_t *sess,
                     size_t pkt_size, uint64_t timestamp_ns);

/*
 * Get current quality of morphing (KS distance to target profile).
 * Lower is better. < 0.1 is good. > 0.3 means DPI might detect.
 */
double morph_quality(const morph_session_t *sess);

/*
 * Generate cover (chaff) traffic when no real data to send.
 * Returns recommended dummy packet size and delay.
 * Essential: real traffic is bursty, but cover profiles may
 * require continuous flow (e.g., video streaming).
 */
int morph_generate_cover(morph_session_t *sess,
                         size_t *out_size, uint64_t *out_delay_ns);

/* Get a read-only pointer to built-in profiles */
const morph_profile_t *morph_get_builtin_profile(morph_cover_t cover);

#endif /* QRNSP_MORPH_H */