Skip to main content

Overview

The Config system provides a flexible, rule-based configuration for the TurkeyDPI engine. It supports JSON and TOML formats, validation, and hot-reloading.

Config

Structure

pub struct Config {
    pub global: GlobalConfig,
    pub rules: Vec<Rule>,
    pub limits: Limits,
    pub transforms: TransformParams,
}

Fields

global
GlobalConfig
required
Global engine settings and feature flags
rules
Vec<Rule>
required
Packet matching rules with transform actions
limits
Limits
required
Resource limits and safety constraints
transforms
TransformParams
required
Parameters for all transform types

Methods

load_from_file

pub fn load_from_file(path: impl AsRef<Path>) -> Result<Self>
Loads configuration from a JSON or TOML file (detected by extension).
path
impl AsRef<Path>
required
Path to configuration file (.json or .toml)
Config
Result<Config>
Loaded and validated configuration
Example:
use turkey_dpi_engine::Config;

let config = Config::load_from_file("config.toml")?;

from_json

pub fn from_json(json: &str) -> Result<Self>
Parses configuration from a JSON string. Example:
let json = r#"
{
  "global": {
    "enabled": true,
    "enable_fragmentation": true
  },
  "rules": [
    {
      "name": "https-bypass",
      "match_criteria": {
        "dst_ports": [443],
        "protocols": ["tcp"]
      },
      "transforms": ["fragment", "padding"]
    }
  ]
}
"#;

let config = Config::from_json(json)?;

from_toml

pub fn from_toml(toml_str: &str) -> Result<Self>
Parses configuration from a TOML string. Example:
let toml = r#"
[global]
enabled = true
enable_fragmentation = true

[[rules]]
name = "https-bypass"
transforms = ["fragment", "padding"]

[rules.match_criteria]
dst_ports = [443]
protocols = ["tcp"]
"#;

let config = Config::from_toml(toml)?;

validate

pub fn validate(&self) -> Result<()>
Validates the configuration, checking limits, parameters, and rule consistency. Example:
let mut config = Config::default();
config.limits.max_flows = 0; // Invalid

assert!(config.validate().is_err());

merge

pub fn merge(&mut self, other: Config)
Merges another configuration into this one, replacing rules and settings. Example:
let mut base_config = Config::default();
let overlay = Config::load_from_file("overlay.toml")?;

base_config.merge(overlay);

GlobalConfig

Structure

pub struct GlobalConfig {
    pub enabled: bool,
    pub enable_fragmentation: bool,
    pub enable_jitter: bool,
    pub enable_padding: bool,
    pub enable_header_normalization: bool,
    pub log_level: String,
    pub json_logging: bool,
}

Fields

enabled
bool
default:"true"
Master switch for the entire engine
enable_fragmentation
bool
default:"true"
Enable packet fragmentation transforms
enable_jitter
bool
default:"false"
Enable timing jitter transforms
enable_padding
bool
default:"true"
Enable packet padding transforms
enable_header_normalization
bool
default:"true"
Enable header normalization transforms
log_level
String
default:"info"
Logging level: trace, debug, info, warn, error
json_logging
bool
default:"false"
Output logs in JSON format

Rule

Structure

pub struct Rule {
    pub name: String,
    pub enabled: bool,
    pub priority: i32,
    pub match_criteria: MatchCriteria,
    pub transforms: Vec<TransformType>,
    pub overrides: HashMap<String, serde_json::Value>,
}

Fields

name
String
required
Unique name for the rule
enabled
bool
default:"true"
Whether this rule is active
priority
i32
default:"0"
Rule priority (higher = evaluated first)
match_criteria
MatchCriteria
required
Conditions for matching packets
transforms
Vec<TransformType>
required
List of transforms to apply when matched
overrides
HashMap<String, Value>
default:"{}"
Rule-specific parameter overrides
Example:
use turkey_dpi_engine::config::*;
use std::collections::HashMap;

let rule = Rule {
    name: "discord-bypass".to_string(),
    enabled: true,
    priority: 100,
    match_criteria: MatchCriteria {
        dst_ports: Some(vec![443]),
        protocols: Some(vec![Protocol::Tcp]),
        domains: Some(vec!["discord.com".to_string()]),
        ..Default::default()
    },
    transforms: vec![
        TransformType::Fragment,
        TransformType::Padding,
        TransformType::Jitter,
    ],
    overrides: HashMap::new(),
};

rule.validate()?;

MatchCriteria

Structure

pub struct MatchCriteria {
    pub dst_ip: Option<Vec<String>>,
    pub src_ip: Option<Vec<String>>,
    pub dst_ports: Option<Vec<u16>>,
    pub src_ports: Option<Vec<u16>>,
    pub protocols: Option<Vec<Protocol>>,
    pub domains: Option<Vec<String>>,
    pub process: Option<String>,
}

Fields

dst_ip
Option<Vec<String>>
Destination IP addresses or CIDR ranges (e.g., ["8.8.8.8", "1.1.1.0/24"])
src_ip
Option<Vec<String>>
Source IP addresses or CIDR ranges
dst_ports
Option<Vec<u16>>
Destination ports (e.g., [443, 8443])
src_ports
Option<Vec<u16>>
Source ports
protocols
Option<Vec<Protocol>>
Protocols: tcp, udp, or icmp
domains
Option<Vec<String>>
Domain names to match (requires SNI/Host inspection)
process
Option<String>
Process name (platform-dependent)
All criteria are AND-ed together. Empty/None means “match all” for that field. Example:
// Match HTTPS traffic to Discord
let criteria = MatchCriteria {
    dst_ports: Some(vec![443]),
    protocols: Some(vec![Protocol::Tcp]),
    domains: Some(vec!["discord.com".to_string()]),
    ..Default::default()
};

// Match all DNS traffic
let dns_criteria = MatchCriteria {
    dst_ports: Some(vec![53]),
    protocols: Some(vec![Protocol::Udp]),
    ..Default::default()
};

// Catch-all rule
let catch_all = MatchCriteria::default();
assert!(catch_all.is_catch_all());

TransformType

Enum

pub enum TransformType {
    Fragment,
    Resegment,
    Padding,
    Jitter,
    HeaderNormalization,
    Decoy,
    Reorder,
}
Fragment
variant
Split packets into smaller fragments
Resegment
variant
Re-segment TCP streams
Padding
variant
Add random padding to packets
Jitter
variant
Add timing delays between packets
HeaderNormalization
variant
Normalize packet headers (TTL, window size, etc.)
Decoy
variant
Send decoy packets with low TTL
Reorder
variant
Reorder packet transmission

TransformParams

Structure

pub struct TransformParams {
    pub fragment: FragmentParams,
    pub resegment: ResegmentParams,
    pub padding: PaddingParams,
    pub jitter: JitterParams,
    pub header: HeaderParams,
    pub decoy: DecoyParams,
}

FragmentParams

pub struct FragmentParams {
    pub min_size: usize,
    pub max_size: usize,
    pub split_at_offset: Option<usize>,
    pub randomize: bool,
}
min_size
usize
default:"1"
Minimum fragment size in bytes
max_size
usize
default:"40"
Maximum fragment size in bytes
split_at_offset
Option<usize>
Fixed offset to split at (None = random)
randomize
bool
default:"true"
Randomize fragment sizes

PaddingParams

pub struct PaddingParams {
    pub min_bytes: usize,
    pub max_bytes: usize,
    pub fill_byte: Option<u8>,
}
min_bytes
usize
default:"0"
Minimum padding bytes
max_bytes
usize
default:"64"
Maximum padding bytes
fill_byte
Option<u8>
Byte to use for padding (None = random)

JitterParams

pub struct JitterParams {
    pub min_ms: u64,
    pub max_ms: u64,
}
min_ms
u64
default:"0"
Minimum delay in milliseconds
max_ms
u64
default:"50"
Maximum delay in milliseconds

HeaderParams

pub struct HeaderParams {
    pub normalize_ttl: bool,
    pub ttl_value: u8,
    pub normalize_window: bool,
    pub randomize_ip_id: bool,
}
normalize_ttl
bool
default:"false"
Normalize TTL values
ttl_value
u8
default:"64"
TTL value to use when normalizing
normalize_window
bool
default:"false"
Normalize TCP window sizes
randomize_ip_id
bool
default:"true"
Randomize IP ID field

DecoyParams

pub struct DecoyParams {
    pub send_before: bool,
    pub send_after: bool,
    pub ttl: u8,
    pub probability: f32,
}
send_before
bool
default:"false"
Send decoy packet before real packet
send_after
bool
default:"false"
Send decoy packet after real packet
ttl
u8
default:"1"
TTL for decoy packets
probability
f32
default:"0.0"
Probability of sending decoy (0.0-1.0)

Limits

Structure

pub struct Limits {
    pub max_flows: usize,
    pub max_queue_size: usize,
    pub max_memory_mb: usize,
    pub max_jitter_ms: u64,
    pub flow_timeout_secs: u64,
    pub log_rate_limit: u32,
}
max_flows
usize
default:"10000"
Maximum number of concurrent flows to track
max_queue_size
usize
default:"1000"
Maximum packets in processing queue
max_memory_mb
usize
default:"128"
Memory limit in megabytes
max_jitter_ms
u64
default:"500"
Maximum allowed jitter delay in milliseconds
flow_timeout_secs
u64
default:"120"
Timeout for idle flows in seconds
log_rate_limit
u32
default:"100"
Maximum log messages per second

Complete Example

TOML Configuration

# config.toml

[global]
enabled = true
enable_fragmentation = true
enable_jitter = true
enable_padding = true
enable_header_normalization = false
log_level = "info"
json_logging = false

[[rules]]
name = "discord-bypass"
enabled = true
priority = 100
transforms = ["fragment", "padding", "jitter"]

[rules.match_criteria]
dst_ports = [443]
protocols = ["tcp"]
domains = ["discord.com", "discordapp.com"]

[[rules]]
name = "twitter-bypass"
enabled = true
priority = 90
transforms = ["fragment", "decoy"]

[rules.match_criteria]
dst_ip = ["104.244.42.0/24"]
dst_ports = [443]
protocols = ["tcp"]

[[rules]]
name = "catch-all"
enabled = true
priority = 0
transforms = ["padding"]

[rules.match_criteria]
# Empty = match all

[limits]
max_flows = 10000
max_queue_size = 1000
max_memory_mb = 128
max_jitter_ms = 500
flow_timeout_secs = 120
log_rate_limit = 100

[transforms.fragment]
min_size = 1
max_size = 40
randomize = true

[transforms.padding]
min_bytes = 0
max_bytes = 64

[transforms.jitter]
min_ms = 5
max_ms = 50

[transforms.header]
normalize_ttl = false
ttl_value = 64
normalize_window = false
randomize_ip_id = true

[transforms.decoy]
send_before = true
send_after = false
ttl = 1
probability = 0.3

Loading and Using Config

use turkey_dpi_engine::{Config, Pipeline};
use std::sync::Arc;

// Load from file
let config = Config::load_from_file("config.toml")?;

// Validate before use
config.validate()?;

// Use with Pipeline
let stats = Arc::new(Stats::new());
let pipeline = Pipeline::new(config, stats)?;

// Later: hot-reload configuration
let new_config = Config::load_from_file("config.toml")?;
pipeline.reload_config(new_config)?;

See Also

  • Pipeline - Using Config with the Pipeline
  • BypassEngine - Simple bypass engine (alternative to full Config)

Build docs developers (and LLMs) love