Skip to content

Latest commit

Β 

History

127 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

b2p

Encrypted file transfer between two machines, built for restricted networks.

CI Latest release Container image Rust 2021

b2p moves files between two machines through a small relay that both sides reach with an ordinary outbound HTTPS/WebSocket connection on port 443 β€” the same kind of connection a browser makes, and on many networks the only kind allowed out. That is the design center: corporate networks, guest Wi-Fi, CGNAT'd home lines, mobile hotspots β€” places where hole-punching, UDP, and high TCP ports are dead on arrival, but the web works. TLS-inspecting proxies are supported too (--cafile). The relay is yours: deploy it once, for free, on Cloudflare Workers, or self-host it anywhere.

flowchart LR
    A["πŸ’»  sender"] -- "outbound wss / 443" --> R{{"☁️  relay"}}
    B["πŸ’»  receiver"] -- "outbound wss / 443" --> R
Loading

The relay pairs the two connections and forwards bytes β€” it sees ciphertext only. A SPAKE2 key exchange over that pipe proves both sides know the one-time code, then the file streams end-to-end encrypted with XChaCha20-Poly1305. Interrupted transfers resume from the staged chunks instead of restarting.

πŸ“₯ Install

Linux Β· macOS

curl -fsSL https://raw.githubusercontent.com/campiohe/b2p/main/scripts/install.sh | bash

Windows (PowerShell)

irm https://raw.githubusercontent.com/campiohe/b2p/main/scripts/install.ps1 | iex

Both scripts download the binary for your platform from the latest release, install it (~/.local/bin Β· %LOCALAPPDATA%\Programs\b2p), and tell you what to do about your PATH. Set B2P_INSTALL_DIR to install elsewhere, or B2P_VERSION (e.g. v0.6.0) to pin a version. No runtime dependencies, ~8 MB.

Other ways to install

Prebuilt archives β€” Linux x86_64 (static musl), macOS arm64, Windows x86_64 β€” are attached to every release; unpack and put b2p on your PATH. For anything else (Intel Macs, ARM Linux), build from source:

cargo install --git https://github.com/campiohe/b2p

The relay also ships as a container image: ghcr.io/campiohe/b2p:latest.

πŸš€ Quick start

1. Install b2p on both machines (above).

2. Point it at a relay (deploy your own below):

$ b2p relay set wss://b2p-relay.<account>.workers.dev

3. Transfer. On the sending machine:

$ b2p send path/to/file-or-folder
$ b2p send --text "the wifi password is hunter2"

It prints the code two ways: a short human code like 7-otter-zebra (works when the receiver has the same relay configured) and a long b2p://… form that embeds the relay address, so a freshly-installed receiver needs no configuration at all. On the receiving machine:

$ b2p receive 7-otter-zebra
$ b2p receive 'b2p://b2p-relay.you.workers.dev/…#…'
All flags

receive <code> --out DIR (destination) Β· --yes (no accept prompt) Β· --overwrite Β· --relay URL (override the configured relay, both commands) Β· --cafile FILE (extra root CA, all commands) Β· env B2P_RELAY / B2P_RELAY_TOKEN override the config file Β· b2p relay show prints the configured relay.

☁️ Deploy your relay β€” free, ~5 minutes, once

The relay is a ~100-line Cloudflare Worker in relay-worker/. You need a free Cloudflare account and Node.js:

$ cd relay-worker
$ npx wrangler login          # opens the browser once
$ npx wrangler deploy         # prints https://b2p-relay.<account>.workers.dev

Optionally restrict it to holders of a shared token (recommended once your relay URL circulates β€” short human codes use a small, enumerable room namespace, so the token is what keeps strangers from squatting rooms on your relay; your data is end-to-end encrypted either way):

$ npx wrangler secret put RELAY_TOKEN

The token stays private to your own relay: b2p never sends it to a relay address that came from someone else's b2p:// code. Then, on each machine:

$ b2p relay set wss://b2p-relay.<account>.workers.dev --token <T>

The free tier comfortably covers personal use β€” dozens of multi-GB transfers a day; the relay never stores data.

