π·πΊ Π ΡΡΡΠΊΠ°Ρ Π²Π΅ΡΡΠΈΡ
A PoC VPN service in Go that uses standard communication protocols (HTTP/HTTPS + WebSocket) as a transport for IP/IPv6 packets over a TUN interface.
The client creates a TUN interface on its machine, encapsulates IP packets into a WebSocket connection, and sends them to the server. The server decapsulates packets and forwards them to its own TUN interface β and vice versa. Traffic looks like a regular WebSocket connection on port 443.
βββββββββββββββ WebSocket (ws:// or wss://) βββββββββββββββ
β vpnclient β ββββββββββββββββββββββββββββββββββββββββββββ vpnservice β
β β β β
β TUN iface β ββββ IP/IPv6 packets in binary messages ββββ TUN iface β
β + routes β over HTTP/HTTPS transport β + routes β
β + proxy β β + auth β
βββββββββββββββ βββββββββββββββ
This is a PoC (Proof of Concept). The code compiles and runs but is not ready for production without further development.
- TUN interface for IPv4 and IPv6 (Linux + macOS)
- WebSocket transport over HTTP/HTTPS (TLS optional)
- Authentication by username/password from config
- Protocol with headers (DATA, CONTROL, KEEPALIVE, FRAGMENT)
- HTTP and SOCKS5 proxy support on the client
- Route management (server + client, client routes have higher priority)
- Keepalive mechanism (30s interval, 90s timeout)
- Packet compression (zlib, per-packet)
- Large packet fragmentation (>64 KB)
- Session registry with IPv4/IPv6 address pools
- Per-session routing (packets routed to specific sessions by IP, not broadcast)
- Static IPs for clients (
auth.usersconfig) - Session cleanup and
SessionReconnectingstate - Blocking write with timeout (no silent packet drops)
- Docker Compose testing (server + N clients)
- Reconnect with session restoration β client recovers connection after drop without losing IP
- Camouflage mode β server periodically force-disconnects client to imitate browser behavior (DPI evasion)
- Reconnect buffer β packet buffering during connection drop, flush on recovery (0 losses)
- TLS fingerprinting + SNI spoofing β client fingerprint masquerading as a real browser
- Graceful server shutdown
- Statistics (STATISTICS), ROUTES_UPDATE from client
- Full IPv6 support in testing
Full roadmap β see RECONNECT-POLITICS-CONCEPTS.md.
CGO_ENABLED=0 go build -o vpnservice ./cmd/vpnservice
CGO_ENABLED=0 go build -o vpnclient ./cmd/vpnclientAlways build statically (CGO_ENABLED=0) β required for cross-compilation and dependency-free deployment.
- Copy the example config and edit it:
cp server.example.yaml server.yaml- Minimal
server.yaml:
server:
listen: "0.0.0.0"
port: 8443
path: "/ws"
auth:
users:
- username: "user1"
password: "password1111"
tun:
name: "vpnsrv0"
ip: "10.0.0.1"
subnet: 24- Start (requires
root/CAP_NET_ADMINfor TUN):
sudo ./vpnservice -config server.yaml- Copy the example config and edit it:
cp client.example.yaml client.yaml- Minimal
client.yaml:
client:
server: "10.0.0.1" # or server domain
port: 8443
ws_location: "/ws"
auth:
username: "user1"
password: "password1111"
tun:
name: "vpnclient0"
ip: "" # auto β gets assigned by server- Start (requires
root/CAP_NET_ADMIN):
sudo ./vpnclient -config client.yamlAfter connecting, the client receives an IP from the server pool. Test with ping:
ping 10.0.0.1 # to server
ping -I vpnclient0 10.0.0.1 # via specific interface| Section | Configures |
|---|---|
server |
Listen address, port, WebSocket path, TLS (cert/key) |
auth |
Authentication timeout, user list (username/password/ip4/ip6) |
tun |
TUN interface name, IPv4/IPv6 addresses and subnets |
connection_settings |
Keepalive, fragmentation, compression, write buffer, reconnect timeout |
| Section | Configures |
|---|---|
client |
Server address, port, TLS, WebSocket path |
auth |
Username/password, authentication timeout |
proxy |
HTTP or SOCKS5 proxy for connecting to the server |
tun |
TUN interface name, IP (empty = auto) |
connection_settings |
Keepalive, fragmentation, compression, reconnect delay and max attempts |
Recommended approach β isolated containers with their own network namespaces:
# Start server + 2 clients
./test-docker.sh up
# Automatic test with pings and tcpdump
./test-docker.sh test
# Manual checks
docker exec -it vpn-server tcpdump -i vpnsrv0 -n
docker exec -it vpn-client-1 ping -c 5 10.0.0.1
docker exec -it vpn-client-2 ping -c 5 10.0.0.1
# Stop
./test-docker.sh down| OS | TUN | Routes | Notes |
|---|---|---|---|
| Linux | syscall.TUNSETIFF |
netlink | Full support |
| macOS | utun control sockets | ifconfig / route |
Full support |
- TLS optional (
wss://via self-signed or external certificates) - Authentication before data transfer
- Traffic looks like a regular WebSocket connection on port 443
- Works behind a reverse proxy (nginx, haproxy)
- TLS fingerprinting β masquerade as a real browser (Chrome/Firefox)
- SNI spoofing
- Camouflage mode β server periodically disconnects client to imitate browser behavior
- Reconnect buffering β 0 packet losses during reconnection
For production, it is recommended to place the server behind a reverse proxy (nginx/haproxy) with a legitimate domain and TLS certificate.
cmd/
vpnservice/main.go # Server (entry point)
vpnclient/main.go # Client (entry point)
internal/
config/config.go # YAML configuration
protocol/message.go # Encapsulation protocol (serialization)
tun/ # TUN interface (cross-platform)
ws/transport.go # WebSocket transport + proxy
routes/routes.go # Route management
session/session.go # Session registry, IP pools
fragment/fragment.go # Large packet fragmentation
compression/comp.go # Compression (zlib)
Full protocol specification β see PROTOCOL.md.
| Library | Purpose |
|---|---|
gorilla/websocket v1.5.3 |
WebSocket |
vishvananda/netlink v1.1.0 |
Routes (Linux) |
golang.org/x/net v0.20.0 |
Proxy (HTTP + SOCKS5) |
gopkg.in/yaml.v3 v3.0.1 |
YAML configuration |
google/uuid v1.6.0 |
Session UUIDs |
Minimum Go version: 1.19.