#!/bin/sh # nDPId Flow Actions Handler # Processes flow events and updates ipsets/nftables # Copyright (C) 2025 CyberMind.fr . /lib/functions.sh . /usr/share/ndpid/functions.sh 2>/dev/null || true DISTRIBUTOR_SOCK="/var/run/ndpid/distributor.sock" CONFIG_FILE="/etc/config/ndpid" # Load configuration load_config() { config_load ndpid config_get_bool ACTIONS_ENABLED actions enabled 0 config_get BITTORRENT_IPSET actions bittorrent_ipset "secubox-bittorrent" config_get BITTORRENT_TIMEOUT actions bittorrent_timeout 900 config_get STREAMING_IPSET actions streaming_ipset "secubox-streaming" config_get STREAMING_TIMEOUT actions streaming_timeout 1800 config_get BLOCKED_IPSET actions blocked_ipset "secubox-blocked" config_get BLOCKED_TIMEOUT actions blocked_timeout 3600 # Get blocked applications BLOCKED_APPS="" config_list_foreach actions blocked_app append_blocked_app } append_blocked_app() { BLOCKED_APPS="$BLOCKED_APPS $1" } # Normalize application name from nDPI format normalize_app() { echo "$1" | tr '.' '\n' | tail -1 | tr '[:upper:]' '[:lower:]' } # Check if app is in blocked list is_blocked_app() { local app="$1" for blocked in $BLOCKED_APPS; do [ "$app" = "$blocked" ] && return 0 done return 1 } # Check if app is streaming service is_streaming_app() { local app="$1" case "$app" in netflix|youtube|spotify|twitch|disney|amazon_video|hulu|hbo|apple_tv|peacock) return 0 ;; esac return 1 } # Process a flow detection event process_detection() { local json="$1" # Extract fields local src_ip=$(echo "$json" | jsonfilter -e '@.src_ip' 2>/dev/null) local dst_ip=$(echo "$json" | jsonfilter -e '@.dst_ip' 2>/dev/null) local ndpi_proto=$(echo "$json" | jsonfilter -e '@.ndpi.proto' 2>/dev/null) [ -z "$ndpi_proto" ] && return local app=$(normalize_app "$ndpi_proto") # BitTorrent detection if [ "$app" = "bittorrent" ]; then logger -t ndpid-actions "BitTorrent detected: $src_ip -> $dst_ip" ipset add "$BITTORRENT_IPSET" "$src_ip" timeout "$BITTORRENT_TIMEOUT" 2>/dev/null ipset add "$BITTORRENT_IPSET" "$dst_ip" timeout "$BITTORRENT_TIMEOUT" 2>/dev/null fi # Streaming services detection if is_streaming_app "$app"; then ipset add "$STREAMING_IPSET" "$dst_ip" timeout "$STREAMING_TIMEOUT" 2>/dev/null fi # Blocked applications if is_blocked_app "$app"; then logger -t ndpid-actions "Blocked app detected: $app from $src_ip" ipset add "$BLOCKED_IPSET" "$src_ip" timeout "$BLOCKED_TIMEOUT" 2>/dev/null fi } # Main event processing loop process_events() { while IFS= read -r line; do # Strip 5-digit length prefix local json="${line:5}" # Get event type local event=$(echo "$json" | jsonfilter -e '@.flow_event_name' 2>/dev/null) case "$event" in detected|guessed) process_detection "$json" ;; esac done } # Create ipsets if they don't exist setup_ipsets() { ipset list "$BITTORRENT_IPSET" >/dev/null 2>&1 || \ ipset create "$BITTORRENT_IPSET" hash:ip timeout "$BITTORRENT_TIMEOUT" ipset list "$STREAMING_IPSET" >/dev/null 2>&1 || \ ipset create "$STREAMING_IPSET" hash:ip timeout "$STREAMING_TIMEOUT" ipset list "$BLOCKED_IPSET" >/dev/null 2>&1 || \ ipset create "$BLOCKED_IPSET" hash:ip timeout "$BLOCKED_TIMEOUT" } # Main main() { load_config if [ "$ACTIONS_ENABLED" -ne 1 ]; then logger -t ndpid-actions "Flow actions disabled in config" exit 0 fi logger -t ndpid-actions "Starting flow actions handler" # Setup ipsets setup_ipsets # Wait for socket local wait_count=0 while [ ! -S "$DISTRIBUTOR_SOCK" ] && [ $wait_count -lt 30 ]; do sleep 1 wait_count=$((wait_count + 1)) done if [ ! -S "$DISTRIBUTOR_SOCK" ]; then logger -t ndpid-actions "ERROR: Distributor socket not found" exit 1 fi # Connect and process events if command -v socat >/dev/null 2>&1; then socat -u UNIX-CONNECT:"$DISTRIBUTOR_SOCK" - | process_events else nc -U "$DISTRIBUTOR_SOCK" | process_events fi } case "$1" in -d|--daemon) main & echo $! > /var/run/ndpid-flow-actions.pid ;; *) main ;; esac