πŸ“¦ Self-host the relay

The same b2p binary can be the relay β€” any VPS, home server, or container platform works:

$ b2p relay serve                                    # plain ws on 0.0.0.0:9009
$ b2p relay serve --token S3CR3T                     # require a bearer token
$ b2p relay serve --tls-cert c.pem --tls-key k.pem   # built-in TLS

or with Docker:

$ docker run -p 9009:9009 -e RELAY_TOKEN=S3CR3T ghcr.io/campiohe/b2p:latest

For internet use put TLS in front (unless using --tls-cert) β€” port 443 is the whole point. Caddy does it in two lines with automatic Let's Encrypt certificates:

relay.example.com {
    reverse_proxy 127.0.0.1:9009
}

(Kubernetes: terminate TLS at the ingress and point it at port 9009.) Then on each machine: b2p relay set wss://relay.example.com.

The Cloudflare Worker and b2p relay serve implement the same protocol and are interchangeable; relay-worker/test.mjs is the conformance suite for both β€” CI runs it against b2p relay serve on every push.

πŸ” Resume

If the connection drops mid-transfer, the sender keeps waiting and the code stays valid β€” re-run the same receive command and only the missing chunks are sent (the receiver reports what it already staged, matched by content fingerprint).

🩺 Diagnostics

$ b2p doctor            # DNS filtering, TLS inspection, UDP/STUN, relay reachability
$ b2p doctor <host>     # same checks, aimed at a specific host or URL

Every check names the layer and ends with a one-line verdict; the relay check does a real WebSocket connect + ping round-trip. b2p send and b2p receive run the doctor automatically when they cannot establish a connection.

πŸ”’ Security & scope

What the encryption covers. The relay sees ciphertext, sizes, and timing β€” never plaintext or keys. The code (and the SPAKE2 exchange derived from it) never travels through the relay in a usable form.

Wrong-code attempts are one-strike. A parked send offer is cancelled by the first connection that fails the code confirmation β€” your file is never sent to a peer that didn't prove the code, and a guesser gets exactly one try per offer (like wormhole and croc). Anyone who can reach the room can burn an offer this way, which is one more reason to set a relay token.

Current limits β€” and the plan. Metadata: the relay operator can see connecting IPs, timing, and transfer sizes. Reachability under filtering: today b2p makes no attempt to hide its traffic, so a network that filters your relay's hostname at the DNS or SNI layer stops transfers (b2p doctor names which layer, and a custom domain in front of the Worker sidesteps category blocks like *.workers.dev). Both areas have designed roadmap items β€” proxy/Tor support, DNS-over-HTTPS resolution, Encrypted Client Hello β€” in todo.md.

Practical notes.

  • b2p trusts the operating system's certificate store (plus SSL_CERT_FILE / SSL_CERT_DIR / --cafile); networks with TLS inspection work as long as the proxy's root CA is installed.
  • Folder transfers briefly need ~2Γ— the transfer size free on both sides (tar spool on the sender, staging area on the receiver).
  • Proxies that require explicit HTTP CONNECT configuration are not supported yet.

πŸ§‘β€πŸ’» Development

$ cargo test            # full offline suite β€” transfers run against the real
                        # `relay serve` implementation on an ephemeral port
$ B2P_TEST_RELAY_URL=wss://… cargo test --test relay_live   # live smoke

CI (ci.yml) runs cargo fmt --check, cargo clippy -- -D warnings, cargo test, and the relay conformance suite on every push and pull request to main.

Cutting a release
  1. Bump version in Cargo.toml and commit.

  2. Tag and push:

    $ git tag v0.5.0
    $ git push origin v0.5.0

The release workflow (release.yml) cross-compiles Linux x86_64 (musl), macOS arm64, and Windows x86_64 binaries, publishes them to a GitHub Release named after the tag, and pushes the Docker image to ghcr.io/campiohe/b2p. Tags containing a hyphen (v0.5.0-rc.1) publish as pre-releases and don't move the :latest image tag.

About

Securely send files between two machines, even on restricted networks πŸ”’ πŸ“¦

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages