checkpoint: implement wgcloak v1 foundations
This commit is contained in:
commit
313ab00765
45 files changed
+12058
No files matched your search
@@ -0,0 +1,73 @@
|
||||
# Architecture
|
||||
|
||||
wgcloak is a single Linux userspace process with a `client` or `server` role.
|
||||
The core moves opaque datagrams between a local UDP socket and a transport
|
||||
session. It does not know whether the payload is WireGuard, DNS, or another UDP
|
||||
protocol.
|
||||
|
||||
```text
|
||||
CLIENT SERVER
|
||||
local UDP peer transport listener
|
||||
│ │
|
||||
▼ ▼
|
||||
local listener ── tunnel core ── transport ── authenticated session
|
||||
│
|
||||
▼
|
||||
dedicated connected UDP backend socket
|
||||
│
|
||||
▼
|
||||
configured UDP backend
|
||||
```
|
||||
|
||||
## Ownership boundaries
|
||||
|
||||
- The local listener receives datagrams and remembers the most recently active
|
||||
local peer for return traffic. One active peer per v1 tunnel is sufficient.
|
||||
- The core owns session lifecycle, limits, datagram-size checks, reconnect
|
||||
policy, and statistics. Payload bytes remain opaque.
|
||||
- A transport owns connection establishment and wire representation. Every
|
||||
transport exposes the same logical send/receive/close behavior and a maximum
|
||||
datagram size.
|
||||
- Authentication is a separate concern. Direct UDP uses the documented
|
||||
challenge/HMAC packet protocol; TLS-capable transports authenticate the
|
||||
client after transport establishment.
|
||||
- The server creates a backend UDP socket only after client authentication and
|
||||
maps that socket to one session. A backend response therefore has natural
|
||||
session ownership without inspecting the backend protocol.
|
||||
|
||||
## Transport lifecycle
|
||||
|
||||
The client state machine is:
|
||||
|
||||
```text
|
||||
STARTING → RESOLVING → PROBING → AUTHENTICATING → CONNECTED
|
||||
│ │
|
||||
└───────────┘ failure
|
||||
▼
|
||||
RECONNECTING
|
||||
│
|
||||
└→ PROBING
|
||||
```
|
||||
|
||||
In `auto` mode the target order is direct UDP, QUIC DATAGRAM, HTTP/3
|
||||
CONNECT-UDP, then TLS/TCP. Authentication rejection is a configuration error,
|
||||
not permission to probe indefinitely. Network failures use bounded exponential
|
||||
backoff with jitter.
|
||||
|
||||
## Server isolation
|
||||
|
||||
One malformed or unauthenticated packet must be rejected without terminating
|
||||
the listener or affecting another client. Server limits cover active sessions,
|
||||
per-source sessions, pending handshakes, handshake duration, authentication
|
||||
attempts, and maximum datagram size. Expiry closes the backend socket and
|
||||
releases replay/session state.
|
||||
|
||||
## Privileges and filesystem
|
||||
|
||||
Normal operation uses ordinary UDP/TCP/Unix sockets and needs no root,
|
||||
`CAP_NET_ADMIN`, or `CAP_SYS_ADMIN`. `CAP_NET_BIND_SERVICE` is optional when a
|
||||
reviewed deployment must bind a port below 1024. The control socket is local
|
||||
and protected by filesystem ownership/mode; it is not a network listener.
|
||||
|
||||
This document describes the intended v1 architecture. Check the milestone
|
||||
matrix before relying on a transport or control command in a particular build.
|
||||
@@ -0,0 +1,109 @@
|
||||
# Development state
|
||||
|
||||
Checkpoint: 2026-09-14, end of day. Development is paused at a compilable
|
||||
checkpoint; no commit was made.
|
||||
|
||||
## Branch and worktree
|
||||
|
||||
- Branch: `main`.
|
||||
- `git status --short` reports the project files as untracked, including
|
||||
`Cargo.toml`, `Cargo.lock`, `src/`, `tests/`, documentation, examples, and
|
||||
packaging files. There is no useful committed baseline to compare against in
|
||||
this checkout.
|
||||
- Multiple agents have been working in the shared directory. Review all diffs
|
||||
and ownership boundaries before committing; in particular, do not assume an
|
||||
untracked file was created by this task or that a concurrent edit is final.
|
||||
|
||||
## Implemented and wired behavior
|
||||
|
||||
The current tree contains the following work, subject to integration review:
|
||||
|
||||
- Operational assets: MIT `LICENSE`, Linux-focused `README.md`, `.gitignore`,
|
||||
client/server TOML examples, architecture/protocol/security/operations/
|
||||
troubleshooting documents, an implementation checklist, and systemd client
|
||||
and server templates.
|
||||
- TLS/TCP transport primitives in `src/transport/tls_tcp.rs`: bounded
|
||||
incremental/coalesced u16-big-endian framing, truncated/oversized-frame
|
||||
handling, PEM/DER certificate and private-key loading, challenge-response
|
||||
authentication, authenticated data/heartbeat/close framing, idle timeout,
|
||||
and bounded shutdown.
|
||||
- HTTP/3 support primitives in `src/transport/http3.rs`: CONNECT-UDP request
|
||||
validation, QUIC varints, RFC 9297 HTTP Datagram context encoding, capsule
|
||||
encoding, and project authentication messages. The module does not fake
|
||||
CONNECT-UDP with POST or ordinary streams.
|
||||
- Runtime orchestration in `src/transport/mod.rs`, `src/client/mod.rs`, and
|
||||
`src/server/mod.rs` instantiates direct UDP, QUIC, and TLS/TCP connectors or
|
||||
listeners. TLS backend creation occurs after the authenticated session is
|
||||
established. HTTP/3 currently returns an explicit `Unsupported` result from
|
||||
runtime selection because the actual h3 datagram adapter is not complete.
|
||||
- The client and server start the Unix control server. Client reconnect and
|
||||
reload commands currently cause a reconnect attempt; server shutdown is
|
||||
handled by the encrypted listener paths, while direct-UDP/control lifecycle
|
||||
still needs review.
|
||||
- `h3-quinn` was enabled with its `datagram` feature; `tokio-rustls` and
|
||||
`rustls-native-certs` were added for TLS runtime integration.
|
||||
|
||||
## Files changed in this work
|
||||
|
||||
Primary files touched by the operations/integration work are:
|
||||
|
||||
- `Cargo.toml`, `Cargo.lock`
|
||||
- `src/transport/mod.rs`
|
||||
- `src/transport/tls_tcp.rs`
|
||||
- `src/transport/http3.rs`
|
||||
- `src/client/mod.rs`
|
||||
- `src/server/mod.rs`
|
||||
- `tests/tls_tcp.rs`, `tests/http3.rs`, `tests/integration_transports.rs`
|
||||
- `.gitignore`, `LICENSE`, `README.md`
|
||||
- `examples/*`, `packaging/systemd/*`, and the other files under `docs/`
|
||||
|
||||
`src/transport/quic.rs` was edited by another concurrent agent and is outside
|
||||
the TLS/integration ownership listed above. Preserve that ownership boundary
|
||||
when resolving conflicts.
|
||||
|
||||
## Verification and current failures
|
||||
|
||||
- TOML examples were parsed successfully with Python `tomllib`.
|
||||
- TLS/TCP focused tests passed: `cargo test --test tls_tcp --quiet` (7 tests).
|
||||
- HTTP/3 focused tests passed: `cargo test --test http3 --quiet` (4 tests).
|
||||
- `cargo check` passed after the transport integration edits.
|
||||
- The TLS loopback integration test compiles but currently panics while
|
||||
constructing a rustls configuration because no process-level crypto provider
|
||||
is installed:
|
||||
|
||||
`Could not automatically determine process-level CryptoProvider from Rustls crate features.`
|
||||
|
||||
The runtime/test setup must explicitly install the `ring` provider (or enable
|
||||
exactly one provider feature) before building rustls configurations.
|
||||
- The supervisor's latest failure reprobe reports that the QUIC focused tests
|
||||
now pass. Run the complete suite again after fixing the rustls provider; the
|
||||
earlier complete-suite run had QUIC handshake-timeout failures before the
|
||||
concurrent QUIC-agent fixes landed.
|
||||
- Clippy has not reached a clean result. Existing included test/source modules
|
||||
produce many dead-code and lint diagnostics, and integration code also needs
|
||||
a final lint pass after the provider fix.
|
||||
|
||||
## Remaining gaps, prioritized
|
||||
|
||||
1. Fix and verify explicit rustls crypto-provider initialization, then run the
|
||||
TLS loopback test and the complete test suite.
|
||||
2. Finish a real h3 0.0.8/h3-quinn 0.0.10 HTTP/3 CONNECT-UDP datagram adapter,
|
||||
or retain the explicit `Unsupported` path with a precise documented
|
||||
dependency/API blocker. Do not substitute POST, capsules-only streams, or
|
||||
ordinary HTTP request bodies for HTTP Datagrams.
|
||||
3. Review runtime lifecycle semantics: direct-UDP control shutdown wiring,
|
||||
actual file-backed config reload, client TLS heartbeat scheduling, and
|
||||
authentication-error mapping so auto fallback stops on rejected credentials.
|
||||
4. Run repository-wide formatting, tests, and clippy; inspect the shared
|
||||
untracked tree and reconcile concurrent `quic.rs` changes before any commit.
|
||||
|
||||
## First three tasks tomorrow
|
||||
|
||||
1. Install/select the rustls `ring` provider once at runtime and in the
|
||||
integration test setup; rerun TLS loopback plus `cargo test`.
|
||||
2. Inspect the enabled h3-quinn datagram API and implement/test the smallest
|
||||
standards-correct CONNECT-UDP client/server adapter; otherwise record the
|
||||
exact unsupported API/dependency condition in the public docs.
|
||||
3. Perform an end-to-end lifecycle review and repository-wide `fmt`, check,
|
||||
test, and clippy pass, resolving only changes within each agent's ownership.
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# Implementation and acceptance checklist
|
||||
|
||||
This is a coordinator checklist, not a claim that the items are complete.
|
||||
Mark an item only with code evidence, tests, and an integration result. Record
|
||||
the commit/test command or issue beside each checked item. A feature marked
|
||||
planned in the other documents must remain visibly planned here until proven.
|
||||
|
||||
## Milestones 1–6
|
||||
|
||||
- [ ] **1 — authenticated direct relay:** local UDP listener; direct UDP
|
||||
handshake; HMAC-authenticated data; replay window; keepalive/expiry; one
|
||||
backend UDP socket per authenticated client; multi-client isolation; TOML;
|
||||
logs and basic stats.
|
||||
- [ ] **2 — QUIC DATAGRAM:** certificate loading and hostname verification;
|
||||
client challenge/response; datagrams; keepalive/MTU; reconnect; multi-client
|
||||
handling without core API redesign.
|
||||
- [ ] **3 — automatic selection:** `mode = "auto"`; direct UDP then QUIC;
|
||||
bounded probes/retries; auth rejection stops probing; jittered reconnect;
|
||||
status reports selected transport.
|
||||
- [ ] **4 — HTTP/3 CONNECT-UDP:** standard CONNECT-UDP/HTTP Datagram semantics;
|
||||
authentication; backend mapping; reuse QUIC infrastructure where practical.
|
||||
- [ ] **5 — TLS/TCP fallback:** TLS listener; client authentication; bounded
|
||||
big-endian length framing; bidirectional datagram reconstruction; fallback
|
||||
integration; expected head-of-line behavior documented.
|
||||
- [ ] **6 — operational polish:** Unix control socket; status/stats/reconnect
|
||||
commands; config validation; systemd units; capability guidance; certificate
|
||||
and configuration reload; benchmarks; fuzzing; installation docs.
|
||||
|
||||
## v1 completion criteria (spec §89)
|
||||
|
||||
- [ ] 1. Multiple clients concurrently reach one UDP backend.
|
||||
- [ ] 2. No WireGuard-specific logic exists.
|
||||
- [ ] 3. Direct UDP works reliably.
|
||||
- [ ] 4. QUIC DATAGRAM works reliably.
|
||||
- [ ] 5. HTTP/3 CONNECT-UDP works.
|
||||
- [ ] 6. TLS/TCP fallback works.
|
||||
- [ ] 7. Automatic transport selection works.
|
||||
- [ ] 8. Authentication is enforced on every public transport.
|
||||
- [ ] 9. Direct UDP has replay and integrity protection.
|
||||
- [ ] 10. Direct UDP NAT rebinding works.
|
||||
- [ ] 11. Sessions expire and clean up correctly.
|
||||
- [ ] 12. The server survives malformed and unauthenticated traffic.
|
||||
- [ ] 13. The daemon runs unprivileged except optional bind capability.
|
||||
- [ ] 14. TOML configuration is clearly validated.
|
||||
- [ ] 15. Meaningful status and statistics are available.
|
||||
- [ ] 16. Reconnects occur automatically.
|
||||
- [ ] 17. Automated integration tests cover multi-client operation.
|
||||
|
||||
## Required evidence before v1 sign-off
|
||||
|
||||
- [ ] Unit tests cover parsing, malformed input, auth, key derivation, replay,
|
||||
config validation, and timeout logic.
|
||||
- [ ] Integration tests cover direct client/server, concurrent clients,
|
||||
source-port change, auth rejection, restart/reconnect, backend outage,
|
||||
oversized datagrams, and expiry; later transports have equivalent coverage.
|
||||
- [ ] Fuzz targets exercise direct packets, TCP frames, and auth messages.
|
||||
- [ ] `cargo test`, formatting, linting, and any documented integration/bench
|
||||
commands pass from a clean checkout.
|
||||
- [ ] Review confirms no payload/secret logging, no unsafe privilege grant, and
|
||||
no accidental WireGuard/routing/firewall coupling.
|
||||
@@ -0,0 +1,93 @@
|
||||
# Operations
|
||||
|
||||
This guide assumes a dedicated `wgcloak` system user and `/etc/wgcloak/` for
|
||||
configuration. Adjust paths for a user service or a different packaging
|
||||
layout.
|
||||
|
||||
## First installation
|
||||
|
||||
```bash
|
||||
sudo install -Dm755 target/release/wgcloak /usr/bin/wgcloak
|
||||
sudo install -d -o wgcloak -g wgcloak -m0750 /etc/wgcloak/clients
|
||||
sudo install -o wgcloak -g wgcloak -m0600 client.secret /etc/wgcloak/client.secret
|
||||
```
|
||||
|
||||
Create server client secrets separately and transfer them through a protected
|
||||
channel. Do not put real secret contents in the repository. Validate a config
|
||||
before starting a service when `check-config` is available in the current
|
||||
build:
|
||||
|
||||
```bash
|
||||
sudo -u wgcloak wgcloak check-config --config /etc/wgcloak/client.toml
|
||||
```
|
||||
|
||||
The command is a target v1 CLI and is delivered in the operational-polish
|
||||
milestone; confirm with `wgcloak --help`.
|
||||
|
||||
## Starting and stopping
|
||||
|
||||
Foreground operation is useful for first-run diagnostics:
|
||||
|
||||
```bash
|
||||
wgcloak client --config /etc/wgcloak/client.toml
|
||||
wgcloak server --config /etc/wgcloak/server.toml
|
||||
```
|
||||
|
||||
SIGTERM and SIGINT should stop accepting new sessions, stop local ingestion,
|
||||
close backend sockets, flush useful metrics, and exit within a bounded timeout.
|
||||
A transport failure should reconnect with jitter; it should not terminate the
|
||||
daemon. The systemd templates set restart-on-failure for this reason.
|
||||
|
||||
## Control socket (intended interface)
|
||||
|
||||
The daemon should expose a Unix-domain control socket at
|
||||
`$XDG_RUNTIME_DIR/wgcloak.sock` (for a system service, the template maps this
|
||||
to its private runtime directory). Filesystem permissions, not a TCP port,
|
||||
authorize access. The initial control protocol may be newline-delimited JSON.
|
||||
|
||||
Target commands are:
|
||||
|
||||
```text
|
||||
status current role/state, selected transport, endpoint, MTU and uptime
|
||||
stats counters for traffic, drops, auth failures, reconnects and sessions
|
||||
reconnect ask the client to leave the current transport and probe again
|
||||
reload re-read supported configuration (not full hot reload in early builds)
|
||||
shutdown request graceful process shutdown
|
||||
```
|
||||
|
||||
The exact request/response field names are implementation-owned until the
|
||||
control protocol lands. A client should never send credentials or payloads
|
||||
through this socket. `status` and `stats` are read-only; `reconnect`, `reload`,
|
||||
and `shutdown` are state-changing and must remain local-admin operations.
|
||||
|
||||
## systemd deployment
|
||||
|
||||
Review and copy the units under `packaging/systemd/`. They assume:
|
||||
|
||||
- binary `/usr/bin/wgcloak`;
|
||||
- user/group `wgcloak`;
|
||||
- configuration `/etc/wgcloak/client.toml` or `server.toml`;
|
||||
- runtime socket under a private `/run` directory;
|
||||
- secret and certificate paths readable by the service user.
|
||||
|
||||
After review:
|
||||
|
||||
```bash
|
||||
sudo install -Dm0644 packaging/systemd/wgcloak-client.service /etc/systemd/system/wgcloak-client.service
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now wgcloak-client.service
|
||||
systemctl status wgcloak-client.service
|
||||
journalctl -u wgcloak-client.service -f
|
||||
```
|
||||
|
||||
For a low port such as 443, uncomment `AmbientCapabilities=CAP_NET_BIND_SERVICE`
|
||||
and its bounding-set companion in the server unit only after confirming the
|
||||
unit still starts. Direct UDP examples use an unprivileged port.
|
||||
|
||||
## Safe rollout
|
||||
|
||||
Start with direct UDP and one test client. Check local listener binding,
|
||||
server authentication, backend reachability, return-peer behavior, counters,
|
||||
and clean shutdown. Add one transport milestone at a time. Keep an independent
|
||||
path to the host while changing a public listener and retain the previous
|
||||
configuration until a restart test succeeds.
|
||||
@@ -0,0 +1,72 @@
|
||||
# Protocol overview
|
||||
|
||||
The application protocol, tunnel session, transport, and authentication remain
|
||||
independent. The application payload is opaque and is never parsed as
|
||||
WireGuard (or any other protocol).
|
||||
|
||||
## Direct UDP wire protocol (target v1)
|
||||
|
||||
Direct messages use protocol version `1`, network byte order, and a 12-byte
|
||||
common header:
|
||||
|
||||
```text
|
||||
+---------+---------+---------+---------+
|
||||
| version | type | flags | hdr_len |
|
||||
| u8 | u8 | u8 | u8 |
|
||||
+---------------------------------------+
|
||||
| session_id (u64) |
|
||||
+---------------------------------------+
|
||||
```
|
||||
|
||||
Packet types are `HELLO (0x01)`, `ACCEPT (0x02)`, `REJECT (0x03)`,
|
||||
`DATA (0x10)`, `KEEPALIVE (0x11)`, and `CLOSE (0x12)`. Unknown or malformed
|
||||
types are rejected or ignored according to context and never crash the daemon.
|
||||
|
||||
`HELLO` has session ID zero and carries a bounded client ID, timestamp,
|
||||
16-byte client nonce, and a 32-byte HMAC-SHA256 authenticator over the
|
||||
canonical version/client/timestamp/nonce encoding. The server checks a default
|
||||
60-second clock window and remembers accepted nonces for replay protection.
|
||||
|
||||
`ACCEPT` assigns a random, non-zero 64-bit session ID and returns a server
|
||||
nonce, idle timeout, maximum datagram size, and an authenticator. `REJECT`
|
||||
returns only a small reason class; it must not disclose secret material.
|
||||
|
||||
Authenticated `DATA` and `KEEPALIVE` packets contain the common header, a
|
||||
32-bit direction-specific sequence number, a 128-bit truncated HMAC tag, and
|
||||
the optional payload. Session keys are derived with HKDF-SHA256 from the
|
||||
configured secret, both nonces, and the session ID. Implementations must use
|
||||
maintained cryptographic libraries and constant-time tag comparison.
|
||||
|
||||
Sequence windows provide duplicate/replay detection and diagnostics but do not
|
||||
reorder UDP. After MAC and replay checks, a valid packet may update the peer
|
||||
address, allowing NAT rebinding. A session expires after the configured idle
|
||||
timeout (target default 120 seconds), then its backend socket and replay state
|
||||
are released.
|
||||
|
||||
The core rejects oversized application datagrams, increments a counter, and
|
||||
logs at debug/warn level. v1 does not fragment datagrams; a conservative
|
||||
starting limit is 1200 bytes.
|
||||
|
||||
## Encapsulated transports
|
||||
|
||||
- **Direct UDP:** lowest overhead and native datagrams; uses the authenticated
|
||||
protocol above and provides integrity but not outer confidentiality.
|
||||
- **QUIC DATAGRAM:** TLS 1.3 protects the transport; client shared-secret
|
||||
challenge/response still authenticates the configured client.
|
||||
- **HTTP/3 CONNECT-UDP:** uses legitimate MASQUE CONNECT-UDP and HTTP Datagram
|
||||
semantics over QUIC. It is for compatibility, not fingerprint spoofing.
|
||||
- **TLS/TCP:** uses the same client authentication model. Each datagram is
|
||||
framed as a big-endian `u16` payload length followed by up to 65535 bytes;
|
||||
the configured lower limit should normally apply. TCP head-of-line blocking
|
||||
is expected.
|
||||
|
||||
QUIC, HTTP/3, and TLS/TCP are planned by milestones 2, 4, and 5 respectively.
|
||||
The direct packet details are a protocol target; confirm the implementation and
|
||||
integration tests before treating them as interoperable guarantees.
|
||||
|
||||
## Authentication and resource order
|
||||
|
||||
The server performs cheap bounds/version checks, authentication and rate-limit
|
||||
checks before allocating a backend UDP socket. Public listeners are hostile:
|
||||
limits, handshake timeouts, per-source caps, and malformed-packet handling are
|
||||
part of the protocol boundary.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Security model
|
||||
|
||||
## What is protected
|
||||
|
||||
The server treats every public listener as hostile. v1 requires a configured
|
||||
client ID and at least 256 bits of entropy in its shared secret. Direct UDP
|
||||
authenticates every session and every data packet, rejects replay, tolerates
|
||||
authenticated NAT rebinding, and does not trust a session ID by itself.
|
||||
TLS-capable transports authenticate the server through normal X.509 hostname
|
||||
verification and authenticate the client with a post-connection HMAC
|
||||
challenge/response.
|
||||
|
||||
Secrets and application payloads must not appear in logs. Cryptographic
|
||||
operations belong to maintained Rust libraries; wgcloak does not implement
|
||||
encryption, HMAC, HKDF, SHA, or TLS itself.
|
||||
|
||||
## Local permissions
|
||||
|
||||
Use separate secret files rather than inline values. Secret files should be
|
||||
owned by the service account and mode `0600`; the parent configuration
|
||||
directory should not be writable by untrusted users. The Unix control socket
|
||||
must be created in a private runtime directory with restrictive ownership and
|
||||
mode (normally `0600`). Do not put it in a world-writable directory.
|
||||
|
||||
The systemd templates apply `NoNewPrivileges`, a read-only system view, private
|
||||
temporary storage, restricted address families, and other process hardening.
|
||||
Review `ReadWritePaths`, certificate access, and local policy before enabling
|
||||
them. Grant only `CAP_NET_BIND_SERVICE` when a low port is essential. Never
|
||||
grant `CAP_NET_ADMIN` or `CAP_SYS_ADMIN` for normal operation.
|
||||
|
||||
## Threat boundaries
|
||||
|
||||
The relay protects session admission and transport integrity; it does not make
|
||||
the encapsulated application secure. Direct UDP is not encrypted by wgcloak,
|
||||
so use QUIC, HTTP/3, or TLS/TCP when outer confidentiality is needed. A shared
|
||||
secret is a credential: rotate it out of band and avoid putting it in command
|
||||
lines, shell history, or issue reports.
|
||||
|
||||
Resource limits and bounded parsing reduce denial-of-service exposure, but a
|
||||
public relay still needs host firewalling, monitoring, and capacity planning.
|
||||
Authentication failure must stop probing rather than causing endless fallback
|
||||
traffic.
|
||||
|
||||
## Explicit non-goals
|
||||
|
||||
v1 does not configure WireGuard, create TUN/TAP interfaces, manage routes or
|
||||
firewalls, provide traffic-shaping or browser/TLS-fingerprint evasion, hide
|
||||
traffic metadata from a compromised host, cluster servers, or support multiple
|
||||
simultaneous client tunnels. These boundaries are intentional.
|
||||
@@ -0,0 +1,65 @@
|
||||
# Troubleshooting
|
||||
|
||||
Check the simplest layer that can explain the symptom, then move outward.
|
||||
|
||||
## Process exits immediately
|
||||
|
||||
- Run the same command in the foreground and read the fatal configuration
|
||||
error.
|
||||
- Check that every secret/certificate path exists and is readable by the
|
||||
service account, but not by unrelated users.
|
||||
- Run `wgcloak --help` and, where implemented, `wgcloak check-config` to spot a
|
||||
command or schema mismatch.
|
||||
- Confirm listener addresses are valid and no other process owns the port.
|
||||
|
||||
## Client cannot connect
|
||||
|
||||
- Verify DNS resolution and the configured server name/port.
|
||||
- Confirm the selected transport is implemented in this build; an `auto` list
|
||||
may mention future transports.
|
||||
- For direct UDP, check both directions in the host firewall and allow the
|
||||
server's UDP listener.
|
||||
- For TLS transports, verify the hostname matches the certificate and do not
|
||||
disable certificate verification.
|
||||
- Authentication rejection means a bad/unknown client or secret and must not
|
||||
be diagnosed as a firewall failure. Fix credentials before retrying.
|
||||
|
||||
## Authentication failures or repeated probing
|
||||
|
||||
Check client ID spelling, secret-file contents, ownership/mode, and system
|
||||
clock skew. Direct HELLO timestamps have a target default 60-second window;
|
||||
replayed client nonces are rejected. Repeated invalid credentials should stop
|
||||
fallback probing rather than generate traffic across every transport.
|
||||
|
||||
## Connected but no application traffic
|
||||
|
||||
- Confirm the local application sends to the configured local UDP address.
|
||||
- Confirm the server backend is listening at `[backend].target`.
|
||||
- Check `status`/`stats` or structured logs for selected transport, maximum
|
||||
datagram size, dropped/oversized datagrams, and backend errors.
|
||||
- v1 remembers one most-recent local source peer per client tunnel. Concurrent
|
||||
source peers can replace that return destination and produce a warning.
|
||||
- No application-layer fragmentation exists: reduce payload size when the
|
||||
configured transport limit is exceeded (starting target is 1200 bytes).
|
||||
|
||||
## Session disappears
|
||||
|
||||
The target idle timeout is 120 seconds, refreshed by authenticated data or
|
||||
keepalive. Check keepalive settings, NAT expiry, server resource limits, and
|
||||
whether the client is reconnecting after a transport failure. A valid direct
|
||||
UDP packet can update the peer address after NAT rebinding; a spoofed packet
|
||||
without a valid MAC cannot.
|
||||
|
||||
## Control socket unavailable
|
||||
|
||||
Check the daemon's `XDG_RUNTIME_DIR`, socket ownership/mode, and whether a
|
||||
stale socket path remains after an unclean exit. The control interface is local
|
||||
only and may be absent until the operational-polish milestone is implemented.
|
||||
|
||||
## Host hardening prevents startup
|
||||
|
||||
Read the unit's journal output. Common causes are a secret/certificate path
|
||||
outside the unit's read paths, a changed binary location, or an address family
|
||||
not allowed by `RestrictAddressFamilies`. Correct the reviewed unit rather
|
||||
than weakening all hardening directives. `CAP_NET_BIND_SERVICE` is only needed
|
||||
for ports below 1024.
|
||||
Reference in new issue
Block a user