Files
esp32-hacking/tools/esp-cmd
user 2586234473 feat: Add HMAC command auth, deauth flood detection, sign all tools
Firmware:
- HMAC-SHA256 command authentication (AUTH command, NVS persisted)
- Deauth flood detection with ring buffer and aggregate ALERT_DATA
- FLOODTHRESH command (count + window, NVS persisted)
- New STATUS fields: auth=on/off, flood_thresh=5/10
- mbedtls dependency in CMakeLists.txt, rx_buf increased to 192

Tools:
- esp-cmd/esp-fleet/esp-ota import sign_command from esp_ctl.auth
- Commands auto-signed when ESP_CMD_SECRET env var is set

Docs:
- CHEATSHEET: AUTH, FLOODTHRESH, HMAC auth, OUI, watch, osint sections
- TASKS: v1.3 completed section with all new features
2026-02-04 21:07:00 +01:00

68 lines
1.8 KiB
Python
Executable File

#!/usr/bin/env python3
"""Send management commands to ESP32 CSI devices over UDP."""
import socket
import sys
from esp_ctl.auth import sign_command
DEFAULT_PORT = 5501
TIMEOUT = 2.0
USAGE = """\
Usage: esp-cmd <host> <command> [args...]
Host can be an IP address or mDNS hostname (e.g., amber-maple.local).
Commands:
STATUS Query device state (uptime, heap, RSSI, tx_power, rate)
REBOOT Restart the ESP32
IDENTIFY Blink LED solid for 5 seconds
RATE <10-100> Set ping frequency in Hz (saved to NVS)
POWER <2-20> Set TX power in dBm (saved to NVS)
Examples:
esp-cmd amber-maple.local STATUS
esp-cmd 192.168.129.30 RATE 50
esp-cmd amber-maple.local IDENTIFY"""
def resolve(host):
"""Resolve hostname to IP address (supports mDNS .local)."""
try:
result = socket.getaddrinfo(host, DEFAULT_PORT, socket.AF_INET, socket.SOCK_DGRAM)
return result[0][4][0]
except socket.gaierror as e:
print(f"ERR: cannot resolve {host}: {e}", file=sys.stderr)
sys.exit(1)
def main():
if len(sys.argv) < 3 or sys.argv[1] in ("-h", "--help"):
print(USAGE)
sys.exit(0 if sys.argv[1:] and sys.argv[1] in ("-h", "--help") else 2)
host = sys.argv[1]
cmd = sign_command(" ".join(sys.argv[2:]).strip())
ip = resolve(host)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(TIMEOUT)
try:
sock.sendto(cmd.encode(), (ip, DEFAULT_PORT))
data, _ = sock.recvfrom(512)
print(data.decode().strip())
except socket.timeout:
print(f"ERR: no reply from {host} ({ip}:{DEFAULT_PORT}), timeout {TIMEOUT}s", file=sys.stderr)
sys.exit(1)
except OSError as e:
print(f"ERR: {e}", file=sys.stderr)
sys.exit(1)
finally:
sock.close()
if __name__ == "__main__":
main()