4.5 KiB
Robovoice DHCP Tunnel Protocol
Overview
Robovoice communicates with a remote STT server by tunneling through the DHCP UDP ports (68→67). This exploits a common killswitch exception: VPN software (e.g. WireGuard) blocks all traffic except DHCP, which is allowed for network connectivity maintenance.
[Robovoice client] --broadcast UDP :68→:67--> [STT server]
[Robovoice client] <--unicast UDP :67→:68-- [STT server]
The client broadcasts NOP heartbeats while PTT is held. The server starts recording on the first NOP and stops when it receives OFF or when 150ms pass with no NOPs.
Transport
- Protocol: UDP (connectionless, unreliable)
- Client → Server: broadcast, source port 68, dest port 67
- Server → Client: unicast, source port 67, dest port 68
- Client binds: to a specific LAN interface IP on port 68 (with
SO_REUSEADDRto coexist with the Windows DHCP service) - No connection state — purely fire-and-forget datagrams
Wire format
All messages are plain text, newline-terminated (\n). Every message starts
with the 6-byte magic HKMSTR to distinguish our traffic from real DHCP.
Client → Server
NOP (heartbeat while PTT held):
HKMSTR <nonce>\n
Sent every 50ms while PTT is held. The nonce is an incrementing unsigned integer that makes each datagram unique. The server discards it — it's purely for packet uniqueness, not for any protocol logic.
OFF (PTT released):
HKMSTR:OFF <nonce>\n
Sent once when PTT is released. This is the fast-stop signal. If lost, the 150ms timeout acts as a backstop.
Server → Client
Partial transcript:
HKMSTR:P <text>\n
Intermediate recognition result. Fire-and-forget. Client logs it but does not act on it.
Final transcript:
HKMSTR:F <text>\n
Complete utterance. Client feeds this to the TTS engine.
Server state machine
┌──────────────────────────────────────────┐
│ │
▼ │
┌──────────┐ first NOP ┌──────────────┐ │
│ IDLE │ ──────────► │ RECORDING │ │
└──────────┘ └──────────────┘ │
│ │ │
OFF │ │ 150ms │
recv'd │ │ silence │
▼ ▼ │
┌─────────────┐ │
│ PROCESSING │ │
└─────────────┘ │
│ │
STT │ │
done │ │
▼ │
send HKMSTR:F ─────────┘
- IDLE → RECORDING: first NOP received, start mic capture
- RECORDING → PROCESSING: OFF received, OR 150ms since last NOP
- PROCESSING → IDLE: STT done, send
HKMSTR:F <text>
Timing
| Parameter | Value | Purpose |
|---|---|---|
| NOP interval | 50ms | Heartbeat frequency while PTT held |
| Silence timeout | 150ms | Stop recording if no NOPs (3 missed = lost OFF) |
| NOP bandwidth | ~20 msg/s × ~20 bytes | ~400 bytes/s — negligible |
Why this works
- Outbound broadcast
:68→:67to255.255.255.255passes the WireGuard WFP killswitch (DHCP exception matches this exact pattern) - Inbound
:67→:68has no address restriction in the WFP rule, so unicast replies pass through - Binding to a specific interface IP (not
0.0.0.0) wins unicast delivery over the Windows DHCP client service - NOP spam ensures the ON message gets through even at 5% packet loss (3 consecutive NOPs = ~0.01% drop probability)
- 150ms timeout is the backstop for lost OFF — at 50ms intervals, 3 consecutive NOPs must all be lost to false-stop