include/qrnsp_fallback.h
/*
* QR-NSP Volcanic Edition — TCP/HTTP2 Fallback
* Module 6: Graceful degradation when UDP/QUIC is blocked
*
* When authoritarian regimes block UDP entirely or throttle QUIC
* (deep-packet inspection on port 443/UDP), the system falls back
* to TCP-based HTTP/2. Steganographic channels shift to:
*
* 1. TCP Options fields (timestamps, SACK blocks)
* 2. HTTP/2 WINDOW_UPDATE / PRIORITY frame manipulation
* 3. Chaffing-and-Winnowing (Rivest 1998): interleave authentic
* and chaff packets; only the holder of the MAC key can winnow
*
* State machine:
* QUIC_OK → detect_throttle → QUIC_DEGRADED → probe_tcp → TCP_PROBE
* TCP_PROBE → handshake_ok → HTTP2_ACTIVE
* HTTP2_ACTIVE → quic_recovered → QUIC_OK (always prefer QUIC)
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#ifndef QRNSP_FALLBACK_H
#define QRNSP_FALLBACK_H
#include <stdint.h>
#include <stddef.h>
/* ─────────────────────────────────────────────
* Transport states
* ───────────────────────────────────────────── */
typedef enum {
TRANSPORT_QUIC_OK, /* Primary: QUIC/UDP operational */
TRANSPORT_QUIC_DEGRADED, /* QUIC loss > threshold */
TRANSPORT_TCP_PROBE, /* Testing TCP/HTTP2 path */
TRANSPORT_HTTP2_ACTIVE, /* Fallback: HTTP2/TCP operational */
TRANSPORT_HTTP2_DEGRADED, /* TCP also impaired */
TRANSPORT_BLOCKED, /* Both paths blocked */
} transport_state_t;
/* ─────────────────────────────────────────────
* TCP steganographic channel types
* ───────────────────────────────────────────── */
typedef enum {
TCP_STEGO_TIMESTAMP, /* Encode in TCP timestamp LSBs */
TCP_STEGO_WINDOW, /* Encode in window size LSBs */
TCP_STEGO_HTTP2_PAD, /* HTTP/2 DATA frame padding */
TCP_STEGO_HTTP2_PRIO, /* HTTP/2 PRIORITY weight manipulation */
TCP_STEGO_CHAFF, /* Chaffing-and-Winnowing */
} tcp_stego_mode_t;
/* ─────────────────────────────────────────────
* Quality metrics for transport monitoring
* ───────────────────────────────────────────── */
typedef struct {
/* QUIC health */
double quic_loss_rate; /* Packet loss ratio [0,1] */
double quic_rtt_ms; /* Smoothed RTT in milliseconds */
uint64_t quic_pkts_sent;
uint64_t quic_pkts_acked;
uint64_t quic_pkts_lost;
uint64_t quic_last_rx_ns; /* Last QUIC packet received */
/* TCP health */
double tcp_loss_rate;
double tcp_rtt_ms;
uint64_t tcp_pkts_sent;
uint64_t tcp_pkts_acked;
uint64_t tcp_last_rx_ns;
/* Thresholds */
double quic_loss_threshold; /* Trigger fallback at this loss rate */
double quic_rtt_threshold; /* RTT suggesting throttling (ms) */
uint64_t quic_silence_ns; /* Timeout: no QUIC rx → fallback */
} transport_metrics_t;
/* ─────────────────────────────────────────────
* Chaffing-and-Winnowing packet
*
* Rivest (1998): Authentication without encryption.
* Interleave real packets (valid MAC) with chaff packets
* (invalid MAC). Only the MAC key holder can tell them apart.
*
* Layout:
* [SEQ:4][DATA:N][MAC:16]
* Real: MAC = HMAC(key, seq || data) — valid
* Chaff: MAC = random 16 bytes — invalid
* ───────────────────────────────────────────── */
#define CHAFF_SEQ_BYTES 4
#define CHAFF_MAC_BYTES 16
#define CHAFF_OVERHEAD (CHAFF_SEQ_BYTES + CHAFF_MAC_BYTES)
#define CHAFF_MAX_DATA 1024
#define CHAFF_RATIO_DEFAULT 3 /* 3 chaff packets per real packet */
typedef struct {
uint32_t seq;
uint8_t data[CHAFF_MAX_DATA];
uint16_t data_len;
uint8_t mac[CHAFF_MAC_BYTES];
int is_real; /* For TX bookkeeping only */
} chaff_packet_t;
/* ─────────────────────────────────────────────
* Fallback session
* ───────────────────────────────────────────── */
typedef struct {
transport_state_t state;
tcp_stego_mode_t tcp_mode;
/* Shared secret (from hybrid KEM) */
uint8_t session_key[32];
/* Chaffing state */
uint32_t chaff_tx_seq;
uint32_t chaff_rx_seq;
int chaff_ratio; /* Chaff packets per real packet */
/* TCP timestamp steganography */
uint32_t ts_bit_index; /* Current bit position in payload */
uint8_t ts_payload[256]; /* Data being embedded in timestamps */
uint16_t ts_payload_len;
uint16_t ts_payload_cap;
/* HTTP/2 frame steganography */
uint32_t h2_stream_id; /* Current HTTP/2 stream */
uint8_t h2_payload[4096]; /* Data for HTTP/2 padding injection */
uint16_t h2_payload_len;
/* Metrics */
transport_metrics_t metrics;
/* Stats */
uint64_t fallback_count; /* Times we've fallen back */
uint64_t recovery_count; /* Times QUIC recovered */
uint64_t chaff_sent;
uint64_t chaff_real_sent;
uint64_t winnowed; /* Successfully winnowed packets */
} fallback_session_t;
/* ─────────────────────────────────────────────
* API
* ───────────────────────────────────────────── */
int fallback_init(fallback_session_t *sess, const uint8_t key[32]);
void fallback_destroy(fallback_session_t *sess);
/* Transport monitoring — call on every packet event */
void fallback_quic_tx(fallback_session_t *sess);
void fallback_quic_rx(fallback_session_t *sess, uint64_t timestamp_ns);
void fallback_quic_loss(fallback_session_t *sess);
void fallback_tcp_tx(fallback_session_t *sess);
void fallback_tcp_rx(fallback_session_t *sess, uint64_t timestamp_ns);
/* State machine tick — call periodically (e.g., every 100ms) */
transport_state_t fallback_tick(fallback_session_t *sess, uint64_t now_ns);
/* Chaffing-and-Winnowing */
int chaff_encode(fallback_session_t *sess,
const uint8_t *payload, size_t len,
chaff_packet_t *out_packets, int *out_count, int max_packets);
int chaff_winnow(fallback_session_t *sess,
const chaff_packet_t *packets, int count,
uint8_t *out, size_t out_cap, size_t *out_len);
/* TCP timestamp steganography */
uint32_t tcp_ts_encode_bits(fallback_session_t *sess,
uint32_t original_ts, int nbits);
int tcp_ts_decode_bits(fallback_session_t *sess,
uint32_t received_ts, int nbits);
/* HTTP/2 DATA frame padding injection */
int h2_pad_inject(fallback_session_t *sess,
uint8_t *frame, size_t frame_len, size_t frame_cap,
const uint8_t *payload, size_t pay_len);
int h2_pad_extract(fallback_session_t *sess,
const uint8_t *frame, size_t frame_len,
uint8_t *out, size_t out_cap, size_t *out_len);
#endif /* QRNSP_FALLBACK_H */