secubox-openwrt/package/secubox/secubox-p2p-intel/files/usr/lib/p2p-intel/applier.sh
CyberMind-FR 006ff03c86 feat(mirrornet): Add v0.19 MirrorNetworking core packages
MirrorNet Core (secubox-mirrornet):
- DID-based identity (did:plc:) with keypair management
- Peer reputation scoring (0-100) with trust levels
- Service mirroring via reverse proxy chaining
- Enhanced gossip protocol with priority routing
- Health monitoring with anomaly detection
- mirrorctl CLI with 30+ commands

Identity Package (secubox-identity):
- Standalone DID generation (AT Protocol compatible)
- HMAC-SHA256 keys with Ed25519 fallback
- Key rotation with backup support
- Trust scoring integration
- identityctl CLI with 25+ commands

P2P Intel Package (secubox-p2p-intel):
- Signed IOC sharing for mesh
- Collectors: CrowdSec, mitmproxy, WAF, DNS Guard
- Cryptographic signing and validation
- Source trust verification
- Application: nftables/iptables/CrowdSec
- Approval workflow for manual review
- p2p-intelctl CLI with 20+ commands

LuCI Dashboard (luci-app-secubox-mirror):
- Identity card with DID, hostname, role
- Peer reputation table with trust levels
- Gossip protocol statistics
- Health alerts with acknowledgment
- RPCD handler with 15 methods

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 18:43:19 +01:00

297 lines
6.8 KiB
Bash

