netbird-embed 0.1.0

Rust bindings for NetBird's client/embed via Go C-shared FFI
docs.rs failed to build netbird-embed-0.1.0
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:

[dependencies]
netbird-embed = "0.1"
use netbird_embed::{Client, ClientOptions};

let client = Client::new(ClientOptions {
    setup_key: Some("YOUR-SETUP-KEY".into()),
    management_url: Some("https://api.netbird.io".into()),
    device_name: Some("my-app".into()),
    token: None,
})?;

client.start()?;

let status = client.status()?;
println!("Overlay IP: {}", status.ip);

for peer in client.peers()? {
    if peer.is_connected() {
        println!("{} ({})", peer.fqdn, peer.ip);
    }
}

// Dial a peer over the mesh — returns a UnixStream (socketpair)
let stream = client.dial("tcp", "10.200.0.1:8080")?;

// Listen on the mesh — returns a Listener that yields UnixStreams
let listener = client.listen(":8080")?;
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 i32 handle. No Go pointers cross FFI.
  • Caller-provided buffers — Status/peers returned as JSON into Rust-allocated buffers. Returns ERANGE if too small; caller retries with larger buffer (handled automatically).
  • Socketpair for connectionsdial() creates a Unix socketpair. Go pumps data between the mesh connection and one end; Rust gets the other as a UnixStream.
  • No callbacks — Status is polled. Avoids cross-runtime threading complexity.

Building

# Build (Go C-shared library is compiled automatically by build.rs)
cargo build

# Run the example
NB_SETUP_KEY=your-key NB_MANAGEMENT_URL=https://api.netbird.io cargo run --example connect

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 cargo build --target x86_64-pc-windows-gnu

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)