docs.rs failed to build netbird-embed-0.1.1
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
netbird-embed-rs
Rust bindings for NetBird's client/embed package via Go C-shared FFI.
Embeds a full NetBird node (WireGuard mesh networking) into any Rust application — no separate VPN client needed.
Requirements
- Rust ≥ 1.75
- Go ≥ 1.25 (builds the C-shared library automatically via
build.rs) - Linux (Unix socketpair for
dial/listen; status/peers work on all platforms)
Usage
Add to your Cargo.toml:
[]
= "0.1"
use ;
let client = new?;
client.start?;
let status = client.status?;
println!;
for peer in client.peers?
// Dial a peer over the mesh — returns a UnixStream (socketpair)
let stream = client.dial?;
// Listen on the mesh — returns a Listener that yields UnixStreams
let listener = client.listen?;
let conn = listener.accept?;
The client is automatically stopped and freed on drop.
API
| Method | Description |
|---|---|
Client::new(opts) |
Create a NetBird node |
client.start() |
Join the mesh network |
client.stop() |
Leave the mesh network |
client.status() |
Local peer info, management/signal state, peer list |
client.peers() |
List of known peers with connection status |
client.dial(net, addr) |
Dial a peer, returns UnixStream (Unix only) |
client.listen(addr) |
Listen on mesh address, returns Listener (Unix only) |
listener.accept() |
Accept next connection, returns UnixStream |
Architecture
┌─────────────────────────────┐
│ Your Rust application │
│ ┌───────────────────────┐ │
│ │ netbird-embed (safe) │ │
│ │ Client, Status, Peer │ │
│ └──────────┬────────────┘ │
│ ┌──────────▼────────────┐ │
│ │ FFI layer │ │
│ │ extern "C" bindings │ │
│ └──────────┬────────────┘ │
└─────────────┼───────────────┘
│ integer handles + caller buffers
┌─────────────▼───────────────┐
│ libnetbird_embed.so (Go) │
│ C-exported wrappers │
│ └─► netbird/client/embed │
│ └─► wireguard-go │
└─────────────────────────────┘
Key design decisions:
- Integer handles — Go GC manages real objects. Rust holds an
i32handle. No Go pointers cross FFI. - Caller-provided buffers — Status/peers returned as JSON into Rust-allocated buffers. Returns
ERANGEif too small; caller retries with larger buffer (handled automatically). - Socketpair for connections —
dial()creates a Unix socketpair. Go pumps data between the mesh connection and one end; Rust gets the other as aUnixStream. - No callbacks — Status is polled. Avoids cross-runtime threading complexity.
Building
# Build (Go C-shared library is compiled automatically by build.rs)
# Run the example
NB_SETUP_KEY=your-key NB_MANAGEMENT_URL=https://api.netbird.io
Cross-compilation
build.rs detects the Rust target and sets GOOS/GOARCH accordingly. For Windows cross-compilation, set CC to a MinGW-w64 compiler:
CC=x86_64-w64-mingw32-gcc
Gotchas
| Issue | Detail |
|---|---|
| One Go runtime per process | Two Go .so files in the same process causes GC corruption. This must be the only Go library loaded. |
| Library size | The .so is ~50MB (Go runtime + NetBird + WireGuard). Strip with go build -ldflags="-s -w" to reduce. |
| CGo call overhead | ~60-100ns per FFI call. Negligible for control plane (start/stop/status). |
| Drop blocks | Client::drop calls Go Stop() which may block while tearing down the tunnel. Call client.stop() explicitly if you need non-blocking cleanup. |
License
BSD-3-Clause (matching NetBird's client license)