Skip to content

YAAMBerlin/vereinigen

Repository files navigation

vereinigen

Declarative UniFi network controller in Rust — TOML config, git-synced, SurrealDB state, OpenTelemetry observability.

CI codecov

Architecture

Crate Purpose
vereinigen-protocol AES-CBC/GCM crypto, packet parsing, inform headers
vereinigen-config TOML config loading + validation
vereinigen-generator USG/USW/UAP system_cfg + mgmt_cfg generators
vereinigen (controller) axum HTTP server, 3-phase inform, auto-adopt, discovery, provision, OTel, IPC, sync, firmware
vereinigen-db SurrealDB embedded device state
vereinigen-ipc Unix socket transport for CLI
vereinigen-sync gix-based git config sync with diff detection
vereinigen-cli CLI management tool
vereinigen-mock-device Test device simulator
vereinigen-unf .unf backup decryptor + TOML converter

Quick Start

# Development shell
nix develop

# Build
cargo build

# Run tests
cargo test

# Run controller
cargo run --bin vereinigen -- \
  --config-dir /etc/vereinigen/config \
  --db-dir /var/lib/vereinigen/db \
  --listen 0.0.0.0:8080

# CLI
cargo run --bin vereinigen-cli -- --socket /run/vereinigen.sock list

Zero-Touch Auto-Adopt

The controller automatically discovers and adopts UniFi devices on the local subnet:

  1. SSH subnet scan — Every 60 seconds, the controller does a parallel TCP connect sweep to port 22 on all 254 hosts in the /24 subnet (~500ms). For each responsive host, it tries SSH with ubnt/ubnt credentials and runs syswrapper.sh set-inform to point the device at the controller.

  2. UDP discovery — Broadcasts and unicasts discovery responses on UDP 10001 every 30 seconds, telling listening devices where the controller is.

  3. Auto-adopt — When an unknown device sends its first inform, the controller auto-creates a device config (model, serial, firmware), generates a unique authkey, and sends an adoption setparam with mgmt_cfg containing the new key.

  4. Provisioning — On subsequent informs, if the device's cfgversion doesn't match the expected hash, the controller sends a full system_cfg + mgmt_cfg setparam. The device applies the config and comes online.

No manual intervention needed — plug in a device and it gets adopted within 60 seconds.

Config Directory Structure

config/
├── settings.toml       # Country, timezone, NTP, SSH, LED
├── site.toml           # Site name and description
├── wireless.toml       # SSID definitions (name, security, passphrase)
├── networks.toml       # Network subnets, VLANs, DHCP
├── firewall.toml       # Firewall groups and rules
├── approved-macs.toml  # Pre-approved device MAC addresses
└── devices/            # Auto-created device configs (one .toml per MAC)
    └── d8-b3-70-cc-89-0a.toml

wireless.toml

[[ssid]]
name = "MyNetwork"
security = "wpa2"
passphrase = "secretpassword"
hide_ssid = false

approved-macs.toml

Pre-approve devices so they're adopted immediately on first inform:

macs = [
    "fc:ec:da:43:19:cd",
]

Unknown devices (not in approved-macs or devices/) are also auto-adopted when they send an inform after being SSH-provisioned.

Device Config (auto-generated)

When a device is auto-adopted, a TOML file is created in devices/:

[device]
name = "UAP-AC-Mesh"
model = "U7MSH"
type = "uap"
mac = "d8:b3:70:cc:89:0a"
authkey = "<generated-hex-key>"
aes_gcm = true

[device.network]

Inform Protocol

The controller implements the UniFi inform protocol with three phases:

Phase Condition Response
Adoption New device, first contact setparam with mgmt_cfg (new authkey + controller URL)
Provisioning Known device, cfgversion mismatch setparam with full system_cfg + mgmt_cfg
Heartbeat Known device, cfgversion match Minimal noop response

Encryption: AES-CBC or AES-GCM depending on device support. GCM is detected from the inform packet header flags and used for responses automatically.

Config Hot-Reload

The controller watches the config directory for changes. Edit any TOML file and it's picked up within 30 seconds — the cfgversion hash changes, triggering re-provisioning on the next inform cycle. No restart needed.

NixOS Module

{
  inputs.vereinigen.url = "github:YAAMBerlin/vereinigen";

  outputs = { nixpkgs, vereinigen, ... }: {
    nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
      modules = [
        vereinigen.nixosModules.vereinigen
        {
          services.vereinigen = {
            enable = true;
            configDir = "/etc/vereinigen/config";
            configRepo = "https://github.com/org/network-config.git";
          };
        }
      ];
    };
  };
}

Import from UniFi Backup

cargo run --bin vereinigen-unf -- --input backup.unf --output ./config

License

Proprietary — YAAMBerlin

About

Declarative UniFi network controller in Rust — TOML config, git-synced, SurrealDB state, OpenTelemetry observability

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors