Skip to content

SaeedMahar2006/Icmp-Tunnel-Detection

Repository files navigation

Icmp Tunnel Detection

Scope

A lightweight containerised ICMP monitoring and detection worker that turns raw packet capture into extensible observability and actions based on a rule engine.

First class integration and examples for Prometheus and Grafana ecosystem, but uses OpenTelemetry for portability.

Setup

Build Requirement

  • .NET 8 SDK
  • Docker & Docker Compose (optional, for containerized builds/runs)

Clone

git clone https://github.com/SaeedMahar2006/Modux-Project.git
cd Modux-Project

Restore and build

dotnet restore IcmpTunnelDetection.sln
dotnet build IcmpTunnelDetection.sln

Run locally

dotnet run --project IcmpSniffer.Worker

Build/run with Docker

docker compose build icmpsniffer
docker compose up icmpsniffer

Examples

Sample compose and observability configs live in Example/. The LLM demo rule is in Detection/flow-rules.json (it emits packet_sampling + llm_judge commands), and the pattern is fully extensible/customizable by adding your own actions, consumers, or judge implementations.

LLM Packet Judging

The system includes a powerful LLM-based packet analysis capability that allows you to leverage large language models to judge ICMP packets for suspicious activity. When enabled, the LLM judge can:

  • Analyze individual ICMP packets for signs of tunneling, exfiltration, or other malicious activity
  • Return structured verdicts with suspicious (bool) and reason fields
  • Process packet payloads in hex and base64 formats for comprehensive analysis
  • Support custom prompts to tailor the analysis to your specific security requirements

The LLM judge works by:

  1. Packet Sampling: When a rule triggers (e.g., LLM_DEMO_SAMPLING), it enables packet sampling for the flow
  2. LLM Policy Application: The rule also creates an LLM judge policy specifying analysis parameters
  3. Asynchronous Processing: The LlmPacketJudgeConsumer processes sampled packets and sends them to the LLM
  4. Verdict Collection: Results are logged with detailed information about suspicious packets

The default implementation uses OpenAI-compatible APIs (configurable via OpenAI:* settings) and can be customized by implementing the ILlmPacketJudge interface.

Here is example log it emits

icmpsniffer-worker  |       LLM packet verdict: suspicious=True flow=[redacted] <-> [redacted] id=8 src=[redacted] dst=[redacted] type=8 code=0 bytes=27 reason=The ICMP Echo Request packet has an unusually large and structured payload of 27 bytes. The hexadecimal payload shows a distinct pattern with an initial header-like sequence (10-01-22-0F) followed by a mix of data, including what resembles a timestamp (0E-E1-0C-3E) and trailing data. This is atypical for normal ICMP Echo traffic, which typically carries minimal or simple payloads like sequential data for reachability testing. The size and apparent structure suggest the payload could be encapsulating covert data for tunneling or exfiltration, as it aligns with known ICMP tunneling techniques.

Packet Sampling Architecture

The system features a sophisticated packet sampling architecture that enables efficient analysis of suspicious flows:

Rule Detection → PacketSamplingActionHandler → FlowTracker (Buffering) 
                                      ↓
                              ActionSupervisorService 
                                      ↓
                              IPacketSampleConsumer implementations

Key Components:

  • PacketSamplingActionHandler: Stores sampling policies for flows when rules trigger
  • FlowTracker: Buffers packet samples according to policy specifications (count/percentage + cap)
  • ActionSupervisorService: Orchestrates sampling sessions and dispatches samples to consumers
  • IPacketSampleConsumer: Interface for components that need to analyze sampled packets

Sampling Modes:

  • Count-based: Sample a fixed number of packets
  • Percentage-based: Sample a percentage of packets
  • Cap: Optional hard cap on total samples per flow

By default, sampling is only enabled when a rule emits a packet_sampling action. This architecture allows multiple consumers to analyze the same packet samples, enabling parallel processing for different analysis needs.

Action Spawning and Management

The system uses a robust action management system that dispatches immediate actions and manages long-running or sampling actions based on rule detections:

Flow Detection → Rule Evaluation → ActionCommand Creation
                                      ↓
                              FlowRulesEvaluator → IActionHandler implementations
                                      ↓
                         ActionSupervisorService (sampling + sessions)
                              ↓                     ↓
                      IPacketSampleConsumer   IActionSessionProvider

