No description
  • Go 69.4%
  • Shell 21.7%
  • JavaScript 8.1%
  • Makefile 0.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Ladislav Brodecký c38be82af0
All checks were successful
/ build (push) Successful in 30m20s
feat(diag): gobond-diag — triáž pomalého speedtestu (bond vs ztrátová WAN vs cesta za VPS)
Read-only sampler na routeru: peak-6s klouzavé okno per-WAN wire TX/RX,
CAKE drops, podíl TCP retransmisí a MPTCP reinjecty za okno uživatelova
testu. Verdikt rozliší: bond dovezl součet shaperů (úzké hrdlo je za VPS
/ na test serveru) vs reálná ztráta na WAN segmentu vs nenaplněný bond.
Vzešlo z honu 2026-07-17 na 'upload cap 60' — drát nesl 115 Mbit, appka
62, a přesně tahle triáž se dělala ručně. Negenerui vlastní zátěž.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-17 12:07:58 +02:00
.claude chore: vyvojovy zaklad — CLAUDE.md, 5 workflowu, overena T1 lab, scaffolding 2026-05-31 16:23:55 +02:00
.forgejo/workflows fix(ci): SDK build padal na curl "TLS not detected" — netifyd se v SDK neinstaluje 2026-06-07 22:56:27 +02:00
cmd/gobond feat(wg,edge,luci,d20): remote-access WireGuard terminovaný na VPS edge — dual-stack + LuCI GUI 2026-07-16 23:58:36 +02:00
deploy feat(wg,edge,luci,d20): remote-access WireGuard terminovaný na VPS edge — dual-stack + LuCI GUI 2026-07-16 23:58:36 +02:00
docs feat(wg,edge,luci,d20): remote-access WireGuard terminovaný na VPS edge — dual-stack + LuCI GUI 2026-07-16 23:58:36 +02:00
internal feat(wg,edge,luci,d20): remote-access WireGuard terminovaný na VPS edge — dual-stack + LuCI GUI 2026-07-16 23:58:36 +02:00
lab feat(wg,edge,luci,d20): remote-access WireGuard terminovaný na VPS edge — dual-stack + LuCI GUI 2026-07-16 23:58:36 +02:00
openwrt/package feat(diag): gobond-diag — triáž pomalého speedtestu (bond vs ztrátová WAN vs cesta za VPS) 2026-07-17 12:07:58 +02:00
test-evidence feat(wg,edge,luci,d20): remote-access WireGuard terminovaný na VPS edge — dual-stack + LuCI GUI 2026-07-16 23:58:36 +02:00
.gitattributes feat(F1): M1.0 — single-path plaintext L3 tunnel, lab-verified inbound convergence 2026-05-31 18:40:12 +02:00
.gitignore feat(wg,edge,luci,d20): remote-access WireGuard terminovaný na VPS edge — dual-stack + LuCI GUI 2026-07-16 23:58:36 +02:00
CLAUDE.md fix: hloubkovy audit cele aplikace - 2x CRITICAL, 4x HIGH, ~14x MEDIUM (adversarialne re-verifikovano) 2026-06-10 10:07:11 +02:00
DEVELOPMENT.md docs: README = user-only, DEVELOPMENT.md for maintainers, docs->English policy 2026-06-06 13:41:43 +02:00
go.mod fix(audit): full opus audit (5 agents, stable net) — MEDIUM-1 GSO regression + F1 + all LOW 2026-06-06 17:11:23 +02:00
go.sum feat(fec): Reed-Solomon FEC core (encoder + decoder) — unit-tested 2026-06-02 11:22:11 +02:00
OMR-shrnuti-a-navrh-Go-nadstavby.md docs: sanitize internal LAN addresses to placeholders 2026-05-31 13:17:28 +02:00
README.md feat(diag): gobond-diag — triáž pomalého speedtestu (bond vs ztrátová WAN vs cesta za VPS) 2026-07-17 12:07:58 +02:00

gobond — lean Go multi-WAN bonding (an OpenMPTCProuter alternative)

One encrypted L3 tunnel across multiple WAN links, userspace UDP bonding with a custom scheduler, and a VPS edge that NATs traffic in and out of the tunnel. A single Go binary, two roles (router / vps), packaged for stock OpenWrt (no fork). A lean, robust alternative to OpenMPTCProuter (OMR).

