Injectable IP_FREEBIND functionality for non-cooperating programs.
  • Rust 52.1%
  • Nix 47.9%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-02 23:13:56 +03:00
nix enable/disable logging in the nix package 2026-04-27 10:12:41 +03:00
src enable/disable logging in the nix package 2026-04-27 10:12:41 +03:00
.gitignore initial commit 2026-04-27 02:06:16 +03:00
Cargo.lock chore: bump dependencies 2026-09-02 23:13:56 +03:00
Cargo.toml initial commit 2026-04-27 02:06:16 +03:00
default.nix initial commit 2026-04-27 02:06:16 +03:00
flake.lock chore: update flake 2026-09-02 23:13:50 +03:00
flake.nix add overlay 2026-04-27 02:28:03 +03:00
LICENSE initial commit 2026-04-27 02:06:16 +03:00
README.md initial commit 2026-04-27 02:06:16 +03:00
rust-toolchain.toml initial commit 2026-04-27 02:06:16 +03:00

libfreebind

An injectable shared object that inserts the IP_FREEBIND option before calls to bind(2). This is needed for programs which do not natively support this option.

Motivation

The original use case for this utility is nginx with Tailscale. At the time of writing, 27/04/2026, nginx has no support for IP_FREEBIND. This is especially annoying because sometimes the network is flaky and Tailscale does not reliably set the IP address of its interface. nginx then fails to bind to Tailscale's IP and exits indicating a failure. systemd then tries to restart nginx and it likely fails again because Tailscale cannot establish a connection. This continues on for some time and then systemd gives up on trying to restart nginx and I have to SSH in and restart it by hand. This is not a limitation or bad design from any of the software mentioned above, it is solely the ISP who causes this. This utility, once injected into nginx, will allow it to bind(2) to Tailscale's IP even if Tailscale hasn't set an IP to its interface.

Building

$ cargo build
$ file target/debug/libfreebind.so

or

$ nix build .
$ file result/lib/libfreebind.so

How to Use

The shared object libfreebind.so is supposed to be LD_PRELOADed inside the target executable. Once preloaded, it will hijack bind(2) and set the IP_FREEBIND flag if it deems necessary. libfreebind uses the environment variable $LIBFREEBIND_IPS to determine which IPs need the IP_FREEBIND flag. $LIBFREEBIND_IPS must be a comma-separated list of IPv4 or IPv6 addresses.

$ env \
    LD_PRELOAD="$PWD/libfreebind.so" \
    LIBFREEBIND_IPS="10.0.0.42,192.168.1.2,::1" \
    nginx # ...