- Rust 52.1%
- Nix 47.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| nix | ||
| src | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| default.nix | ||
| flake.lock | ||
| flake.nix | ||
| LICENSE | ||
| README.md | ||
| rust-toolchain.toml | ||
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 # ...