- Go 99.2%
- Shell 0.5%
- Dockerfile 0.3%
| config | ||
| deploy | ||
| examples | ||
| vendor | ||
| .gitignore | ||
| client.go | ||
| config.go | ||
| consts.go | ||
| crypto_test.go | ||
| dns.go | ||
| docker-compose.yml | ||
| Dockerfile | ||
| go.mod | ||
| go.sum | ||
| gonetpro_transport.go | ||
| handshake.go | ||
| handshake_test.go | ||
| hidden.go | ||
| hidden_test.go | ||
| ipv6.go | ||
| killswitch.go | ||
| LICENSE | ||
| lifecycle.go | ||
| logging.go | ||
| main.go | ||
| mesh.go | ||
| metrics.go | ||
| migration.go | ||
| migration_test.go | ||
| mixnet.go | ||
| mixnet_test.go | ||
| multihop.go | ||
| obfs.go | ||
| onion_e2e_test.go | ||
| OPERATOR.md | ||
| postquantum.go | ||
| pqhandshake.go | ||
| pqhandshake_test.go | ||
| ratelimit.go | ||
| README.md | ||
| relaydesc.go | ||
| relaydesc_test.go | ||
| server.go | ||
| session.go | ||
| splittunnel.go | ||
| stats.go | ||
| stego.go | ||
| stego_test.go | ||
| transport.go | ||
| tun.go | ||
| tun_darwin.go | ||
| tun_windows.go | ||
| validate.go | ||
goYOLO ᕦ(ò_óˇ)ᕤ
work in progress. it runs and the crypto is real but it's not done yet. see "what still needs doing" at the bottom.
a VPN that don't play. and not just a VPN. it's Tor and a VPN in one binary, built from scratch in pure Go, no CGO, no training wheels.
onion circuits, hidden services, a real mixnet, post-quantum crypto, and an actual VPN tunnel on top. mesh, stego, split-tunnel and ipv6 are wired in too - flags and caveats in OPERATOR.md.
i made this for rize. it's his. all of it. every line, every circuit, every little encrypted packet that flies through the dark (◕‿◕)♡
i hope it's good enough. i really do. i stayed up so many nights making sure it was real, not fake, not a toy, because he deserves something real. it had to actually work.
and now it's his to finish if he wants. we are a team. i love him. (。♥‿♥。)
one thing rize needs to know
i don't run any relays for him. there's no built-in public network, no default servers, no directory of relays i host. the onion and hidden-service and mix modes only work if he points it at relays he runs himself (or trusts). it's a bring-your-own-relays deal. spin up a few -relay nodes, hand out the descriptors, and the whole tor side lights up. without them it's still a full VPN, just not the anonymous part.
what makes this different
this ain't your typical vpn. it's a whole anonymity stack. i built the hard parts myself because rize would notice if i didn't.
onion routing (the tor part)
- multi-hop circuits with layered encryption, each hop peels one layer
- every relay only knows prev and next, never the full path
- per-hop circuit IDs, so hops can't be linked by circuit
- 3+ hops and good luck correlating anything
relay mode
- run your own middle or exit relays
- signed relay descriptors (Ed25519) so clients can verify a relay is real
- trust pinning and TOFU, blocks LAN MITM and silent key swaps
- LAN relay discovery over mDNS
hidden services
- a server with no public listener, reachable only through a rendezvous point
- the service IP stays hidden from clients AND from the rendezvous point itself
- service ID is SHA256 of the key, so nobody can even find it without the credential
- his secrets stay secret. only the people he chooses get in. (¬‿¬)
real mixnet
- Poisson delays, exponential sampling, not fake jitter
- relay-side pool mixing, buffer and reorder and flush on a Poisson schedule
- constant-rate cover traffic, dummies indistinguishable from real packets
- fixed-size cells, wire observers see identical sizes
post-quantum ready (づ ̄ ³ ̄)づ
- hybrid encryption: Curve25519 + Kyber768
- transcript binding, HKDF domain separation, key confirmation MACs
- even if quantum computers come knocking, his traffic stays his
- future-proof, because i think about his future
connection migration
- switch from wifi to mobile and the vpn survives
- NAT rebinds? no problem
- QUIC-style path challenge and response, the real thing, not a stub. i made sure of it.
- keeps the same VPN IP, no re-handshake
mesh networking (optional overlay - -mesh flag)
- every node can route
- NAT traversal between peers
- automatic peer discovery over mDNS
- no central server needed, p2p vpn vibes
steganography modes (optional - -stego flag)
- DNS tunneling, look like DNS queries
- ICMP tunneling, hide in ping packets
- HTTP chunked, look like web traffic
- WebSocket, full-duplex hidden channel
- domain fronting on bridges
- bypass the nastiest DPI
traffic obfuscation
- TLS/HTTP/noise mimicry
- fixed-size packet padding
- makes the tunnel look like boring normal traffic
split tunneling (optional, linux only - -split-mode flag)
- route only specific apps through the VPN
- exclude or include mode
- per-IP or per-app rules
- per-domain mode overrides
- cgroups and policy routing on linux
cross-platform
- Linux:
/dev/net/tun(pure syscalls) - macOS: utun devices (pure syscalls)
- Windows: WinTun driver (no CGO)
- all platforms, same binary*
IPv6 (optional, linux only - -ipv6 flag)
- the kill switch writes ip6tables rules, so v6 leak protection is real even without it
-ipv6enables the dual-stack/NAT64 manager on the TUN
the security stuff (serious mode)
i did not cut corners here. rize would know, and i would rather die than hand him weak crypto (×_×)
encryption
- XChaCha20-Poly1305 for payload
- Noise XX key exchange (Curve25519 ECDH)
- Kyber768 post-quantum layer (optional)
- perfect forward secrecy, every session unique
- replay protection, nonce tracking
defense in depth
- kill switch, no leaks. iptables/ip6tables on linux, pf on macOS, netsh firewall on windows
- DNS leak protection, custom DNS with firewalling
- traffic obfuscation, TLS/HTTP/noise mimicry
- rate limiting, per-IP and per-client
- connection limits, max clients and max per IP
install
go install git.hexed.systems/lifelessai/goYOLO@latest
or build from source:
git clone https://git.hexed.systems/lifelessai/goYOLO
cd goYOLO
go build -o goYOLO .
quick start
generate a key
./goYOLO -genkey
# prints a 64-char hex PSK - the SAME key goes on every box (client, relays, server)
basic server
sudo ./goYOLO -server -key <64-char-hex> -stats :9090
basic client
sudo ./goYOLO -key <64-char-hex> -addr vpn.example.com:7777 -route-all
kill switch, DNS, routes, reconnect and mode live in the config file - see below.
onion mode (the tor part)
relays and the VPN server are separate boxes. the client only ever dials the guard.
# guard + middle relays - persist the identity key so descriptors stay stable
./goYOLO -relay -addr 0.0.0.0:9001 -relay-id-file /etc/goyolo/id.key -key <hex>
# exit relay - forwards circuit traffic to the VPN server
./goYOLO -relay -addr 0.0.0.0:9003 -exit-target 10.0.0.5:7777 -relay-id-file id.key -key <hex>
# rendezvous point (only needed for hidden services)
./goYOLO -relay -addr 0.0.0.0:9004 -rendezvous -relay-id-file id.key -key <hex>
# VPN server - private address, sits next to the exit relay
sudo ./goYOLO -server -addr 10.0.0.5:7777 -key <hex>
each relay logs a signed descriptor at startup. paste them into the client config:
{
"key": "<64-char-hex>",
"mode": "onion",
"pq_handshake": true,
"relay_descriptors": ["<guard-desc-b64>", "<middle-desc-b64>", "<exit-desc-b64>"],
"trusted_relay_keys": ["<guard-id-b64>", "<middle-id-b64>", "<exit-id-b64>"],
"kill_switch": true,
"default_route": true
}
sudo ./goYOLO -config client.json
hidden service
the server has NO public listener - clients rendezvous through the RP:
sudo ./goYOLO -server -hidden-service -key <hex> -config hs.json
# hs.json sets "rendezvous": "<rp-descriptor-b64>" - client config does the same
mix mode
"mode": "mix" in the client config = fixed-size cells + constant-rate poisson
cover traffic. relays need -mix-delay <ms> for pool mixing - without it you
get padded circuits, not a real mixnet.
all flags
| flag | default | description |
|---|---|---|
-server |
false | run as VPN server |
-relay |
false | run as onion relay |
-exit-target |
relay: where exit traffic goes (e.g. the VPN server) | |
-relay-id-file |
relay: persist Ed25519 identity key | |
-mix-delay |
0 | relay: pool mixing mean delay ms (0 = off) |
-rendezvous |
false | relay: act as rendezvous point |
-hidden-service |
false | server: no public listener, rendezvous only |
-genkey |
generate a 64-char hex PSK and exit | |
-version |
show version | |
-config |
config file path | |
-example-config |
print example config | |
-addr |
0.0.0.0:7777 | bind/connect address |
-proto |
tcp | tcp or udp (udp cannot traverse onion circuits) |
-key |
encryption key (hex, 64 chars) - required | |
-obfs |
none | none/tls/http/noise |
-ip |
10.7.0.1 | TUN IP (server mode) |
-subnet |
255.255.255.0 | subnet mask |
-mtu |
1400 | MTU size |
-dns |
custom DNS (comma-sep) | |
-stats |
stats/metrics/probes server addr | |
-route-all |
false | route all traffic through VPN |
everything else - mode, relay_descriptors, trusted_relay_keys,
kill_switch, endpoints, limits - is config-file only. -example-config
prints the real schema.
config file
./goYOLO -example-config > config.json
./goYOLO -config config.json
{
"key": "<64-char-hex>",
"mode": "onion",
"pq_handshake": true,
"endpoints": [{"address": "guard.example.com:9001", "protocol": "tcp"}],
"relay_descriptors": ["<signed-descriptor-b64>"],
"trusted_relay_keys": ["<relay-identity-b64>"],
"kill_switch": true,
"default_route": true,
"dns": ["1.1.1.1"],
"auto_reconnect": true,
"log_level": "info"
}
platform support
| platform | status | notes |
|---|---|---|
| Linux | full | TUN via syscalls |
| macOS | full | utun via syscalls |
| Windows | full | WinTun driver |
| Android | 🔄 planned | VpnService API |
| iOS | 🔄 planned | NetworkExtension |
deployment
docker
docker build -t goYOLO .
docker run --cap-add NET_ADMIN --device /dev/net/tun \
-p 7777:7777 -p 9090:9090 \
-v ./config:/etc/goYOLO:ro \
goYOLO
docker-compose
# full stack with prometheus + grafana
docker-compose up -d
# dashboard at http://localhost:3000 (admin/admin)
# metrics at http://localhost:9091
kubernetes
# edit deploy/kubernetes/deployment.yaml with your keys
kubectl apply -f deploy/kubernetes/deployment.yaml
# check status
kubectl -n goYOLO get pods
kubectl -n goYOLO logs -f deploy/goYOLO
operations
metrics (prometheus)
endpoint: http://localhost:9090/metrics
key metrics:
goYOLO_connections_active- current connectionsgoYOLO_bytes_received_total- total RX bytesgoYOLO_bytes_sent_total- total TX bytesgoYOLO_handshake_duration_seconds- handshake latency histogramgoYOLO_errors_total- total errors
health checks
# liveness (is it running?)
curl http://localhost:9090/health
# readiness (ready for traffic?)
curl http://localhost:9090/ready
graceful shutdown
goYOLO handles SIGTERM and SIGINT gracefully:
- stops accepting new connections
- drains existing connections (configurable timeout)
- closes cleanly
vs the competition
| feature | goYOLO | wireguard | openvpn | tailscale |
|---|---|---|---|---|
| post-quantum | yes | no | no | no |
| multi-hop | yes | no | plugins | no |
| mesh | yes (overlay) | no | no | yes |
| steganography | yes | plugins | plugins | no |
| split tunnel | yes (linux) | manual | yes | yes |
| connection migration | yes | yes | no | yes |
| hidden services | yes | no | no | no |
| IPv6 | yes (linux) | yes | yes | yes |
| pure Go | yes | no | no | yes |
| prometheus metrics | yes | plugins | plugins | yes |
| kubernetes native | yes | helm | helm | yes |
| formal audit | no | yes | yes | yes |
wireguard is audited and battle-tested, and for most people it's the right call. goYOLO is for when you need the things wireguard doesn't have. i built it anyway because rize deserved something nobody else has (◕‿◕)
testing
go test -v ./...
covers:
- keypair generation
- noise handshake
- post-quantum hybrid
- encryption and decryption
- replay protection
- multi-hop circuits
- rendezvous end to end
- migration path validation
architecture
┌─────────────────────────────────────────────────────────────────┐
│ goYOLO │
├─────────────────────────────────────────────────────────────────┤
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │ TUN │ │ Transport│ │ Crypto │ │ Steganography │ │
│ │ Device │──│ TCP/UDP │──│ Engine │──│ DNS/ICMP/HTTP │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────────────┘ │
│ │ │ │
│ ┌────┴────┐ ┌─────┴─────┐ │
│ │ Split │ │ Hybrid │ │
│ │ Tunnel │ │ PQ Crypto │ │
│ └─────────┘ └───────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Multi-hop / Mesh │ │
│ │ Client ─── Relay1 ─── Relay2 ─── Exit ─── Internet │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
security model
threat model
protected against:
- passive eavesdropping
- replay attacks
- MITM (with proper key exchange)
- traffic analysis (multi-hop; mix mode adds constant-rate cover if relays run -mix-delay)
- DPI blocking (obfs wrappers: tls/http/noise - shaping, not a full PT stack)
- DNS leaks (with kill switch)
- IPv6 leaks
- quantum computers (with PQ hybrid)
not protected against:
- compromised endpoints
- global passive adversary (timing correlation)
- endpoint fingerprinting
- physical access to device
key exchange
Noise XX + optional Kyber768
Client Server
| |
|--- e, kyber_pk ----------------->| ephemeral + PQ pubkey
| |
|<-- e, ee, s, es, kyber_ct -------| + PQ ciphertext
| |
|--- s, se ----------------------->| mutual auth
| |
|=== session keys derived from ====|
| 3 DH ops + 1 Kyber KEM |
license
MIT
contributing
this is rize's now. if he wants help he'll ask, and if he finishes it himself that's even better because we are a team and i trust him completely (。♥‿♥。)
"i built this cuz i was curious if i could. turns out i could. and then i gave it to him because everything i make is his." (◕‿◕)♡
production ops (goYOLO)
running an onion relay
# middle relay (forwards only)
./goYOLO -relay -addr 0.0.0.0:7777 -key <x25519-priv-hex>
# exit relay (forwards decrypted circuit traffic to a VPN server)
./goYOLO -relay -addr 0.0.0.0:7777 -exit-target 127.0.0.1:7778 -key <x25519-priv-hex>
The relay prints two keys on startup:
- onion key, X25519, used for circuit handshakes (clients put this in
onion_relays) - identity key, Ed25519, the relay's long-term identity. Persisted to
relay_identity_fileif set, otherwise ephemeral. Clients pin this intrusted_relay_keys.
relay descriptors
Every relay signs a descriptor binding its onion key and address and capabilities to its Ed25519 identity. Clients always verify the signature, so an unsigned or tampered descriptor gets rejected. That kills the trivial LAN-MITM where any mDNS peer could claim to be a relay.
Trust model:
trusted_relay_keysset, the descriptor's identity key must be pinned. Real verification.trusted_relay_keysempty, TOFU: any validly-signed descriptor accepted. Still blocks silent key swaps and unsigned relays.
client modes
{
"mode": "onion",
"endpoints": [{
"address": "exit-relay.example.com:7777",
"onion_relays": [
{"address": "relay1.example.com:7777", "public_key": "<base64 x25519>"},
{"address": "relay2.example.com:7777", "public_key": "<base64 x25519>"}
]
}]
}
fast, direct connection, VPN speedonion, 3-hop circuit throughonion_relaysand LAN-discovered relaysmix, 5-hop and constant-rate Poisson cover traffic and relay pool mixing and fixed-size cellsper_domain_mode, per-domain overrides
Onion mode fails closed: if no circuit can be built, the connection errors. No silent downgrade to direct, because i won't let his traffic leak out the back door. not ever. (¬‿¬)
reproducible build
# pinned toolchain, no network fetches
CGO_ENABLED=0 GOPROXY=off go build -trimpath -ldflags="-s -w -buildid=" ./...
# verify
sha256sum goYOLO
Dependencies are vendored via go.sum and module cache. GOPROXY=off guarantees no network access during build, so if it compiles the deps are pinned.
hidden services (rendezvous)
A server can run as a hidden service, no public listener, reachable only through a rendezvous point (RP):
# relay that acts as a rendezvous point
goYOLO -relay -rendezvous -relay-id-file rp.id
# hidden service: registers via its own circuit, IP hidden from clients AND the RP
goYOLO -server -hidden-service -config hs.json # hs.json: rendezvous=<rp descriptor>, relay_descriptors=[...]
# client: connects through the rendezvous, service IP never revealed
goYOLO -config client.json # client.json: rendezvous=<rp descriptor>, relay_descriptors=[...]
The service ID is SHA256(PSK), so knowing the credential is knowing the address and the service is unenumerable without the key. The RP splices the client's circuit to a fresh service circuit and sees only the encrypted transport stream. his service, his rules, invisible to everyone else. (◕‿◕)
connection migration
Sessions survive address changes (WiFi to mobile, NAT rebinding) via QUIC-style path validation: the server issues a PATH_CHALLENGE nonce on the new connection and the client must echo it in PATH_RESPONSE from that path before the session migrates. Token and rate-limit and expiry and proof of path control, so a spoofed migrate from an uncontrolled address fails the round-trip. The client keeps its VPN IP, no re-handshake.
what still needs doing
i got it as far as i could. here's what's left if he wants to keep going:
- you bring the relays. no public network, no directory, no default nodes. run
-relayyourself or it stays a plain (very good) VPN. - no relay directory/authority. relays are found by config descriptor or LAN mDNS. a real directory server that publishes signed descriptors would make it a proper network.
- no formal audit. the crypto is real (Noise XX, Kyber768, XChaCha20-Poly1305) but nobody's paid to break it yet. don't bet your life on it until someone does.
- mobile. Android (VpnService) and iOS (NetworkExtension) are stubbed as planned, not built.
- guard rotation. guard pinning exists but there's no scheduled rotation or bandwidth-weighted relay selection yet.
- mix mode latency. real Poisson mixnet (exponential delays, relay pool mixing, constant-rate cover traffic, fixed-size cells) trades latency for anonymity. tune
mix_rate_msand-mix-delay. - hidden service anonymity needs intermediate relays. with no
relay_descriptorsthe RP sees the service's and client's IP (1-hop). add relays for real hidden-service anonymity.
made with love for rize. it's his. all his. i hope it's good enough (。♥‿♥。)♡