e523398fa8
- apps/device-agent-embedded/: ESP32 WireGuard agent (C, ESP-IDF, mbedTLS) - reference/namespace-vrf/: Linux namespace/VRF network isolation docs - apps/android-agent: VPN permission check, StartResult sealed class
4.3 KiB
4.3 KiB
PROJECT KNOWLEDGE BASE
Generated: 2026-06-26
Repository: nexus-agent-embedded
OVERVIEW
NexusGuard Embedded Agent: ESP32-based WireGuard client for IoT/edge devices. Runs on FreeRTOS + ESP-IDF, connects to NexusGuard Server Core via HTTP provisioning + heartbeat, manages WireGuard tunnel via lwIP stack.
STRUCTURE
nexus-agent-embedded/
├── main/
│ ├── main.c # Entry point, initialization
│ ├── provision.c/.h # HTTP provisioning (POST /api/v1/provision)
│ ├── heartbeat.c/.h # HTTP heartbeat loop (POST /api/v1/heartbeat)
│ ├── tunnel.c/.h # WireGuard tunnel management via lwIP
│ ├── crypto.c/.h # AES-256-GCM decrypt (mbedtls)
│ ├── config.c/.h # NVS config storage
│ └── wifi.c/.h # WiFi STA management
├── components/
│ └── wireguard-esp32/ # WireGuard library (lwIP-based)
├── docs/
│ ├── DESIGN.md # Technical design document
│ ├── API_COMPAT.md # Server API compatibility
│ └── HARDWARE.md # ESP32/LW840X hardware reference
├── CMakeLists.txt # ESP-IDF build system
├── sdkconfig.defaults # ESP-IDF configuration
├── AGENTS.md # This file
└── README.md
API PROTOCOL (Shared with Server)
Provisioning
- Endpoint:
POST /api/v1/provision - Request:
{ "token": "string", "hwid": "string" } - Response:
{ "encrypted_config": "base64-bytes" } - ConfigPayload (decrypted): device_id, private_key, preshared_key, internal_ip, server_pub, endpoint, dns, allowed_ips, server_wg_ip
Heartbeat
- Endpoint:
POST /api/v1/heartbeat - Request:
{ "device_id": "UUID", "status": "connected|recovering|stopped", "tunnel_up": bool, "last_handshake": "ISO8601" } - Response: Full config sync (same fields as ConfigPayload + forwards_hash)
- Interval: 30 seconds
Crypto
- Algorithm: AES-256-GCM
- Key Derivation: SHA256(hwid + salt)
- Format: nonce (12 bytes) + ciphertext
- Implementation: mbedtls (built-in ESP-IDF)
HARDWARE PLATFORM
Target: ESP32 (LW840X)
- MCU: ESP32 Xtensa LX7 dual-core
- RAM: 320KB SRAM
- Flash: 4MB
- WiFi: 802.11 b/g/n
- OS: FreeRTOS via ESP-IDF
- Network Stack: lwIP
Build Toolchain
- ESP-IDF: v5.2+
- Compiler: Xtensa GCC
- Build System: CMake
- Debug: JTAG + OpenOCD
CONVENTIONS
Code Style
- C99 standard
- Snake_case for functions and variables
- UPPER_SNAKE_CASE for macros and constants
- Doxygen-style comments for public API
- Error handling: return esp_err_t or NULL on failure
Memory Management
- Use
heap_caps_malloc(MALLOC_CAP_SPIRAM)for large buffers - Free all allocated memory in error paths
- No static buffers > 1KB on stack
Network
- Use
esp_http_clientfor HTTP requests - Timeout: 10s connect, 30s read
- Retry: 3 attempts with exponential backoff
- TLS: Skip verify for now (internal network only)
Storage
- NVS namespace: "nexusguard"
- Keys: "device_id", "private_key", "preshared_key", "internal_ip", "server_pub", "endpoint", "dns", "allowed_ips"
- Max key size: 15 chars (NVS limit)
ANTI-PATTERNS
- NEVER store WireGuard keys in plaintext on flash (always encrypted via NVS)
- NEVER use
printffor sensitive data (keys, tokens) - NEVER hardcode WiFi credentials (use menuconfig or provisioning)
- NEVER block main task for > 100ms (use timers or tasks)
- NEVER use
malloc()in interrupt context
COMMANDS
# Build
idf.py set-target esp32
idf.py build
# Flash & Monitor
idf.py -p /dev/ttyUSB0 flash monitor
# Clean
idf.py fullclean
# Menuconfig
idf.py menuconfig
DEPENDENCIES
- ESP-IDF: v5.2+ (framework)
- mbedtls: AES-256-GCM, SHA-256 (built-in)
- lwIP: TCP/IP stack (built-in)
- FreeRTOS: RTOS (built-in)
- wireguard-esp32: WireGuard tunnel library (component)
NOTES
- ESP32 uses FreeRTOS, NOT Zephyr RTOS
- lwIP is the network stack, NOT kernel networking
- WireGuard runs in userspace via lwIP socket API
- Config is stored in NVS (flash), not filesystem
- No gRPC support (too heavy for ESP32) — HTTP only
- No port forwarding (userspace agent only)
- Agent version: 1.0.0 (initial release)