#!/bin/sh
# P2P Intel Applier - Apply validated IOCs to security controls
. /lib/functions.sh
INTEL_DIR="/var/lib/p2p-intel"
APPLIED_FILE="$INTEL_DIR/applied.json"
PENDING_FILE="$INTEL_DIR/pending.json"
# Initialize applier
applier_init() {
[ -f "$APPLIED_FILE" ] || echo '[]' > "$APPLIED_FILE"
[ -f "$PENDING_FILE" ] || echo '[]' > "$PENDING_FILE"
}
# Get application method
_get_method() {
uci -q get p2p-intel.application.apply_method || echo "nftables"
}
# Get ban duration
_get_ban_duration() {
uci -q get p2p-intel.application.ban_duration || echo "86400"
}
# Get ipset name
_get_ipset_name() {
uci -q get p2p-intel.application.ipset_name || echo "p2p_intel_blocked"
}
# Apply IP ban via nftables
_apply_nftables_ip() {
local ip="$1"
local duration="$2"
local ipset_name
ipset_name=$(_get_ipset_name)
# Ensure ipset exists
nft list set inet fw4 "$ipset_name" >/dev/null 2>&1 || \
nft add set inet fw4 "$ipset_name" '{ type ipv4_addr; flags timeout; }' 2>/dev/null
# Add IP with timeout
nft add element inet fw4 "$ipset_name" "{ $ip timeout ${duration}s }" 2>/dev/null
if [ $? -eq 0 ]; then
logger -t p2p-intel "Applied IP ban: $ip (${duration}s via nftables)"
return 0
else
return 1
fi
}
# Apply IP ban via iptables
_apply_iptables_ip() {
local ip="$1"
local duration="$2"
local ipset_name
ipset_name=$(_get_ipset_name)
# Ensure ipset exists
ipset list "$ipset_name" >/dev/null 2>&1 || \
ipset create "$ipset_name" hash:ip timeout "$duration" 2>/dev/null
# Add IP
ipset add "$ipset_name" "$ip" timeout "$duration" 2>/dev/null
if [ $? -eq 0 ]; then
logger -t p2p-intel "Applied IP ban: $ip (${duration}s via iptables)"
return 0
else
return 1
fi
}
# Apply IP ban via CrowdSec
_apply_crowdsec_ip() {
local ip="$1"
local duration="$2"
local scenario="${3:-p2p-intel/shared-ioc}"
if ! command -v cscli >/dev/null 2>&1; then
return 1
fi
cscli decisions add -i "$ip" -d "${duration}s" -R "$scenario" 2>/dev/null
if [ $? -eq 0 ]; then
logger -t p2p-intel "Applied IP ban: $ip (${duration}s via CrowdSec)"
return 0
else
return 1
fi
}
# Apply domain block
_apply_domain_block() {
local domain="$1"
# Add to dnsmasq blocklist
local blocklist="/etc/dnsmasq.d/p2p-intel-blocked.conf"
# Check if already blocked
if grep -q "^address=/$domain/" "$blocklist" 2>/dev/null; then
return 0
fi
echo "address=/$domain/0.0.0.0" >> "$blocklist"
# Reload dnsmasq
/etc/init.d/dnsmasq reload 2>/dev/null
logger -t p2p-intel "Applied domain block: $domain"
return 0
}
# Apply single IOC
apply_ioc() {
local ioc="$1"
local ioc_type value action duration
ioc_type=$(echo "$ioc" | jsonfilter -e '@.type' 2>/dev/null)
value=$(echo "$ioc" | jsonfilter -e '@.value' 2>/dev/null)
action=$(echo "$ioc" | jsonfilter -e '@.action' 2>/dev/null)
duration=$(_get_ban_duration)
local method
method=$(_get_method)
local result=1
case "$ioc_type" in
ip)
case "$method" in
nftables)
_apply_nftables_ip "$value" "$duration" && result=0
;;
iptables)
_apply_iptables_ip "$value" "$duration" && result=0
;;
crowdsec)
_apply_crowdsec_ip "$value" "$duration" && result=0
;;
esac
;;
domain)
_apply_domain_block "$value" && result=0
;;
*)
logger -t p2p-intel "Unknown IOC type: $ioc_type"
return 1
;;
esac
if [ "$result" -eq 0 ]; then
# Record as applied
_record_applied "$ioc"
fi
return $result
}
# Record applied IOC
_record_applied() {
local ioc="$1"
local timestamp
timestamp=$(date +%s)
local entry="{\"ioc\":$ioc,\"applied_at\":$timestamp}"
local tmp_file="/tmp/applied_$$.json"
if [ -s "$APPLIED_FILE" ] && [ "$(cat "$APPLIED_FILE")" != "[]" ]; then
sed 's/]$/,'"$entry"']/' "$APPLIED_FILE" > "$tmp_file"
else
echo "[$entry]" > "$tmp_file"
fi
mv "$tmp_file" "$APPLIED_FILE"
}
# Add IOC to pending queue (for manual approval)
queue_pending() {
local ioc="$1"
local source="$2"
local timestamp
timestamp=$(date +%s)
local entry="{\"ioc\":$ioc,\"source\":\"$source\",\"queued_at\":$timestamp,\"status\":\"pending\"}"
local tmp_file="/tmp/pending_$$.json"
if [ -s "$PENDING_FILE" ] && [ "$(cat "$PENDING_FILE")" != "[]" ]; then
sed 's/]$/,'"$entry"']/' "$PENDING_FILE" > "$tmp_file"
else
echo "[$entry]" > "$tmp_file"
fi
mv "$tmp_file" "$PENDING_FILE"
logger -t p2p-intel "Queued IOC for approval from $source"
}
# Get pending IOCs
get_pending() {
cat "$PENDING_FILE"
}
# Approve pending IOC
approve_pending() {
local index="$1"
# Get the IOC at index
local ioc
ioc=$(jsonfilter -i "$PENDING_FILE" -e "@[$index].ioc" 2>/dev/null)
if [ -z "$ioc" ]; then
echo '{"error": "IOC not found"}'
return 1
fi
# Apply it
apply_ioc "$ioc"
# Remove from pending (simplified - just mark as approved)
logger -t p2p-intel "Approved pending IOC at index $index"
echo '{"success": true}'
}
# Reject pending IOC
reject_pending() {
local index="$1"
# Mark as rejected (simplified)
logger -t p2p-intel "Rejected pending IOC at index $index"
echo '{"success": true}'
}
# Apply all validated IOCs (auto-apply mode)
apply_all_validated() {
local validated_dir="$INTEL_DIR/validated"
local applied=0
local failed=0
for f in "$validated_dir"/*.json 2>/dev/null; do
[ -f "$f" ] || continue
jsonfilter -i "$f" -e '@[*]' 2>/dev/null | while read -r ioc; do
[ -z "$ioc" ] && continue
if apply_ioc "$ioc"; then
applied=$((applied + 1))
else
failed=$((failed + 1))
fi
done
# Move processed file
mv "$f" "$INTEL_DIR/processed/" 2>/dev/null
done
echo "{\"applied\": $applied, \"failed\": $failed}"
}
# Get applied IOCs
get_applied() {
cat "$APPLIED_FILE"
}
# Remove IP ban
remove_ban() {
local ip="$1"
local method
method=$(_get_method)
local ipset_name
ipset_name=$(_get_ipset_name)
case "$method" in
nftables)
nft delete element inet fw4 "$ipset_name" "{ $ip }" 2>/dev/null
;;
iptables)
ipset del "$ipset_name" "$ip" 2>/dev/null
;;
crowdsec)
cscli decisions delete -i "$ip" 2>/dev/null
;;
esac
logger -t p2p-intel "Removed ban: $ip"
}
# Initialize on source
applier_init