Skip to content

dmitriimaksimovdevelop/macos-netbird-reconnect

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

netbird-reconnectd (macOS)

A tiny macOS daemon that listens for system wake events and forces a clean NetBird VPN reconnect.

wake → netbird down → short delay → netbird up --enable-lazy-connection → status
  • Uses IOKit power notifications (sleep/wake callback).
  • Spawns NetBird commands with posix_spawnp (no shell; resolves via $PATH).
  • Logs to stderr; when run via Homebrew services, logs are written to Homebrew's log files.

How it works

  • Registers a power notification callback with IORegisterForSystemPower.

  • On wake (kIOMessageSystemHasPoweredOn), runs:

    1. netbird down
    2. wait a few seconds (default: SLEEP_BEFORE_UP_SEC = 5)
    3. netbird up --enable-lazy-connection with NB_ENABLE_EXPERIMENTAL_LAZY_CONN=true (set internally)
    4. netbird status
  • posix_spawnp("netbird", ...) looks up netbird in $PATH.

  • On startup, the daemon sets a sane default PATH for launchd contexts if needed: /opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin.


Requirements

  • macOS 11+ (Intel or Apple Silicon)
  • NetBird CLI installed (e.g., brew install netbird)
  • Xcode Command Line Tools or a recent clang/cmake

Install via Homebrew (recommended)

brew tap dmitriimaksimovdevelop/tap
brew install dmitriimaksimovdevelop/tap/macos-netbird-reconnect
brew services start macos-netbird-reconnect

Status & Logs

brew services list | grep -i netbird
# Logs (captured from stderr):
tail -f "$(brew --prefix)/var/log/netbird-reconnectd.log"

Stop / Uninstall

brew services stop macos-netbird-reconnect
brew uninstall macos-netbird-reconnect

The Homebrew service definition includes a proper PATH so posix_spawnp can find netbird without hardcoded paths.


Build from source

Option A — clang one-liner

clang -O2 -Wall -Wextra netbird-reconnectd.c -o netbird-reconnectd \
  -framework IOKit -framework CoreFoundation

Option B — CMake (e.g., CLion)

cmake -S . -B build
cmake --build build --config Release
# Result: build/netbird-reconnectd

Configuration

Edit in netbird-reconnectd.c if desired:

  • SLEEP_BEFORE_UP_SEC: seconds to wait after wake before up (default 5).

You do not need to set the NetBird path. The daemon uses posix_spawnp("netbird", ...) and relies on $PATH.


Running manually (without Homebrew)

./netbird-reconnectd
  • Logs are written to stderr; you'll see them in your terminal.
  • Stop with Ctrl+C.

Optional: install as a LaunchAgent (manual)

Save as ~/Library/LaunchAgents/com.netbird.reconnectd.plist (adjust the absolute path to your binary):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>com.netbird.reconnectd</string>

    <key>ProgramArguments</key>
    <array>
      <string>/Users/USERNAME/bin/netbird-reconnectd</string>
    </array>

    <key>EnvironmentVariables</key>
    <dict>
      <key>PATH</key>
      <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
    </dict>

    <key>RunAtLoad</key>
    <true/>

    <key>KeepAlive</key>
    <false/>

    <!-- Optional: route launchd's own stdout/stderr (daemon already logs to stderr) -->
    <key>StandardOutPath</key>
    <string>/tmp/netbird-reconnectd.launchd.out.log</string>
    <key>StandardErrorPath</key>
    <string>/tmp/netbird-reconnectd.launchd.err.log</string>

    <key>ProcessType</key>
    <string>Background</string>
  </dict>
</plist>

Load / reload:

launchctl bootout gui/$(id -u)/com.netbird.reconnectd 2>/dev/null || true
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.netbird.reconnectd.plist

Check status and live logs:

launchctl print gui/$(id -u)/com.netbird.reconnectd | head -n 80
log stream --predicate 'process == "netbird-reconnectd"' --style syslog --info

Troubleshooting

  • posix_spawn failed: rc=2 (No such file or directory) for netbird

    • NetBird CLI not installed or not on the service $PATH.
    • Fix: brew install netbird. With Homebrew services, PATH is set automatically; for manual LaunchAgents, add EnvironmentVariables.PATH in the plist as shown above.
  • Service not started / disappears

    • Check: brew services list | grep -i netbird
    • Foreground run for debugging: brew services run macos-netbird-reconnect
  • Bootstrap failed: 5: Input/output error (manual plist)

    • Usually an invalid plist or wrong ProgramArguments path. Validate: plutil -lint ~/Library/LaunchAgents/com.netbird.reconnectd.plist.
  • Exec format error on Apple Silicon

    • Ensure you built an ARM64 binary (Apple clang does this by default on Apple Silicon). Avoid running Intel-only binaries without Rosetta.

Security notes

  • No shell is invoked; arguments/env are passed directly to posix_spawnp.
  • Consider code signing if you distribute the binary.

License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors