mirror of
https://github.com/DaLaw2/NetGuardia.git
synced 2026-08-24 14:10:28 +09:00
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| 6c5641c3d8 | feat: update BYO pipeline model support (#21) | |||
| 84a1c29e1e | Refactor backend architecture and code organization (#20) | |||
|
|
d47d08d79e |
feat: RBAC, clippy fixes, frontend CI, integration test (#16)
* feat: SQLite persistence for ACL, rate limit, DNS, and GeoIP rules Add rusqlite with WAL mode for persisting all security rules. On startup, load persisted state into eBPF maps. On API writes, persist to DB alongside eBPF updates (DB-first for crash safety). Tables: users, acl_rules, rate_limit_config, dns_blacklist, geo_blocked_countries, settings. Database module uses parking_lot Mutex for thread-safe access. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: JWT authentication with RBAC and default admin Auth: JWT token-based authentication with argon2 password hashing. Auto-generated secret persisted in SQLite settings table. Middleware validates Bearer tokens on all /api/* endpoints except /api/auth/login. RBAC: admin (all operations) and viewer (GET only). Default admin user created on first run (password: "admin", logged as warning). Endpoints: POST /api/auth/login, POST /api/auth/register (admin only), GET /api/auth/me. WebSocket endpoints validate ?token= query parameter. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: Ed25519 license validation and generator Validator (net-guardia): Reads license.key (base64 payload + signature), verifies Ed25519 signature against embedded public key, checks expiry. Optional — missing license logs warning, invalid/expired fails startup. GET /api/system/license exposes license info. Generator (license-generator): Standalone crate, not in workspace. Subcommands: keygen (Ed25519 keypair), issue (sign license with device_id/expires/features), verify (check license file). Public key placeholder (all zeros) — replace after running keygen. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: security hardening, monitor mode, SMTP reports, XDP fallback, tests & deploy tooling - Security: force password change on first login, auth input validation (password ≥8 chars, username alphanumeric), login rate limiting (5 failures → 15min lockout), change-password API endpoint - DB: From<rusqlite::Error> trait impl eliminates ~20 duplicated map_err calls - XDP: fallback chain DRV_MODE → SKB_MODE → clear error with supported NIC list - Monitor mode: enforce_mode setting (monitor/enforce) with GET/PUT API - CORS: switched from hardcoded localhost to permissive for appliance deployment - Email: SMTP weekly report module (lettre) with HTML template and cron scheduler - Health: disk usage monitoring with >90% warning and >95% critical alerts - System API: XDP mode reporting, enforce mode toggle endpoints - Tests: 19 unit tests covering DB CRUD, JWT lifecycle, password hashing, license date calculations, and login lockout - Deploy: setup wizard (bash/whiptail), systemd service with watchdog, logrotate config, Packer VM template (OVA + QCOW2) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: hexagonal architecture with ports, adapters, and CQRS event bus - Architecture: reorganize into hexagonal layers (interface/, adapter/, infrastructure/) with strict unidirectional dependency rules - interface/communication: CQRS message bus (Command, Query, Event traits) adapted from MirrorSphere's CommunicationManager pattern - interface/port: define 5 port traits (RepositoryPort, AuthPort, HealthPort, NotificationPort, PacketProcessorPort) for dependency inversion - infrastructure: extract ServiceFactory and HttpServer from God Object (system.rs reduced from 503 to ~120 lines), add CommunicationManager - adapter/http: move web/api/ handlers, use dyn RepositoryPort trait objects instead of concrete Database type - adapter/websocket: move web/websocket/ handlers + route definitions - adapter/persistence: move core/database/, implement RepositoryPort trait - Fix layer violations: model/ no longer imports core/, adapters don't cross-import each other - Define 10 command types, 8 query types, 6 event types for subsystem communication - Add 10 new tests (29 total): CommunicationManager dispatch (9 tests), RepositoryPort trait object verification (1 test) Dependency rules enforced: model/ → (no imports from other layers) interface/ → model/ only adapter/ → interface/ + model/ (no cross-adapter imports) infrastructure/ → all layers (composition root) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: rename MLService to AppServices and move to infrastructure/ MLService was misleadingly named — it held SystemHealth and FlowStatistics alongside ML components. Renamed to AppServices and moved from core/infrastructure/ to infrastructure/ where service orchestration belongs in the hexagonal architecture. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: move core/infrastructure/ to infrastructure/, fix layer violations - Move app_config, health, statistics, geoip from core/infrastructure/ to infrastructure/ — completes hexagonal layer separation - Rename MLService to AppServices (name reflected actual contents: health, statistics, ML engine, not just ML) - Fix core/ → adapter/ dependency violations: jwt.rs, email/scheduler.rs, email/report.rs now use dyn RepositoryPort trait instead of concrete Database - Move misplaced data types to model/: - Claims → model/auth.rs - AlertMessage → model/ml_detection.rs - LicensePayload + LicenseInfo → model/license.rs - DropEventMessage + DropCounters → model/drop_event.rs - InferenceConfig (ML JSON) → model/config.rs as MLInferenceConfig - Wire CommunicationManager: enforce mode flow now goes through CQRS (ChangeEnforceModeCommand + GetEnforceModeQuery via EnforceModeHandler) - Add GitHub Actions CI workflow (cargo check + test + clippy) - Add 9 new tests (38 total): enforce mode handler (3), auth validation (6) - core/ now contains only business logic with no adapter imports (except #[cfg(test)] blocks which need concrete types) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: update frontend submodule to feat/ml-page branch Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: frontend overhaul, design system, CI fix Frontend (submodule update): - JWT authentication with login page and route protection - WebSocket refactor: 26 connections → 4 with subscription filtering - All API paths migrated from /ebpf/ to /api/ with JWT headers - 6 new pages: drops, geo-block, dns-filter, rate-limit, protocol-filter, system settings - 3-group sidebar navigation (監控/安全/系統) - Updated all existing pages to new backend API Design system: - DESIGN.md: Industrial/Utilitarian aesthetic, Geist + JetBrains Mono, Slate palette, compact spacing, accessibility specs - CLAUDE.md: design system reference for future work - TODOS.md: implementation tracking CI fix: - Add Node.js 22 setup + npm install for frontend build in build.rs - Fix bpf-linker resolution: find_bpf_linker() in net-guardia/build.rs resolves path and passes via CARGO_TARGET_BPFEL_UNKNOWN_NONE_LINKER env var to eBPF subprocess (no more PATH guessing) - Add which crate to net-guardia build-dependencies - Force-install bpf-linker to avoid stale cache false positive - Set stable as default toolchain so clippy runs on stable - Make ingress/egress-ebpf build.rs non-fatal on which() failure Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: clean image names, gitignore project docs, frontend design review - deploy: add explicit image names (netguardia, netguardia-router, netguardia-endpoint) - gitignore: exclude CLAUDE.md, DESIGN.md, TODOS.md from tracking - frontend: Toast system, skeleton loading, mobile sidebar, a11y, cross-nav links Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: update frontend submodule — UX fixes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: RBAC user groups, permission middleware, account management APIs Backend: - User groups with junction table (user_group_members) - Permission-based middleware replacing role-based (viewer=GET only) - Permissions resolved as union of all user's group permissions - Default groups: Administrator (all perms) + Viewer (read-only) - Auto-migration: seed groups + assign existing users on first run - User management APIs: list, delete, reset-password - Group management APIs: CRUD + member assignment - Protected: admin account (no delete/group change), built-in groups (no edit/delete) - JWT claims include permissions array from groups Deploy: - setup.sh uses absolute path for compose file - config.toml: combined_queue_count=1 for veth interfaces Frontend submodule updated to include RBAC UI + i18n. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: resolve clippy errors, add frontend CI steps and integration test - Fix 10 clippy errors: type_complexity (add UserListItem/UserGroupTuple type aliases) and collapsible_if (collapse nested if-let chains) - Add frontend type check (tsc --noEmit) and build (next build) to CI - Move integration test script into repo at tests/integration_test.sh with hardcoded password removed (uses direct sudo instead) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: gitignore VERSION, CHANGELOG, and SQLite db files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: update frontend submodule — add CI pipeline Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: remove frontend CI from main repo (frontend has its own CI) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: update frontend submodule Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
ebc7edcead |
feat: symmetric hash, drop events, GeoIP/DNS, performance & bug fixes (#15)
* 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> |
||
|
|
24af672c41 | feat: Adjust project structure (#7) |