You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Merge feature/multiprotocol: multi-protocol support
Adds SSH, Telnet, SMTP, RDP, FTP, SIP, SMB, MAIL honeypot support
with protocol switcher, per-protocol leaderboards, Proto Stats pane,
classic mode for single-protocol servers, and ?show= URL filtering.
Preserves blocklist features from master.
Copy file name to clipboardExpand all lines: CLAUDE.md
+85-43Lines changed: 85 additions & 43 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
4
4
5
5
## Project Overview
6
6
7
-
Knock-Knock is an SSH honeypot monitoring system that captures unauthorized SSH login attempts and displays real-time attack data through a live web dashboard. It can be deployed via Docker or as two coordinated systemd services.
7
+
Knock-Knock is a multi-protocol honeypot monitoring system that captures unauthorized login attempts on SSH (port 22), Telnet (port 23), and SMTP (port 587), and displays real-time attack data through a live web dashboard. It can be deployed via Docker or as two coordinated systemd services.
8
8
9
9
## Commands
10
10
@@ -32,10 +32,12 @@ docker compose logs -f
32
32
```bash
33
33
source .venv/bin/activate
34
34
35
-
# SSH honeypot (port 22)
36
-
python honeypot.py
35
+
# Individual honeypots (ports 22, 23, 587)
36
+
python ssh_honeypot.py
37
+
python telnet_honeypot.py
38
+
python smtp_honeypot.py
37
39
38
-
# Log monitor + geo-enricher — spawns honeypot.py as a subprocess
40
+
# Log monitor + geo-enricher — spawns all three honeypots as subprocesses
39
41
# Add --save-knocks to store individual knocks in SQLite
40
42
python monitor.py
41
43
@@ -64,43 +66,55 @@ sqlite3 data/knock_knock.db "SELECT * FROM knocks ORDER BY id DESC LIMIT 10;"
64
66
65
67
# Redis connectivity
66
68
redis-cli ping
69
+
70
+
# Check per-protocol feed lists
71
+
redis-cli llen knock:recent:ssh
72
+
redis-cli llen knock:recent:tnet
73
+
redis-cli llen knock:recent:smtp
74
+
75
+
# Watch for SMTP connections (even without AUTH — honeypot logs every connect)
-`honeypot.py` + `monitor.py`: Combined into a single systemd unit. Monitor spawns honeypot as a subprocess and reads its stdout. Performs GeoIP lookups, updates intel tables in SQLite, publishes to Redis. Individual knocks are only saved to SQLite with `--save-knocks`. Honeypot checks`knock:blocked` Redis set on each connection to reject blocked IPs instantly.
85
-
-`main.py`: FastAPI server with WebSocket endpoint `/ws`, subscribes to Redis, broadcasts to all connected browsers
94
+
-`monitor.py`: Spawns all three honeypots as subprocesses, merges their stdout via a shared `queue.Queue`, performs GeoIP lookups, updates SQLite intel tables, publishes to Redis. Individual knocks saved to SQLite only with `--save-knocks`. Honeypots check`knock:blocked` Redis set on each connection to reject blocked IPs instantly.
95
+
-`main.py`: FastAPI server with WebSocket endpoint `/ws`, subscribes to Redis, broadcasts to all connected browsers.
86
96
87
97
**Data Flow:**
88
-
- Monitor spawns honeypot as a subprocess and reads its stdout (both systemd and Docker)
98
+
- Monitor spawns honeypots as subprocesses and reads their stdout (both systemd and Docker)
user_intel_proto(username, proto INTEGER, hits, last_seen) -- INDEX on (proto, hits DESC)
167
+
pass_intel_proto(password, proto INTEGER, hits, last_seen) -- INDEX on (proto, hits DESC)
168
+
country_intel_proto(iso_code, proto INTEGER, country, hits, last_seen)
169
+
isp_intel_proto(isp, proto INTEGER, hits, last_seen, asn)
170
+
ip_intel_proto(ip, proto INTEGER, hits, last_seen, lat, lng)
141
171
142
172
-- Uptime tracking for KPM calculation
143
-
monitor_heartbeats(id, timestamp)
173
+
monitor_heartbeats(id, uptime_minutes)
144
174
```
145
175
146
-
Intel tables are updated on each knock via `INSERT ... ON CONFLICT DO UPDATE`. Top-N queries use the hits index (~100 rows) instead of GROUP BY on knocks (all rows).
147
-
148
-
## External Dependencies
149
-
150
-
- Redis server (localhost:6379 or via `REDIS_HOST` env var)
151
-
- GeoIP databases at `/usr/share/GeoIP/GeoLite2-{City,ASN}.mmdb`
152
-
- SSL certificates in `certs/` directory (optional, for HTTPS)
153
-
- Python 3.12 with `uv` virtual environment (systemd) or Docker
176
+
Each knock writes 10 upserts: 5 to ALL tables + 5 to `_proto` tables. ALL tables serve as fast rollup for the ALL leaderboard; `_proto` tables serve per-protocol leaderboards.
154
177
155
178
## Redis Keys
156
179
157
-
-`knock:total_global` - Total attack count
180
+
-`knock:total_global` - Total attack count (all protocols)
181
+
-`knock:uptime_minutes` - Monitor uptime in minutes
158
182
-`knock:last_time` - Unix timestamp of last knock
159
183
-`knock:last_lat` - Latitude of last knock location
160
184
-`knock:last_lng` - Longitude of last knock location
161
-
-`knock:recent` - Last 100 knocks (JSON list, used for initial page load)
185
+
-`knock:recent` - Last 100 knocks, all protocols (JSON list)
186
+
-`knock:recent:ssh` - Last 100 SSH knocks
187
+
-`knock:recent:tnet` - Last 100 Telnet knocks
188
+
-`knock:recent:smtp` - Last 100 SMTP knocks
162
189
-`knock:blocked` - Set of blocked IPs (seeded from `blocklist.txt` on startup; checked by honeypot on each connection)
163
190
-`radiation_stream` - Pub/sub channel for real-time events
164
191
192
+
## Globe Rendering Rules
193
+
194
+
The pane globes are paused when idle (`pauseAnimation()`). **Any change to globe scene state (polygon data, point data, styles) will NOT be visible until the animation loop runs a frame.** Always follow scene changes with:
195
+
```javascript
196
+
if (paneGlobeDesktop &&paneGlobeVisible.desktop) paneGlobeDesktop.resumeAnimation();
197
+
if (paneGlobeMobile &&paneGlobeVisible.mobile) paneGlobeMobile.resumeAnimation();
198
+
schedulePaneGlobePause();
199
+
```
200
+
`refreshHeatGlobe()` and `applyGlobeStyle()` already do this. Any new function that modifies pane globe state must too.
201
+
202
+
Additionally, `polygonsData(sameRef)` may be short-circuited by globe.gl — always pass `[...countriesData]` to guarantee the polygon digest runs and accessor functions are re-evaluated.
203
+
165
204
## Frontend Features
166
205
167
-
-**3D Globe** (globe.gl): Displays attack location, rotates on new knocks; includes heat map mode
168
-
-**Live Feed**: Real-time attack log with username/password/location
169
-
-**Leaderboards**: Top countries, usernames, passwords, ISPs, IPs
206
+
-**3D Globe** (globe.gl): Displays attack location, rotates on new knocks; heat map mode extrudes countries by hit count
207
+
-**Protocol Filter**: Cycles ALL → SSH → TNET → SMTP → ALL; filters live feed, leaderboards, globe rotation, and heat map
208
+
-**Live Feed**: Real-time attack log with protocol badge, username/password/location
209
+
-**Leaderboards**: Top countries, usernames, passwords, ISPs, IPs — per-protocol or ALL
170
210
-**Trivia & Jokes**: Context about why usernames/passwords are chosen, plus knock-knock jokes
171
211
-**Sound Effects**: Optional audio notifications for new knocks
172
212
-**About**: Project info section
213
+
-**Classic Mode**: Automatically activates when only one protocol is active — hides protocol switcher, cycle buttons, proto badges, proto chip pulses, and Proto Stats pane for a clean single-protocol UI. Header label changes from "Total Knocks" to "[PROTO] Knocks"
214
+
-**`?show` URL Parameter**: Subset which protocols are visible (e.g., `?show=SSH`, `?show=SSH,RDP`). Intersected with server's enabled protocols; invalid values fall back to all enabled. Single-protocol `?show` triggers classic mode. When filtered, header stats (total, KPM, ago) reflect only the active protocols, computed client-side from `protoBreakdownCache` and `lastKnockTimeByProto`
173
215
-**Debug Mode**: Overlay via `?debug` URL parameter
174
216
-**Responsive**: Mobile carousel with swipe navigation, desktop grid layout
175
217
-**WebSocket**: Auto-reconnect, live updates without polling
knock-knock.net (master) runs an SSH-only honeypot with a clean, focused UI — 11 panes, ~1,800 lines of frontend code. beta.knock-knock.net (feature/multiprotocol) extends this to 8 protocols (SSH, Telnet, SMTP, RDP, MAIL, FTP, SIP, SMB) with protocol cycling buttons, per-protocol leaderboards, protocol badges, and a Proto Stats pane — 12 panes, ~2,800 lines of frontend. The feature branch is 54 commits ahead; master has 0 commits not in feature (clean fast-forward).
6
+
7
+
The dilemma: the simple UI is elegant, the multiprotocol data is valuable, and maintaining two divergent codebases is unsustainable for a solo developer.
**Insight:** The multiprotocol frontend *already works identically to the classic view* when the protocol filter is on "ALL." The only visual differences are protocol cycle buttons, the Proto Stats pane, and protocol badges in the feed. When only one protocol is enabled, those elements are meaningless — so hide them automatically.
12
+
13
+
**The rule:** The frontend already receives `enabled_protocols` from the server on WebSocket connect. If `enabled_protocols.length === 1`, apply classic mode. If `> 1`, show the full multiprotocol UI. No toggles, no URL params, no user decisions — the UI adapts to the server config.
14
+
15
+
## Implementation
16
+
17
+
### Step 1: Merge feature/multiprotocol into master
2. Multi-protocol test: deploy with multiple protocols enabled → confirm full UI (cycle buttons, Proto Stats, badges all visible)
72
+
3. Single-protocol test: set `ENABLED_PROTOCOLS=SSH` in env → restart monitor → reload page → confirm classic mode (no cycle buttons, no Proto Stats pane, no protocol badges)
73
+
4. Mobile: confirm Proto Stats nav dot hidden in classic mode, swipe navigation still works correctly
74
+
5. Verify leaderboards still aggregate correctly in both modes
0 commit comments