mirror of
https://github.com/DaLaw2/NetGuardia.git
synced 2026-08-24 14:10:28 +09:00
* fix: ML formula alignment, dependency cleanup, and code quality - Restore correct MSE denominator (ae_feature_names.len()) - Align feature extraction with CICFlowMeter: payload bytes, sample std (N-1), min_seg_size_forward without payload filter, act_data_pkt_fwd skip first packet, init_win_bytes_bwd stores last packet - Organize workspace dependencies and update all crates to latest - Fix libxdp-sys 0.2.4 clang 20 build (enable use_cc_build + use_precompiled_bpf) - Pin aya-ebpf =0.1.1 (0.1.2 yanked, aya-rs/aya#1400) - Remove all comments and dead code - Use macro-generated constructors for error types - Replace eprintln/tracing::error with log! macro - Clean up duplicate/unused error and log variants, fix log levels Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: correct UDP/TCP/mid-stream forward/backward direction logic * fix: symmetric hash redirect, per-queue optimization, and ICMP ACL support eBPF: Add XOR symmetric hash to transmission stage so both directions of a flow land on the same XSK queue, fixing the RSS asymmetry bug that caused FlowTracker to only see one direction. Egress uses stack-local ParsedPacket to avoid unnecessary map allocation. Allow non-TCP/UDP packets through the pipeline so ACL can block ICMP. Userspace: Revert shared tracker to per-queue trackers now that symmetric hash guarantees bidirectional visibility. Replace Arc<Mutex<Vec<FrameDesc>>> with private Vec per XskPair to eliminate hot-path lock contention. Add pre-allocated BufferPool and parse-before-clone to reduce per-packet malloc. Log partial sends when frames < packets. Config: Add mtu, packet_buffer_size, buffer_pool_capacity to [Network] with serde defaults for backward compatibility. Cleanup: Remove unused Direction::flip(), FlowTracker::drain_flows(), FlowStatistics broadcast/subscribe, MAX_BUFFERED_PACKETS, and Engine::process_packet wrapper. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: drop event ring buffer, double-buffer flow tracker, and review fixes eBPF: Add 256KB RingBuf map for drop event reporting. Each XDP_DROP site (ACL blacklist, rate limit, protocol filter) emits a DropEvent with reason code. Refactor rate_limit::should_drop to return Option<u8> with specific reason. Extract rate limit defaults to common/define/setting. Userspace: Add DropMonitor with tokio async consumer, broadcast channel, DropCounters, and /api/stats/drops REST + /ws/drops WebSocket endpoints. FlowTracker: Replace O(flows) lock with O(1) take_snapshot() swap. Inference tick now does phase-1 swap under lock, phase-2 filter outside lock. Removes cleanup_old_flows, get_flows_for_inference, drain_flows_for_logging. Review fixes: explicit IPv6 match in symmetric_hash, consistent naming (compute_symmetric_queue_id), reason_to_str helper, std::net::Ipv6Addr formatting, WebSocketLagged typo, remove unused mtu config field. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: move IP field writes before L4 match to prevent eBPF dead store elimination The eBPF LLVM backend was optimizing away the non-TCP/UDP path by treating ParsedPacket writes as dead stores (reads happen in separate tail-called programs). Moving IP-level fields (timestamp, src/dst IP, packet_length, ip_version, protocol) before the L4 protocol match ensures they are written regardless of protocol, sharing code path with TCP/UDP and preventing branch merging with the error path. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: GeoIP LPM Trie country blocking and DNS query blacklist eBPF: Add LPM Trie maps (GEO_BLOCK_V4/V6) in access_control for country-level IP blocking with big-endian keys for correct prefix matching. Add DNS query name parser in dns_filter with bounded loops, lowercase normalization, and subdomain matching via parent domain iteration. Both emit drop events with new reason codes. Userspace: Add GeoBlock manager that loads CIDR prefixes from MaxMind GeoLite2 database into LPM Tries per blocked country. Add DnsFilter manager with wire-format domain conversion. New REST endpoints: PUT/DELETE/GET /api/acl/geo/{block,unblock,blocked} and PUT/DELETE/GET /api/filter/dns/blacklist. Review fixes: DNS header bounds check off-by-one (+2 to +3), total_prefixes accumulation (= to +=), proper InvalidDnsName error type replacing InvalidMapType abuse. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: review fixes for GeoIP and DNS features GeoIP: Fix LPM Trie endianness (from_be_bytes → from_ne_bytes for consistent memory layout). Move whitelist check before geo/blacklist (whitelist should always take priority). Batch block/unblock API to rebuild tries only once. Minimize rebuild gap by collecting entries before locking. Use config path for GeoIP DB. Validate country codes (2-letter alpha). DNS: Fix bounds check off-by-one (dns_header+2 → +3). Add QDCOUNT>0 check. Replace InvalidMapType error with proper InvalidDnsName variant. Add domain count limit per request (1000). Wrap API responses in JSON objects for consistency. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: add deployment and testing infrastructure Add container definitions, compose config, and traffic generator scripts for realistic inline deployment testing. deploy/compose/ — Containerfiles for netguardia, router, endpoints and podman-compose.yml with management network deploy/scripts/ — setup.sh (veth/namespace wiring), traffic-external.sh and traffic-internal.sh Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: P0 bugs — IPv4 IHL parsing, TX frame leak, SSH whitelist logic IPv4 IHL: L4 header offset was hardcoded to 34 (20-byte IPv4 header). Now reads IHL field dynamically (20-60 bytes) so IP options don't cause wrong port/flag parsing. Attackers could previously bypass port-based rules by adding IP options. TX frame leak: tx.produce() may submit fewer frames than provided. Unsubmitted FrameDescs were lost, permanently shrinking frame_pool. Now returns unsubmitted frames to pool. SSH whitelist: Array<PlaceHolder>.get(0).is_some() always returns true (zero-initialized entries exist). Changed to check actual value != 0, matching userspace enable(1)/disable(0) semantics. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: P1 bugs — rate_limit real values, ML status, DNS rate protocol check rate_limit API: GET /api/rate-limit/config now reads actual values from eBPF Array map instead of returning hardcoded defaults. Added getter methods for each rate limit parameter. ML status API: GET /api/ml/status now returns real engine state (mode, tracker count, flow count, inference interval) instead of hardcoded {"active": true}. DNS rate limit: Added UDP protocol check before dst_port==53 test. TCP connections to port 53 no longer incorrectly trigger DNS rate limiter alongside packet rate limiter. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf: P2 fixes — binary IPs, pre-alloc buffers, build.rs dedup parse_packet: Replace String IP addresses with [u8; 16] binary in UserPacket, eliminating 2M heap allocations/sec at 1Mpps. FlowKey copies bytes directly instead of string-parse-to-bytes round-trip. xsk_manager: Pre-allocate comp_descs (256) and rx_descs (64) once before the main loop instead of per-iteration vec![] allocation. build.rs: Extract duplicate build_ingress_ebpf/build_egress_ebpf into shared build_ebpf_package(). Add cargo:rerun-if-changed for common/src to fix stale eBPF build cache when common crate changes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf: P2 fixes — feature_extractor precompute, filter.rs dedup feature_extractor: Pre-compute all statistics once via PrecomputedStats struct instead of recomputing per feature name. ~70x speedup for the 72-feature extraction step. Public API unchanged. filter.rs: Extract ok_or_error() helper to eliminate 16 instances of duplicated match-result-to-HttpResponse pattern. File reduced from 338 to 243 lines with identical behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: P3 code quality — release profile, dep cleanup, dead code, safety Release profile: Enable opt-level=3, lto="thin", strip=true. Dependencies: Remove unused `futures` crate. Change tokio from "full" to selective features (rt-multi-thread, macros, sync, time). Remove commented-out csv/anyhow deps. Dead code: Remove unused get_attack_label(), unnecessary #[allow(dead_code)] annotations where code is actually used. Safety: Add bounds check in PortRule::to_port_vec to prevent OOB if count is corrupted. Fix set_config to propagate errors instead of silently ignoring with `let _ =`. Misc: Add .env, .DS_Store, profiling files to .gitignore. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: ParrotXray <b05817691@gmail.com>
128 lines
3.6 KiB
Bash
128 lines
3.6 KiB
Bash
#!/bin/bash
|
|
# External network traffic generator
|
|
# Simulates external hosts sending traffic toward the internal network
|
|
|
|
INTERNAL_IP="10.10.2.2"
|
|
SELF_BASE="10.10.1"
|
|
|
|
echo "[external] Traffic generator started"
|
|
|
|
# Wait for network and routing to be ready
|
|
sleep 5
|
|
until ping -c 1 -W 1 $INTERNAL_IP &>/dev/null; do
|
|
echo "[external] Waiting for internal connectivity..."
|
|
sleep 2
|
|
done
|
|
echo "[external] Internal network reachable"
|
|
|
|
# --- Benign traffic functions ---
|
|
|
|
http_traffic() {
|
|
while true; do
|
|
for src in 2 3 4; do
|
|
local ip="${SELF_BASE}.${src}"
|
|
# Various HTTP methods
|
|
curl -s --interface $ip -o /dev/null -m 3 http://${INTERNAL_IP}/ 2>/dev/null
|
|
curl -s --interface $ip -o /dev/null -m 3 -X POST -d "data=test" http://${INTERNAL_IP}/ 2>/dev/null
|
|
curl -s --interface $ip -o /dev/null -m 3 -X HEAD http://${INTERNAL_IP}/ 2>/dev/null
|
|
curl -s --interface $ip -o /dev/null -m 3 -X OPTIONS http://${INTERNAL_IP}/ 2>/dev/null
|
|
done
|
|
sleep $((RANDOM % 3 + 1))
|
|
done
|
|
}
|
|
|
|
ssh_traffic() {
|
|
while true; do
|
|
for src in 2 5; do
|
|
local ip="${SELF_BASE}.${src}"
|
|
# SSH connection attempts (will fail but generates TCP SYN to port 22)
|
|
timeout 2 bash -c "echo | nc -w 1 -s $ip $INTERNAL_IP 22" 2>/dev/null || true
|
|
done
|
|
sleep $((RANDOM % 5 + 3))
|
|
done
|
|
}
|
|
|
|
dns_traffic() {
|
|
while true; do
|
|
for src in 2 3 6; do
|
|
local ip="${SELF_BASE}.${src}"
|
|
# UDP packets to port 53 (DNS-like)
|
|
echo -ne '\x00\x01\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\x01\x00\x01' | \
|
|
nc -u -w 1 -s $ip $INTERNAL_IP 53 2>/dev/null || true
|
|
done
|
|
sleep $((RANDOM % 4 + 2))
|
|
done
|
|
}
|
|
|
|
udp_traffic() {
|
|
while true; do
|
|
for src in 2 4 7; do
|
|
local ip="${SELF_BASE}.${src}"
|
|
for port in 5000 5001 8000 9090; do
|
|
echo "udp-payload-$(date +%s)" | nc -u -w 1 -s $ip $INTERNAL_IP $port 2>/dev/null || true
|
|
done
|
|
done
|
|
sleep $((RANDOM % 3 + 2))
|
|
done
|
|
}
|
|
|
|
tcp_traffic() {
|
|
while true; do
|
|
for src in 3 5 6; do
|
|
local ip="${SELF_BASE}.${src}"
|
|
for port in 3000 4000 6379 5432; do
|
|
timeout 2 bash -c "echo 'hello' | nc -w 1 -s $ip $INTERNAL_IP $port" 2>/dev/null || true
|
|
done
|
|
done
|
|
sleep $((RANDOM % 4 + 2))
|
|
done
|
|
}
|
|
|
|
icmp_traffic() {
|
|
while true; do
|
|
for src in 2 3 4 5; do
|
|
local ip="${SELF_BASE}.${src}"
|
|
ping -c 2 -W 1 -I $ip $INTERNAL_IP >/dev/null 2>&1 || true
|
|
done
|
|
sleep $((RANDOM % 5 + 3))
|
|
done
|
|
}
|
|
|
|
# --- Attack-like traffic (low intensity, for ML training) ---
|
|
|
|
syn_scan() {
|
|
while true; do
|
|
sleep $((RANDOM % 30 + 30))
|
|
src="${SELF_BASE}.$((RANDOM % 3 + 5))"
|
|
echo "[external] SYN scan burst from $src"
|
|
# Quick port scan pattern
|
|
for port in 22 80 443 8080 3306 5432 6379 8443 9090 27017; do
|
|
timeout 1 bash -c "echo | nc -w 1 -s $src $INTERNAL_IP $port" 2>/dev/null || true
|
|
done
|
|
done
|
|
}
|
|
|
|
udp_burst() {
|
|
while true; do
|
|
sleep $((RANDOM % 60 + 45))
|
|
src="${SELF_BASE}.$((RANDOM % 3 + 5))"
|
|
echo "[external] UDP burst from $src"
|
|
for i in $(seq 1 50); do
|
|
echo "flood-$i" | nc -u -w 0 -s $src $INTERNAL_IP $((RANDOM % 10000 + 1024)) 2>/dev/null || true
|
|
done
|
|
done
|
|
}
|
|
|
|
# Launch all traffic generators in background
|
|
http_traffic &
|
|
ssh_traffic &
|
|
dns_traffic &
|
|
udp_traffic &
|
|
tcp_traffic &
|
|
icmp_traffic &
|
|
syn_scan &
|
|
udp_burst &
|
|
|
|
echo "[external] All traffic generators running"
|
|
wait
|