Action Types:

  1. Immediate Actions (IActionHandler): Execute immediately when rules trigger (e.g., logging, alerts)
  2. Session-based Actions (IActionSessionProvider): Long-running sessions for continuous monitoring
  3. Sampling-based Actions (IPacketSampleConsumer): Analyze sampled packets from suspicious flows

Action Lifecycle:

  • Immediate actions are dispatched by FlowRulesEvaluator when rules match
  • Sampling and session policies are synchronized by ActionSupervisorService
  • Policies are synchronized periodically (configurable interval)
  • Sessions are automatically cleaned up when flows disappear
  • Idempotency keys prevent duplicate action execution

The architecture supports extensibility - new action types can be added by implementing the appropriate interfaces and will be automatically discovered and registered.

Project Layout

  • Domain/ — core domain models, shared interfaces, and utilities.
  • Detection/ — your custom detection logic and handlers; defines flow-rules.json so you can extend rule definitions here. Review RulesEngine docs for syntax, follow anonymous object style by example given.
  • IcmpSniffer.Worker/ — worker service that does packet capture and wiring:
    • references Domain and links Detection/flow-rules.json
    • exports metrics
  • docker-compose.yaml — builds/runs the worker container (host network, NET_RAW/NET_ADMIN caps) for on-host packet capture.

ICMP Flow Diagram

Options

Settings live in IcmpSniffer.Worker/appsettings.json and can be overridden with environment variables. Docker Compose uses the same env var names under services.icmpsniffer.environment.