What it does

  • Aggregation of multiple WANs into higher throughput + failover on link loss (download and upload, TCP and UDP).
  • One public egress IP on the VPS (hides the real WAN IPs).
  • Inbound hosting — a server behind the router (TS3, game servers) reachable from the internet via the VPS (DNAT into the tunnel).
  • Dual-stack IPv4 + IPv6 end-to-end.
  • Encryption: Noise IK + ChaCha20-Poly1305 (forward secrecy, rekey, anti-replay) — wireguard-go crypto+TUN as a library, with a custom datagram bonding scheduler (pin-only multi-flow + optional FEC on lossy links).
  • TCP auto-bonds via kernel-MPTCP dual-PEP (a single flow aggregates all WANs + seamless failover); UDP / ICMP / P2P / inbound stay on the L3 tunnel — with no configuration. Path MTU auto-tunes (PLPMTUD).
  • QoS / bufferbloat: per-WAN CAKE (sized from each WAN) + CAKE on gob0 + BBR — low latency under load with app-priority, and switchable for an external qosmate/SQM. Plus adaptive FEC and capacity auto-rate.

Status

Working, verified on real hardware over the internet (OpenWrt router + Debian VPS, real WANs): encrypted tunnel, multipath bonding, ~ms WAN-down failover, inbound hosting, dual-stack IPv6 (NAT66 + auto VRRP-gateway fix, client→v6-internet HW-verified), per-WAN CAKE QoS + BBR (low bufferbloat). Single binary, self-programming VPS edge, OpenWrt package (netifd proto + procd + UCI + LuCI). Performance tuning on a small VPS is ongoing — measure real throughput, don't treat metrics as final.

Install

You need a VPS (Debian/Ubuntu, public IPv4; IPv6 is optional and works either way — see IPv6) and an OpenWrt router. Both sides are a single command.

1) VPS — one command, as root

Downloads the prebuilt binary (or builds from source as a fallback), installs a hardened systemd service (CAP_NET_ADMIN/NET_RAW only, NoNewPrivileges, ProtectSystem=strict), generates the keypair, and prints the values to paste into the router:

curl -fsSL https://git.xn--la-mia8p.eu/ladab/gobond/raw/branch/main/deploy/vps-edge/bootstrap.sh | sh

Re-running is safe (it keeps the keypair; ROTATE_KEYS=1 regenerates it, which means you must re-pair the router). VPS-internal ports live in the reserved 6500065535 range (underlay :65535, admin SSH :65022), so every port below 65000 is free to forward to a LAN host. The installer also frees port 22 by moving SSH to :65022 (opt out with KEEP_SSH_22=1) and sets a minimal host firewall.

The optional legacy TCP PEP (tcp_pep, off by default — superseded by the auto-on MPTCP dual-PEP) also listens in the reserved range (:65333), so it never occupies a forwardable port. Like the underlay and the MPTCP PEP it binds all interfaces; the minimal host firewall the installer sets covers it.

2) Router (OpenWrt) — install, then configure in LuCI

Fetch the installer and run it with no arguments — it installs both packages (gobond + luci-app-gobond, from the feed or the release) and stops:

wget https://git.xn--la-mia8p.eu/ladab/gobond/raw/branch/main/deploy/router/openwrt-install.sh
sh openwrt-install.sh

Then open LuCI → Network → gobond → Settings and fill in: the VPS server, the router private key + VPS public key the VPS installer printed, and your WANs (each with optional Down/Up, or a Measure button). Save & Apply — the tunnel comes up and reconfigures itself. The firewall zone, lan → tunnel forwarding and default route are created automatically by the package (uci-defaults + an ifup hotplug).

Prefer the command line? Run it with the values inline and it configures the interface for you too:

SERVER=<vps_ip> PEER_PUBLIC_KEY=<VPS public key> PRIVATE_KEY=<Router private key> \
  WANS="wan:150 wwan0:30" sh openwrt-install.sh

WANS = space-separated <openwrt_iface>:<down_mbit>[:<up_mbit>] (seeds the scheduler weights).

That's it — TCP auto-bonds via MPTCP, UDP/ICMP/P2P stay on L3, the MTU auto-tunes, and WAN-down failover is ~ms. To force plain L3 (no MPTCP PEP): set Scheduler-adjacent option mptcp_pep_disable (or option mptcp_pep_disable '1').

Updating

Ship a new version by tagging — CI builds and publishes the release:

git tag v0.3.0 && git push origin v0.3.0     # builds the binaries + .apk (version 0.3.0) and publishes a release

Then one command per machine (keys and config are preserved):

  • VPS — re-run the same one-liner (downloads the new binary, atomically swaps it, restarts the service):
    curl -fsSL https://git.xn--la-mia8p.eu/ladab/gobond/raw/branch/main/deploy/vps-edge/bootstrap.sh | sh
    
  • Router — the gobond binary lives inside the .apk, so a package upgrade is the binary upgrade, and the package re-ups the interface by itself. Either LuCI → System → Software → Updates (the new version shows because the .apk carries the tag version) → upgrade gobond; or, over SSH:
    sh openwrt-install.sh        # no variables = UPDATE mode: apk upgrade gobond + reactivate, keys untouched
    

Usage

# router: tunnel status (established, paths, weights, RTT, loss)
gobond -config /var/run/gobond-wanbond.json -status

# measure real speed (through OpenWrt), per-WAN or the bonded aggregate
gobond-speedtest wan            # one link only (source-bound)
gobond-speedtest                # bonded tunnel (aggregate)
gobond-speedtest --set wan      # measure + write the real rate into the config (seeds the scheduler weights)

# "my speed test shows less than the WAN sum — is it the bond?" — start this, run your speed test
# from a LAN device while it samples, read the verdict (bond fine / lossy WAN / bond underfilled)
gobond-diag 30

# VPS: edge status
gobond -config /etc/gobond/vps.json -status
systemctl status gobond-vps

Port forwards are managed from OpenWrt (firewall redirects) and propagate to the VPS automatically. Per-WAN speeds are either seeded manually or detected by auto-rate.

QoS / SQM (bufferbloat)

gobond shapes in two places, because traffic takes two paths: TCP auto-bonds over kernel-MPTCP subflows that ride the raw WAN interfaces (not the tunnel), while UDP / ICMP / P2P ride the decrypted L3 tunnel gob0. Both layers are on by default and are independently switchable in LuCI → Network → gobond → Settings.

  • Smart Queue (per-WAN CAKE) — the main bufferbloat fix. Sized from each WAN's Down/Up, it attaches CAKE to every physical WAN: ingress (download) via an IFB + egress (upload) with ack-filter, diffserv4, per-host fairness and the correct PPPoE/cable overhead. This is where bonded TCP's bufferbloat actually lives, so it is what holds latency down under load and lets a bulk download yield to streaming / games / VoIP. HW-measured: loaded latency 62/304 ms → 29/36 ms (down/up). Toggle: Smart Queue (QoS) (needs per-WAN Down/Up set); switch it off to run your own SQM/qosmate on the WAN devices instead — it tears down immediately on Save & Apply (no reconnect needed).
  • Queue management (gob0) — CAKE on the decrypted tunnel, which carries the UDP/ICMP/P2P that does not ride the MPTCP subflows. Toggle: set it to off to hand gob0 to an external qosmate / SQM — point it at the gob0 interface, bandwidth = the bonded aggregate (a little under the real total, which is variable as WANs come and go, so be conservative). off leaves gob0 on the default qdisc so two qdiscs don't collide.

Both ends also run BBR + fq (the VPS is the sender for your download), pacing to the bottleneck instead of filling the buffer; the per-WAN CAKE owns the actual rate, BBR just keeps the sender from over-driving the asymmetric link.

IPv6

Dual-stack is automatic — the tunnel carries IPv6 natively and the VPS gives your LAN clients IPv6 with no configuration, on either kind of provider:

  • Routed prefix — routed straight down the tunnel to the LAN (no NAT).
  • Single on-link /64 (most cheap VPSes, e.g. ZONER) — NAT66 out the VPS's own global IPv6, exactly like the IPv4 egress (one public exit). gobond also auto-handles the common provider quirk where the IPv6 gateway is a VRRP virtual router that ignores Neighbor Solicitation: the VPS edge pins the gateway's VRRP MAC as a static neighbour (derived from the working v4 VRRP gateway) and re-pins it if the uplink flaps — so IPv6 works even on a box where a bare ping6 fails. No-op on a normal network where the gateway answers NDP.

Outbound (clients → IPv6 internet) is done and HW-verified. Inbound IPv6 hosting (port-forward DNAT to a backend) is implemented end to end — the VPS edge installs a v6 DNAT + NAT66 branch and the router propagates the gob0 IPv6 backend with each forward — but is not yet HW-verified (the v4 inbound path is).

Developing

Building from source, the test/lab harness, releasing, and the OpenWrt package feed are covered in DEVELOPMENT.md. The architecture, the locked decisions (D1D17), the phase roadmap, and the synthesis-vs-verified ledger live in docs/.