fix: stealth=true implies TLS+WebSocket; update public docs
This commit is contained in:
@@ -17,9 +17,12 @@ connection to a legitimate domain — not a VPN.
|
||||
3. **Konduit** receives a plain TCP connection and runs its normal handshake.
|
||||
Stealth mode must be **disabled** on the server side — HAProxy already handled TLS.
|
||||
|
||||
The `stealth = true` and `tls = true` config flags are equivalent. Both activate TLS
|
||||
wrapping on the client. Existing configs with `stealth = true` continue to work without
|
||||
modification.
|
||||
There are two client-side flags:
|
||||
|
||||
- **`tls = true`** — activates real TLS wrapping only (for the HAProxy TLS-termination model above)
|
||||
- **`[stealth] enabled = true`** — activates TLS **and** WebSocket camouflage (see [WebSocket mode](#websocket-camouflage-tspu--russia-bypass) below)
|
||||
|
||||
Use `tls = true` when HAProxy terminates TLS for you. Use `stealth = true` when the server handles TLS directly and you need WebSocket framing to bypass DPI.
|
||||
|
||||
## Server Requirements
|
||||
|
||||
@@ -99,18 +102,26 @@ echo "your-mantra" | ./konduit-ctl bootstrap \
|
||||
|
||||
## Client Configuration (`client.toml`)
|
||||
|
||||
For the HAProxy TLS-termination model (HAProxy decrypts TLS, konduit receives plain TCP):
|
||||
|
||||
```toml
|
||||
[client]
|
||||
server_endpoint = "your-domain.com:443"
|
||||
tls = true
|
||||
peer_id = "..."
|
||||
identity_key = "..."
|
||||
server_endpoint = "your-domain.com:443"
|
||||
tls = true
|
||||
peer_id = "..."
|
||||
identity_key = "..."
|
||||
server_public_key = "..."
|
||||
```
|
||||
|
||||
The legacy flag is identical:
|
||||
For WebSocket camouflage mode (konduit handles TLS and WebSocket end-to-end):
|
||||
|
||||
```toml
|
||||
[client]
|
||||
server_endpoint = "your-domain.com:443"
|
||||
peer_id = "..."
|
||||
identity_key = "..."
|
||||
server_public_key = "..."
|
||||
|
||||
[stealth]
|
||||
enabled = true
|
||||
```
|
||||
@@ -118,8 +129,8 @@ enabled = true
|
||||
## Flutter / Mobile App
|
||||
|
||||
Enable **Stealth Mode** in the app settings. The toggle maps to `stealth = true` in
|
||||
the connection config and activates TLS wrapping on all platforms (Linux, Android,
|
||||
Windows).
|
||||
the connection config and activates TLS + WebSocket camouflage on all platforms
|
||||
(Linux, Android, Windows).
|
||||
|
||||
For QR-code-based provisioning, the `t: true` field in the QR payload enables stealth.
|
||||
|
||||
@@ -136,11 +147,77 @@ curl -s https://your-domain.com/ | head -5
|
||||
journalctl -u haproxy -f
|
||||
```
|
||||
|
||||
## WebSocket Camouflage (TSPU / Russia Bypass) {#websocket-camouflage-tspu--russia-bypass}
|
||||
|
||||
Some ISPs (notably Russia's TSPU system) allow real TLS but still drop connections whose
|
||||
payload doesn't look like HTTP. WebSocket camouflage solves this: konduit protocol runs
|
||||
inside WebSocket binary frames over HTTPS, which TSPU whitelists (Telegram Web, online
|
||||
games, and countless other services use the same pattern).
|
||||
|
||||
```
|
||||
Client ──TLS 1.3──▶ HAProxy :443 (TCP passthrough) ──▶ Konduit :8443
|
||||
HTTP/1.1 GET /ws
|
||||
101 Switching Protocols
|
||||
WS binary frames (konduit protocol inside)
|
||||
```
|
||||
|
||||
HAProxy acts as a pure TCP proxy — it does **not** terminate TLS in this mode.
|
||||
|
||||
### Server (`server.toml`)
|
||||
|
||||
```toml
|
||||
[server]
|
||||
listen_addr = "0.0.0.0"
|
||||
listen_port = 8443
|
||||
public_addr = "your-domain.com"
|
||||
public_port = 443
|
||||
tls = true
|
||||
tls_cert = "/etc/letsencrypt/live/your-domain.com/fullchain.pem"
|
||||
tls_key = "/etc/letsencrypt/live/your-domain.com/privkey.pem"
|
||||
websocket = true
|
||||
```
|
||||
|
||||
### HAProxy (`haproxy.cfg`)
|
||||
|
||||
```haproxy
|
||||
frontend https-ingress
|
||||
bind *:443
|
||||
mode tcp
|
||||
default_backend konduit-vpn
|
||||
|
||||
backend konduit-vpn
|
||||
mode tcp
|
||||
timeout tunnel 0
|
||||
server konduit 127.0.0.1:8443
|
||||
```
|
||||
|
||||
`timeout tunnel 0` disables HAProxy's idle-connection timeout for established tunnels.
|
||||
Without it, connections are killed after 30 seconds of silence.
|
||||
|
||||
### Client (`client.toml`)
|
||||
|
||||
```toml
|
||||
[client]
|
||||
server_endpoint = "your-domain.com:443"
|
||||
peer_id = "..."
|
||||
identity_key = "..."
|
||||
server_public_key = "..."
|
||||
|
||||
[stealth]
|
||||
enabled = true
|
||||
```
|
||||
|
||||
`stealth = true` tells the client to use TLS and WebSocket framing. No other flags needed.
|
||||
|
||||
---
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
| Mistake | Effect | Fix |
|
||||
|---------|--------|-----|
|
||||
| `WAIT_END` in inspect rule | 5-second stall on every connect | Use `req.payload(0,1) -m found` |
|
||||
| Stealth enabled on server | Handshake mismatch after HAProxy strips TLS | Set `[stealth] enabled = false` |
|
||||
| Stealth enabled on server (HAProxy-TLS model) | Handshake mismatch after HAProxy strips TLS | Set `[stealth] enabled = false` on server |
|
||||
| `tls = true` instead of `stealth = true` on client | Connects but drops — no WebSocket framing | Use `[stealth] enabled = true` for TSPU bypass |
|
||||
| Missing `timeout tunnel 0` in HAProxy | Connection drops after 30 s of silence | Add `timeout tunnel 0` to backend |
|
||||
| Port 8443 exposed to internet | Bypass HAProxy, no DPI camouflage | Firewall port 8443 to localhost only |
|
||||
| Expired/self-signed cert | TLS error on client | Use Let's Encrypt; renew via certbot |
|
||||
|
||||
Reference in New Issue
Block a user