Setting (appsettings.json) Default (if unset) What it does Compose env var
Logging:LogLevel:Default Information Default minimum log level for the app Logging__LogLevel__Default
Logging:LogLevel:Microsoft.Hosting.Lifetime Information Log level for host lifecycle logs (start/stop, etc.) Logging__LogLevel__Microsoft.Hosting.Lifetime
IcmpCapture:DeviceNames [] Interface/device names to capture on. Empty means auto-selection. IcmpCapture__DeviceNames__0, IcmpCapture__DeviceNames__1, ...
IcmpCapture:Filter icmp or icmp6 BPF filter applied to capture (SharpPcap/libpcap style) IcmpCapture__Filter
IcmpCapture:DetectionInterval 00:00:05 How often to run detection over current flows IcmpCapture__DetectionInterval
IcmpCapture:FlowIdleTimeout 00:05:00 How long a flow can be idle before it is pruned IcmpCapture__FlowIdleTimeout
IcmpCapture:LogPackets true Enable per-packet logging (queued off capture threads) IcmpCapture__LogPackets
IcmpCapture:PacketLogQueueCapacity 2048 Bounded queue capacity for per-packet logs IcmpCapture__PacketLogQueueCapacity
FlowTracker:MaxSamplesPerFlow 256 Max packet samples stored per sampling-enabled flow FlowTracker__MaxSamplesPerFlow
Actions:LlmPacketJudgeType "" Override ILlmPacketJudge type name (empty uses built-in default)(Only for LLM capability) Actions__LlmPacketJudgeType
OpenAI:ApiKey null API key for LLM judge (Only for LLM capability) OpenAI__ApiKey
OpenAI:DefaultModel deepseek/deepseek-v3.2 Default model id used by the LLM judge (Only for LLM capability) OpenAI__DefaultModel
OpenAI:BaseUrl https://openrouter.ai/api/v1 OpenAI-compatible base URL (Only for LLM capability) OpenAI__BaseUrl
OpenAI:Prompt null Optional custom prompt for the LLM judge (Only for LLM capability) OpenAI__Prompt
ActionSupervisor:PolicySyncInterval 00:00:02 How often to refresh action policy ActionSupervisor__PolicySyncInterval
ActionSupervisor:SamplingInterval 00:00:01 Flow sampling interval used by action supervisor ActionSupervisor__SamplingInterval
ActionSupervisor:StrictMonitoringInterval 00:00:01 Strict monitoring interval used by action supervisor ActionSupervisor__StrictMonitoringInterval
Metrics:Enabled true Enable/disable metrics endpoint/export Metrics__Enabled
Metrics:Port 9464 Port to expose metrics on (host network recommended) Metrics__Port
OpenTelemetry:Otlp:Enabled true Enable/disable OTLP exporter for logs/metrics OpenTelemetry__Otlp__Enabled
OpenTelemetry:Otlp:Endpoint null OTLP collector endpoint (e.g. http://localhost:4317) OpenTelemetry__Otlp__Endpoint
OpenTelemetry:Otlp:Headers null OTLP headers (e.g. Authorization=Bearer <token>) OpenTelemetry__Otlp__Headers
OpenTelemetry:Otlp:Protocol null grpc or http/protobuf OpenTelemetry__Otlp__Protocol
OpenTelemetry:Otlp:TimeoutMilliseconds null OTLP export timeout in ms OpenTelemetry__Otlp__TimeoutMilliseconds
ASPNETCORE_ENVIRONMENT Production Selects appsettings.{Environment}.json overlay (e.g. Development) ASPNETCORE_ENVIRONMENT

Notes:

  • TimeSpan values use hh:mm:ss (example: 00:00:05). Longer formats like d.hh:mm:ss also work.
  • Prefer env vars for secrets like OpenAI__ApiKey.

Example

services:
  icmpsniffer:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development

      # Logging
      - Logging__LogLevel__Default=Information
      - Logging__LogLevel__Microsoft.Hosting.Lifetime=Information

      # Capture
      - IcmpCapture__Filter=icmp or icmp6
      - IcmpCapture__DetectionInterval=00:00:05
      - IcmpCapture__FlowIdleTimeout=00:05:00
      # Example: pick interfaces explicitly
      - IcmpCapture__DeviceNames__0=eth0
      - IcmpCapture__DeviceNames__1=eth1

      # Flow tracking
      - FlowTracker__MaxSamplesPerFlow=256

      # LLM judge (optional)
      - Actions__LlmPacketJudgeType=
      - OpenAI__ApiKey=REPLACE_ME
      - OpenAI__DefaultModel=deepseek/deepseek-v3.2
      - OpenAI__BaseUrl=https://openrouter.ai/api/v1

      # Metrics
      - Metrics__Enabled=true
      - Metrics__Port=9464

Make sure to change values and settings.

Extensibility Architecture

The system is designed for easy extension at multiple levels, with automatic discovery and dependency injection support.

Extension Points

  • Custom Rules: Modify Detection/flow-rules.json to add detection logic using RulesEngine syntax
  • Action Handlers: Implement IActionHandler for immediate actions triggered by rule matches
  • Packet Consumers: Implement IPacketSampleConsumer for analyzing sampled packet data
  • Session Providers: Implement IActionSessionProvider for long-running monitoring sessions
  • LLM Judges: Implement ILlmPacketJudge to replace or extend AI-based packet analysis

Automatic Discovery

  • Location: Place implementation classes in the Detection project
  • Discovery: AddDetectionActions() scans the assembly for concrete types implementing extension interfaces
  • Registration: All found implementations are registered as singletons with the DI container
  • Activation: Components are instantiated with full dependency injection support

Key Interfaces

  • IActionHandler: Handle immediate actions with Type and Handle()
  • IPacketSampleConsumer: Analyze packet samples with Wants() and ConsumeAsync()
  • IActionSessionProvider: Manage long-running sessions with GetDesiredSessions() and RunSessionAsync()
  • ILlmPacketJudge: Judge individual packets with JudgeAsync()

Development Workflow

  1. Create Implementation: Add a class implementing the appropriate interface
  2. Define Policy Classes: Create record types for action configuration (serialized as camelCase JSON)
  3. Add to Rules: Use ActionCommandFactory.Create() in flow-rules.json to trigger your extension
  4. Test: The system automatically picks up your implementation
  5. Deploy: No additional configuration needed - just build and run

Advanced Customization

  • Override LLM Judge: Set Actions:LlmPacketJudgeType to your custom implementation
  • Multiple Consumers: Multiple IPacketSampleConsumer implementations can analyze the same packets
  • Session Management: Use Pinned = true for sessions that should survive flow pruning
  • Policy Evolution: Use configuration hashes to detect and reload changed policies

Custom Rules and Actions

The detector evaluates rules from Detection/flow-rules.json using RulesEngine. Each rule runs against a single FlowFact and returns a DetectionAction with optional action commands.

1) Add/modify rules

  • Rules live in Detection/flow-rules.json and are copied to the worker output at build time.
  • Expressions are LambdaExpression and use input as the FlowFact instance.
  • Common fields: TotalPackets, TotalBytes, AveragePayloadBytes, DurationSeconds, PacketsPerSecond, BytesPerSecond, ForwardPackets, ReversePackets, IcmpType, IcmpCode.

