mirror of
https://github.com/DaLaw2/NetGuardia.git
synced 2026-08-24 14:10:28 +09:00
* 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>
179 lines
6.4 KiB
Bash
179 lines
6.4 KiB
Bash
#!/bin/bash
|
|
set -e
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
DEPLOY_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
COMPOSE_FILE="$DEPLOY_DIR/compose/podman-compose.yml"
|
|
|
|
if command -v podman-compose &>/dev/null; then
|
|
COMPOSE="podman-compose -f $COMPOSE_FILE"
|
|
RT="podman"
|
|
elif command -v docker &>/dev/null && docker compose version &>/dev/null 2>&1; then
|
|
COMPOSE="docker compose -f $COMPOSE_FILE"
|
|
RT="docker"
|
|
else
|
|
echo "ERROR: No container runtime found"
|
|
exit 1
|
|
fi
|
|
|
|
echo "=== Runtime: $RT ==="
|
|
echo "=== Kernel: $(uname -r) ==="
|
|
echo ""
|
|
|
|
echo "=== Building containers ==="
|
|
$COMPOSE build
|
|
|
|
echo "=== Starting containers ==="
|
|
$COMPOSE up -d
|
|
|
|
echo ""
|
|
echo "=== Containers running ==="
|
|
$RT ps --format "table {{.Names}}\t{{.Status}}" 2>/dev/null || $RT ps
|
|
|
|
get_pid() {
|
|
$RT inspect --format '{{.State.Pid}}' "$1"
|
|
}
|
|
|
|
mkdir -p /var/run/netns
|
|
|
|
EXT_PID=$(get_pid external)
|
|
INT_PID=$(get_pid internal)
|
|
RTR_PID=$(get_pid router)
|
|
NG_PID=$(get_pid netguardia)
|
|
ln -sf /proc/$EXT_PID/ns/net /var/run/netns/external
|
|
ln -sf /proc/$INT_PID/ns/net /var/run/netns/internal
|
|
ln -sf /proc/$RTR_PID/ns/net /var/run/netns/router
|
|
ln -sf /proc/$NG_PID/ns/net /var/run/netns/netguardia
|
|
|
|
# ============================================================
|
|
# Segment 1: external <-> router (10.10.1.0/24)
|
|
# Direct connection, no inspection needed
|
|
# ============================================================
|
|
echo ""
|
|
echo "=== Segment 1: external <-> router (10.10.1.0/24) ==="
|
|
|
|
ip link add ext-eth0 type veth peer name rtr-ext
|
|
ip link set ext-eth0 netns external
|
|
ip link set rtr-ext netns router
|
|
|
|
ip netns exec external ip link set lo up
|
|
ip netns exec external ip link set ext-eth0 up
|
|
ip netns exec external ip addr add 10.10.1.2/24 dev ext-eth0
|
|
for i in 3 4 5 6 7; do
|
|
ip netns exec external ip addr add 10.10.1.${i}/24 dev ext-eth0
|
|
done
|
|
ip netns exec external ip route add default via 10.10.1.1
|
|
|
|
ip netns exec router ip link set lo up
|
|
ip netns exec router ip link set rtr-ext up
|
|
ip netns exec router ip addr add 10.10.1.1/24 dev rtr-ext
|
|
|
|
echo " external: ext-eth0 10.10.1.{2-7}/24, gw 10.10.1.1"
|
|
echo " router: rtr-ext 10.10.1.1/24"
|
|
|
|
# ============================================================
|
|
# Segment 2: router <-> netguardia <-> internal (10.10.2.0/24)
|
|
# NetGuardia inline: XDP on ng-ext (router side) and ng-int (internal side)
|
|
# No bridges, no inline veth pair — direct XSK forwarding
|
|
# ============================================================
|
|
echo ""
|
|
echo "=== Segment 2: router <-> [NetGuardia] <-> internal (10.10.2.0/24) ==="
|
|
|
|
# router <-> netguardia: ng-ext is the netguardia side
|
|
ip link add rtr-int type veth peer name ng-ext
|
|
ip link set rtr-int netns router
|
|
ip link set ng-ext netns netguardia
|
|
|
|
# netguardia <-> internal: ng-int is the netguardia side
|
|
ip link add int-eth0 type veth peer name ng-int
|
|
ip link set int-eth0 netns internal
|
|
ip link set ng-int netns netguardia
|
|
|
|
# Router internal side
|
|
ip netns exec router ip link set rtr-int up
|
|
ip netns exec router ip addr add 10.10.2.1/24 dev rtr-int
|
|
ip netns exec router sh -c 'echo 1 > /proc/sys/net/ipv4/ip_forward'
|
|
|
|
# Internal container
|
|
ip netns exec internal ip link set lo up
|
|
ip netns exec internal ip link set int-eth0 up
|
|
ip netns exec internal ip addr add 10.10.2.2/24 dev int-eth0
|
|
for i in 3 4 5 6; do
|
|
ip netns exec internal ip addr add 10.10.2.${i}/24 dev int-eth0
|
|
done
|
|
ip netns exec internal ip route add default via 10.10.2.1
|
|
|
|
# NetGuardia interfaces (no IP, transparent)
|
|
ip netns exec netguardia ip link set ng-ext up
|
|
ip netns exec netguardia ip link set ng-int up
|
|
|
|
# Disable checksum offload on ALL veth endpoints.
|
|
# AF_XDP TX bypasses the kernel stack, so checksums are not computed.
|
|
# Without this, TCP packets forwarded through XSK have bad checksums and get dropped.
|
|
ip netns exec router ethtool -K rtr-int tx off rx off 2>/dev/null || true
|
|
ip netns exec router ethtool -K rtr-ext tx off rx off 2>/dev/null || true
|
|
ip netns exec internal ethtool -K int-eth0 tx off rx off 2>/dev/null || true
|
|
ip netns exec external ethtool -K ext-eth0 tx off rx off 2>/dev/null || true
|
|
ip netns exec netguardia ethtool -K ng-ext tx off rx off 2>/dev/null || true
|
|
ip netns exec netguardia ethtool -K ng-int tx off rx off 2>/dev/null || true
|
|
|
|
echo " router: rtr-int (10.10.2.1) <-> ng-ext (XDP ingress)"
|
|
echo " netguardia: ng-ext <-> [XSK forwarding] <-> ng-int"
|
|
echo " internal: int-eth0 (10.10.2.{2-6}) <-> ng-int (XDP egress)"
|
|
echo " checksum offload disabled on all veth endpoints"
|
|
|
|
# ============================================================
|
|
# Verify
|
|
# ============================================================
|
|
echo ""
|
|
echo "=== Interfaces inside netguardia ==="
|
|
ip netns exec netguardia ip -br link show
|
|
|
|
echo ""
|
|
echo "=== Testing connectivity ==="
|
|
|
|
echo -n " external -> router: "
|
|
ip netns exec external ping -c 1 -W 2 10.10.1.1 >/dev/null 2>&1 && echo "OK" || echo "FAIL"
|
|
|
|
# Without net-guardia, traffic between router and internal won't pass
|
|
# because ng-ext/ng-int are just veth endpoints with no forwarding
|
|
echo -n " router -> internal: "
|
|
ip netns exec router ping -c 1 -W 2 10.10.2.2 >/dev/null 2>&1 && echo "OK" || echo "FAIL (expected - needs net-guardia)"
|
|
|
|
cat > /tmp/netguardia_interfaces.txt << IEOF
|
|
# NetGuardia interface mapping - realistic inline deployment
|
|
# Router handles L3 (10.10.1.0/24 <-> 10.10.2.0/24)
|
|
# NetGuardia inline on 10.10.2.0/24 (no IP, no bridge)
|
|
# ng-ext - XDP ingress (router side, attached to rtr-int peer)
|
|
# ng-int - XDP egress (internal side, attached to int-eth0 peer)
|
|
# XSK forwards packets: ng-ext RX -> ng-int TX and ng-int RX -> ng-ext TX
|
|
# Management: eth0 (10.10.3.10)
|
|
IEOF
|
|
$RT cp /tmp/netguardia_interfaces.txt netguardia:/root/NetGuardia/interfaces.txt 2>/dev/null || true
|
|
|
|
rm -f /var/run/netns/external /var/run/netns/internal /var/run/netns/router /var/run/netns/netguardia
|
|
|
|
echo ""
|
|
echo "=========================================="
|
|
echo " NetGuardia realistic inline deployment!"
|
|
echo ""
|
|
echo " external (10.10.1.{2-7})"
|
|
echo " |"
|
|
echo " [router] 10.10.1.1 <-> 10.10.2.1"
|
|
echo " | rtr-int"
|
|
echo " |"
|
|
echo " ng-ext (no IP) <- XDP ingress"
|
|
echo " |"
|
|
echo " [net-guardia XSK]"
|
|
echo " |"
|
|
echo " ng-int (no IP) <- XDP egress"
|
|
echo " |"
|
|
echo " | int-eth0"
|
|
echo " internal (10.10.2.{2-6})"
|
|
echo ""
|
|
echo " All 10.10.2.0/24 traffic requires net-guardia!"
|
|
echo " Mgmt: 10.10.3.10"
|
|
echo " SSH: ssh -p 2222 root@<host-ip>"
|
|
echo " Web: http://<host-ip>:8080"
|
|
echo "=========================================="
|