arn-c0de / arn-c0de/ESP32-LABs
ESP32 Red/Blue Team Lab – Gameplay & Defense Mechanics
- Dominant language
- C++
- Stars
- 8
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
- Every lab shares identical defense mechanics, command syntax (iptables/tc/session-like), and JSON automation format.
- ESP32 acts as central simulated "server/host".
- **No real kernel-level changes**, no real packet filtering — everything is simulated at the application level (HTTP, WebSocket, Telnet, etc.).
- Purely **educational** — never use in production or on real/connected networks.
## Core Game Principles
- Blue Team cannot block everything → defenses cost **DP** (Defense Points) and reduce **SS** (Stability Score) when overused.
- Red Team must choose smart vectors and timing under **AP** (Actions Per round/window) constraints.
- Time-limited rounds + per-defense cooldowns create realistic pressure.
- All parameters (DP/AP/SS costs, durations, cooldowns) are **configurable** and **persist** across reboots.
## Core Concepts & Resources
| Resource | Meaning | Default | Notes |
|-------------------|--------------------------------------|---------|-------|
| DP | Defense Points budget | 100 | Spent when activating defenses |
| AP | Max actions per round / time window | 2 | Global limit on defense activations |
| SS | Stability Score (system health) | 100 | Reduced by aggressive/high-cost defenses |
## Supported Defenses
| Defense Type | Command Alias | DP Cost | AP Cost | Default Duration | Default Cooldown | Side Effects / Notes |
|-------------------|---------------|---------|---------|------------------|------------------|----------------------|
| IP Block | iptables DROP | 15 | 1 | 30 s | 60 s | Blocks all traffic from IP/subnet |
| Rate Limit | tc rate-limit | 10 | 1 | 60 s | 30 s | Limits requests per second from src |
| Session Reset | session reset | 25 | 1 | immediate | 90 s | Forces disconnect (closes WS/Telnet) |
| Mistrust Mode | mistrust mode | 40 | 2 | 300 s | 600 s | Log-only / observe mode + extra logging |
All values configurable via `defense config set ...`
## Command Interfaces
### Human-readable (single-line, iptables/tc/session style)
Examples:
```bash
# Add IP block
iptables -A INPUT -s 192.168.4.100 -j DROP --duration 30 --dp 15 --ap 1 --id req-01
# Remove by id
iptables -D INPUT -s 192.168.4.100 -j DROP --id req-01
# Rate limit subnet to 10 req/s
tc qdisc add rate-limit --src 192.168.4.0/24 --rps 10 --duration 60 --dp 10 --id req-02
# Delete rate limit rule
tc qdisc del rate-limit --src 192.168.4.0/24 --id req-02
# Force session reset
session reset --ip 192.168.4.101 --reason "suspect" --dp 25 --id req-03
# Show rules
iptables -L
tc qdisc show
# Config management
defense status
defense config set dp=80 ap=3 stability=90
defense config show
```
### JSON (single-line, machine-readable)
**Add IP block example** (one line):
```json
{"action":"add","type":"ipblock","chain":"INPUT","src":"192.168.4.100","jump":"DROP","duration":45,"dp":15,"ap":1,"id":"req-17"}
```
**Remove example**:
```json
{"action":"del","type":"ipblock","id":"req-01"}
```
**Config example**:
```json
{"action":"config","set":{"dp":90,"ap":2,"stability":85}}
```
**Typical response** (mirror input style — human or JSON):
Human:
```
Rule req-01 added: DROP from 192.168.4.100 for 30s (DP-15, AP-1)
```
JSON:
```json
{"status":"ok","id":"req-01","message":"Rule added","remaining_dp":85,"remaining_ap":1}
```
Error example:
```json
{"status":"error","code":"insufficient_dp","message":"Need 15 DP, only 10 remaining"}
```
## Implementation Outline (15_Defense.ino)
### Main Classes / Structures
```cpp
// In 15_Defense.h / .ino
#include
#include
#include
#include
enum DefenseType { IP_BLOCK, RATE_LIMIT, SESSION_RESET, MISTRUST_MODE };
struct DefenseRule {
String id; // unique request id
DefenseType type;
IPAddress src; // or subnet start
uint8_t subnet; // CIDR (0 = single IP)
String jump; // DROP, REJECT etc (mostly cosmetic)
uint32_t startTime;
uint32_t duration; // seconds (0 = permanent, rare)
uint32_t cooldownEnd; // when rule can be re-added
uint8_t dpCost;
uint8_t apCost;
String reason; // for session reset
// ... rate limit specific fields (rps etc)
};
class DefenseManager {
public:
bool begin();
bool applyDefense(const String &cmdLine); // human or JSON
bool removeDefense(const String &id);
bool isIpBlocked(IPAddress ip);
bool checkRateLimit(IPAddress ip); // returns true = allow
void forceSessionReset(IPAddress ip, const String &reason);
void tick(); // call from main loop ~every second
String getStatusHuman();
String getStatusJson();
void loadConfig();
void saveConfig();
// config values
int dpRemaining = 100;
int apPerWindow = 2;
int stability = 100;
// ... per-type defaults/cooldowns
private:
std::vector activeRules;
std::set recentIds; // last N for idempotency (~50)
Preferences prefs;
// helper parsers
bool parseHumanCommand(const String &line);
bool parseJsonCommand(const String &line);
bool canAfford(uint8_t dp, uint8_t ap);
void deductCosts(uint8_t dp, uint8_t ap);
void broadcastEvent(const String &msg); // ws.textAll + Serial
};
```
### Integration Points
1. **Serial command handler** (`12_Debug.ino`):
```cpp
void handleSerialCommands() {
if (Serial.available()) {
String line = Serial.readStringUntil('\n');
line.trim();
if (line.length() == 0) return;
if (line.startsWith("{")) {
// JSON → DefenseManager → JSON reply
String reply = defenseManager.applyDefense(line) ? ... : ...;
Serial.println(reply);
} else {
// human command → DefenseManager → human reply
String reply = defenseManager.applyDefense(line);
Serial.println(reply);
}
}
}
```
2. **Enforcement hooks** (application layer only):
- `03_WebServer.ino` — in request handler (early):
```cpp
if (defenseManager.isIpBlocked(client.remoteIP())) {
client.send(403, "text/plain", "Blocked by defense rule");
return;
}
if (!defenseManager.checkRateLimit(client.remoteIP())) {
// throttle or 429
}
```
- `07_WebSocket.ino` — on new connection / message:
Similar IP block / rate limit check → close if needed.
- `08_Telnet.ino` — on connect / before command:
Block or reset session.
3. **Tick loop** (main `loop()` or timer):
```cpp
static uint32_t lastTick = 0;
if (millis() - lastTick >= 1000) {
defenseManager.tick(); // expire rules, cooldowns, etc.
lastTick = millis();
}
```
4. **Persistence**:
- **Preferences**: store scalars (`dp`, `ap`, `stability`, per-type defaults)
- **LittleFS**: `/defense.json` — full rules + recent ids (atomic write: write to temp → rename)
5. **Idempotency**:
Store last 50–100 ids. If `id` already seen → ignore or reply "already processed".
6. **Events**:
```cpp
void DefenseManager::broadcastEvent(const String &msg) {
ws.textAll(msg); // if WebSocket active
Serial.println("[DEF] " + msg);
}
```
## Safety & Ethics Reminders (README)
- **Simulation only** — application-layer checks, **no** real firewall/tc/iptables.
- **Isolated network required** — never connect lab ESP32s to internet or shared LAN.
- Educational purpose: classrooms, CTF-style labs, red/blue exercises.
- Explicit warning: do **not** use outside controlled environments.
Contributor guide
Research direction
Start by reading the proposed DefenseManager in 15_Defense.h/.ino, then trace command handling in 12_Debug.ino and enforcement hooks in 03_WebServer.ino, 07_WebSocket.ino, and 08_Telnet.ino. Done means the simulated defenses, human and JSON commands, resource limits, ticking, persistence, idempotency, events, and safety guidance work together without real kernel or packet-filtering changes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- arduino, cpp
- Domain
- embedded-iot, game-dev, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100