Minimal rule pattern (note the OutputExpression fields):

"Actions": {
  "OnSuccess": {
    "Name": "OutputExpression",
    "Context": {
      "Expression": "new(\"MY_RULE\" as Rule, TunnelSeverity.Medium as Severity, 2.0 as Score, \"My reason\" as Reason, null as Commands)"
    }
  }
}

Meaning of fields

  • Rule: rule name used for logging/aggregation.
  • Severity: TunnelSeverity enum value (Low/Medium/High).
  • Score: numeric weight used when aggregating multiple matches.
  • Reason: human-readable reason stored on the detection.
  • Commands: optional list of ActionCommand objects to trigger actions.

2) Emit action commands from a rule

Use ActionCommandFactory.Create(type, payload, idempotencyKey, pinned) in the rule expression:

ActionCommandFactory.Create("packet_sampling",
    new (PacketSamplingMode.Count as mode, 5 as amount, 50 as cap),
    null, false)

Notes:

  • type must match an IActionHandler.Type (case-insensitive).
  • Payload is serialized with camelCase keys (that's what ActionCommandFactory does).
  • idempotencyKey suppresses duplicates; pinned scopes idempotency to the flow key (survives pruning).

3) Implement your own action (pattern)

Create your action class in the Detection project (same assembly) and implement one of:

  • IActionHandler for immediate rule-triggered actions.
  • IPacketSampleConsumer if you need sampled packets.
  • IActionSessionProvider for long-running sessions.

Example handler skeleton:

public sealed class MyActionHandler : IActionHandler
{
    public const string ActionType = "my_action";
    public string Type => ActionType;

    public void Handle(IcmpFlow flow, FlowFact fact, ActionCommand command)
    {
        var policy = command.Payload.Deserialize<MyActionPolicy>(new JsonSerializerOptions
        {
            PropertyNameCaseInsensitive = true
        });
        // do something with policy + flow/fact
    }
}

public sealed record MyActionPolicy(string? Tag = null, int? Threshold = null);

Naming conventions

  • Rule names: UPPER_SNAKE (e.g., HIGH_VOLUME_SHORT_WINDOW).
  • Action types: lower_snake (e.g., packet_sampling, llm_judge).
  • Payload fields: camelCase (recommended to match ActionCommandFactory).

4) How the LLM action works (reference pattern)

The built-in LLM path is a good example of the pattern:

  • Rule emits packet_sampling + llm_judge commands (see Detection/flow-rules.json).
  • PacketSamplingActionHandler stores sampling policies for flows.
  • LlmPacketJudgeActionHandler stores per-flow LLM policies.
  • LlmPacketJudgeConsumer (an IPacketSampleConsumer) reads sampled packets and calls ILlmPacketJudge.
  • Default judge is OpenAiLlmPacketJudge, configured via OpenAI:* settings.
  • To override the judge, set Actions:LlmPacketJudgeType to a type name that implements ILlmPacketJudge (example: IcmpTunnelDetection.Detection.Actions.MyCustomJudge).

5) Registration (no manual DI needed)

AddDetectionActions(...) auto-registers all concrete types in the Detection assembly that implement IActionHandler, IPacketSampleConsumer, or IActionSessionProvider.
So: place your classes in the Detection project, keep them non-abstract, and they will be picked up.

Dependencies and licensing

Project Package (or group) License Used? Notes
Domain RulesEngine MIT Rule evaluation engine (FlowRulesEvaluator)
Detection OpenAI MIT LLM judge client
Detection Microsoft.Extensions.Logging.Abstractions MIT Logging for LLM consumer
Detection Microsoft.Extensions.Configuration.Abstractions MIT IConfiguration in action registration
Detection Microsoft.Extensions.DependencyInjection.Abstractions MIT IServiceCollection in action registration
Worker SharpPcap MIT Live packet capture
Worker PacketDotNet MPL-2.0 Packet parsing
Worker RulesEngine MIT Workflow model load
Worker OpenTelemetry stack (core + OTLP + Prometheus + runtime) Apache-2.0 Metrics + OTLP export + /metrics endpoint

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors